Skip to content

玩家上传图片 ​

玩家图片使用 api.media,相关的小型 JSON 使用 api.sessionStorage。两者属于当前会话,同一账户可在另一台设备读取。创作者随卡提供的图片仍然放在面板 → 资源里,通过 @asset: 引用来使用。

玩家界面的模板里没有上传用的部件,所以这个食谱要写界面代码(面板 → 前端代码)。

选择存储位置 ​

数据API
玩家图片字节和图库元数据api.media
当前选中的图片 ID、有限长度笔记或其他存档 JSONapi.sessionStorage
浏览器偏好、可丢弃缓存api.storage
规则或 AI 需要使用的游戏状态已声明的游戏变量

不要把图片 base64 放进 JSON、游戏变量或浏览器存储。云端保存需要网络连接。会话图片独立于世界导出包,不应承诺导出世界会下载玩家的私人文件。

上传并显示 ​

在组件中取得 const api = useYumina()。打开图库、修改后,以及临时显示链接的五分钟有效期到期前,重新读取列表:

tsx
const page = await api.media.list(0);
// page.items 含 { id, entryId, metadata, version, url, thumbnailUrl, deleted, ... }。
// page.hasMore 为 true 时继续加载后续页。

if (!api.readOnly && page.uploadsEnabled) {
  const result = await api.media.pick({
    metadata: { title: "角色头像" }
  });
  if (result) {
    // result 为 { mediaId, entryId };取消时为 null。
    // 重新读取列表,取得临时显示链接。
  }
}

用未删除条目的 url 或 thumbnailUrl 显示图片。文件被彻底删除后,条目 URL 可能为空。捕获请求失败并保留错误状态,只有 promise 成功后才显示保存成功。上传控件应遵守 api.readOnly 和 uploadsEnabled。

已有文件选择器时,可调用 api.media.upload(file, { entryId, uploadId, metadata })。失败后保留选中的 File;重试同一文件/请求时复用 uploadId。不要退回本地存储却声称已经云端保存。

保存选中的图片 ​

JSON 只记录稳定的条目 ID,再通过 media.list() 找到显示链接,不持久保存 url 或 thumbnailUrl:

tsx
const previous = await api.sessionStorage.get("selected-portrait");
const saved = await api.sessionStorage.set(
  "selected-portrait",
  { entryId: selectedItem.entryId, mediaId: selectedItem.id },
  { expectedVersion: previous.version }
);
// 保留 saved.version,供后续修改使用。

JSON 方法均返回 { value, version, exists },读取时检查 exists。每次 set 和 remove 都必须提供 { expectedVersion }。另一台设备已经修改记录时,写入返回 SESSION_STORAGE_CONFLICT;保留草稿,重新读取并协调修改后再提交,不能盲目重试旧选择。

仅清空选择时,使用最新版本调用 api.sessionStorage.remove("selected-portrait", { expectedVersion })。从当前会话移除图片时,调用 api.media.remove(item.entryId, item.version)。这是两个独立操作;清空选择不会删除图片。文件的彻底删除在我的库 → 资源 → 存档图片管理,可能影响其他存档、存档点和分享。

限制与快照 ​

  • 图片支持静态 JPEG/PNG/WebP,输入最多 16 MiB、4,000 万解码像素。服务端生成最长边 2048 像素的 WebP 显示图及缩略图,并非原文件备份。图片计入账户现有素材容量。
  • JSON:每个序列化 UTF-8 值 32 KiB;每会话当前值合计 256 KiB、128 个键(含删除标记)、值历史 16 MiB;同一所有者全部会话每小时最多 1,000 次修改。
  • 改变 JSON 的存档点恢复也受上述限制;容量超限返回 HTTP 413,每小时次数超限返回 429,包括图片与剧情状态在内的整个恢复回滚。旧历史不会删除。值未变化的恢复不复制历史,即使达到这些 JSON 上限也仍可进行。
  • 存档点、同账户分支与分享快照一起保存 JSON 和媒体引用;恢复存档点时一起恢复。分享仅包含创建时的快照,不会收到之后新增的私人内容。
  • 分享回放只读,沿用现有可见性、世界发布状态、隐藏/审核状态与内容级别规则。分享者和卡片作者是快照的特权读取者,包括已隐藏、世界已下架或敏感内容的快照;其他查看者须通过适用检查。不公开列出的分享可通过链接访问。这不授予作者访问私人原始会话当前数据的权限,该数据仍仅所有者可访问。

已有浏览器图库 ​

兼容适配器在所有世界识别已验证的 Oncin v2/v3/v4 与 gallery_data 当前有效格式。迁移必须在保存原始图片的浏览器进行,并保留旧本地数据。不会猜测损坏或不明确的 journal/backup,不会读取另一台设备的浏览器数据,不抓取远程 URL,也不自动转换任意 localStorage 键。

新卡片应使用上述明确的 SDK API。其他旧格式需自行适配;确认上传和云端保存都成功前,保留本机原始数据。

验证接入 ​

  1. 上传一张小型受支持图片,等待成功后刷新会话。
  2. 用同一账户在另一台设备打开该会话,确认图片和选择可读取。
  3. 保存存档点后更换选择,再恢复存档点,确认图片引用与 JSON 一起恢复。
  4. 创建同账户分支与分享快照,确认捕获状态和回放只读行为。
  5. 验证取消选择、上传失败、容量不足和另一设备修改导致的 JSON 冲突,保留草稿并显示失败。

方法签名见 API 参考。向 AI 发送图片使用独立的聊天附件能力;仅在界面显示图片不会把像素传给模型。