跳至正文

保存后处理 ​

保存后处理由后台执行。下面检查图片宽度,超过阈值就返回屏蔽意见,由 Picloom 更新状态;上传完成不代表审核完成,也不能保证图片在审核前未被访问。

最小实现 ​

按快速开始创建项目,将 plugin.json.kind 设为 processor,保留自己的 ID 和版本。将 src/index.ts 替换为以下外层代码,再用下一段实现替换注释行:

ts
import { PluginError, type Definition } from "@picloom/plugin-sdk";
import manifest from "../plugin.json";

const { kind, apiVersion } = manifest;
if (kind !== "processor" || apiVersion !== 1)
  throw new Error("Expected processor plugin API 1");

export default {
  id: manifest.id,
  version: manifest.version,
  kind,
  apiVersion,
  // 将下一段实现放在这里
} satisfies Definition<"processor">;
ts
defaultLocale: "en-US",
nameKey: "package.name",
messages: {
  "en-US": {
    "package.name": "Example width review",
    "settings.maxWidth.label": "Maximum width",
  },
  "zh-CN": {
    "package.name": "宽度审核示例",
    "settings.maxWidth.label": "最大宽度",
  },
},

stages: {
  post_save: {
    configSchemaVersion: 1,
    configSchema: {
      type: "object",
      properties: {
        maxWidth: {
          "x-ui": { labelKey: "settings.maxWidth.label" },
          type: "integer",
          minimum: 1,
          default: 1280,
        },
      },
      required: ["maxWidth"],
      additionalProperties: false,
    },
    async createInstance({ config }) {
      const maxWidth = Number(config.maxWidth);
      return {
        async execute({ file }, { signal }) {
          signal.throwIfAborted();
          const width = file.metadata.width;
          if (width === null)
            throw new PluginError("UNSUPPORTED", "Image width is required");
          return {
            disposition: { value: width > maxWidth ? "block" : "pass" },
            details: { width, maxWidth },
          };
        },
      };
    },
  },
},

execute 读取元数据,通过 disposition.value 返回 pass 或 block,并用 details 记录宽度和阈值。

安装与验证 ​

在独立项目中运行 bun run build,使用生成的 dist/<插件ID>-<版本>.zip。 后台选择示例字典中的名称(随界面语言显示),或你自己修改后的名称:

  1. 安装生成的 ZIP,创建保存后流水线,添加 Example width review,将 maxWidth 设为 1280。
  2. 关联到上传配置。测试时不要启用上传缩放,否则审核的是缩放后的图片。
  3. 分别上传宽度小于和大于 1280 的图片,等待后台操作完成。
  4. 在图片详情查看结果:前者可访问,后者被屏蔽,详情记录实际宽度和阈值。

接口行为 ​

配置与实例声明见插件基础,文件和上下文见宿主服务。

此阶段仅提供 execute,没有请求参数、check/process 或替换图片的输出接口。

execute:执行保存后操作 ​

后台任务按步骤调用;同一次操作可能因重试再次调用。

ts
execute(input: {
  readonly operationId: string;
  readonly record: FileContext;
  readonly publicPath: string;
  readonly url: string;
  readonly file: FileInput;
  readonly currentDisposition: PostSaveDisposition;
  readonly previousResults: readonly Readonly<PostSaveStepResult>[];
}, context: PostSaveContext): Promise<PostSaveResult>;

PostSaveResult 的字段均可省略,通知插件可以只返回 { details: { sent: true } }:

字段类型核心行为
disposition{ value: "pass" | "block" | "delete", mode?: "escalate" | "replace" }提出处置;省略表示不参与
organizationOrganizationUpdate修改本次图片的标签或集合
detailsConfig保存简要 JSON 对象并传给后续步骤,不放凭证或图片字节

record 包含文件 ID、时间、来源、归属及当前有效归类;context.organization 提供当前归属范围内的查找和创建服务,见文件上下文与归类。归类修改省略字段表示保留该项,空数组清空,非空数组设置完整目标 ID,每项最多 100 个。

operationId 可用于远端幂等处理;publicPath 含公开前缀、不含域名,url 在未配置域名时可能是相对路径。currentDisposition 是本次尝试的累计决策,初始为 pass,并非数据库文件状态。

previousResults 按执行顺序包含本次尝试已完成步骤的隔离快照。每项复用规范化后的结果,加上 stepId、pluginId、pluginVersion 和 Unix 毫秒时间 completedAt。有处置时记录明确的 mode。结果表示步骤当时接受的修改,文件详情中的关系才是当前归类。

可选能力与约束 ​

如何形成累计处置 ​

省略 mode 或使用 escalate 时,按 pass < block < delete 累积;replace 明确覆盖此前累计决策,后续步骤仍可再次改变:

步骤返回值累计处置
审核{ disposition: { value: "block" } }block
复核{ disposition: { value: "pass", mode: "replace" } }pass
通知{ details: { sent: true } }pass

block/delete 不终止后续步骤,后续步骤通过 currentDisposition 决定是否通知,通过 previousResults 读取前序识别摘要。delete 随后由后台清理副本,不表示远端图片已删除。

归类与失败提交 ​

每一步完整结果有效后才同时接受归类、处置和摘要。同一步返回屏蔽意见和非法分类时,整个步骤失败,屏蔽意见也不参与累计。需要审核独立生效时,将审核与归类配置为两个步骤,让归类步骤读取前序 details。

本次执行成功或失败时,核心统一提交此前已接受的归类、处置、结果及任务状态。只写插件明确修改的归类字段;未改集合不会覆盖人工编辑的集合。人工与插件对同一字段的修改按提交顺序生效。已接受结果中的分类在提交前被删除时排除相应 ID;文件被其他操作置入删除流程后,不再写新归类或覆盖删除状态。

累计为 block/delete 时,失败任务不自动重试;为 pass 时,可重试错误按次数限制重试整条流水线。只有 ready 文件可重新执行,每次从数据库当前归类及空前序结果开始。屏蔽文件必须先由管理员解除屏蔽,重试不隐式放行;删除失败通过删除任务处理。

一次执行的结果总量上限为 64 KiB,包括步骤标识、处置、归类与摘要。只返回完成后续处理和解释结果所需的内容。

步骤间传值 ​

context.data 用于本次流水线的临时 JSON,previousResults 用于保存后读取已完成步骤的接受结果,currentDisposition 用于读取每步执行前的累计处置。临时数据不跨请求或重试保存;持久运行数据见状态服务。

开发流程见最小实现,调用规则见接口行为。

文档随 main 分支维护;部署与升级请核对产物版本及兼容说明。