去年三月,他把同一批素材跑了两遍。第一次跑到一半,网络不稳卡住了,于是他做了任何人都会做的事:再跑一遍。Adobe 照单全收,没有半句怨言。Vecteezy 没有。

他花了一个周日下午,一条一条删掉60 多条投稿,随后收到一封警告邮件,说明重复提交相同内容违反投稿者条款。就是那一刻,他不再相信自己的记忆,转而写了一份台账。

这套东西不炫技:一个纯文本台账,加上严格的 CSV 表头。它决定了一条流水线是能被信任,还是需要你时刻盯着。

CSV 表头是闸门,不是建议

三家图库平台都会先解析你上传的 CSV,表头错了就是直接拒收——不是警告,是拒收。而且三家的表头彼此差得很远:

  • Adobe 要5 列:标题、关键词、分类、授权、文件引用,五列,顺序固定。
  • Vecteezy 要4 列,字段更少,但你把 Adobe 的格式递过去,第一行就会失败。
  • Dreamstime 要15 列,其中一半可以留空,但所有列都必须存在且位置正确。

他最初的解法是一张表格,按平台手工改。撑了大约两周,一次手滑填错列,就丢掉了一个投稿窗口。后来 make_metadata.py 从同一个文件夹一次性生成三种格式:指向 ./my-assets,选平台,输出该平台要求的精确表头,不多一列。Adobe 拿 5 列,Vecteezy 拿 4 列,Dreamstime 拿 15 列,没有模板漂移,没有手工编辑。

一个需要说明的前提:如果没有标题文件,脚本会把文件名转成标题格式当作标题。首轮凑合可以,但提交前要换成真正的标题和关键词。审核员看得出关键词堆砌和文件名标题,一次拒收就要搭上几天的审核排队时间。

让重复投稿不可能发生的台账

三月那次事故的修法简单到有点难为情。upload_tracker.py 用纯文本记录你已经提交过什么,三条命令:

  • python upload_tracker.py pending items.txt:列出还没做的
  • python upload_tracker.py done "asset-001.jpg":标记完成
  • python upload_tracker.py status:查看状态

每批之前,他先跑 pending,把输出喂给上传器。如果某次跑到一半挂了,台账仍然知道哪些文件已经完成,重跑只碰剩下的部分。没有会损坏的状态,没有要维护的数据库,就是一个能读、能跟其他东西一起备份的文本文件。

这件事的意义不止于省事。重复提交是让投稿账号被标记的最快方式之一。Vecteezy 直接拒掉了他的重复件,Adobe 放行之后又把它们扣在审核里。两种结果都一样:审核员看到的是一个把同一份素材提交了两次的投稿者,而在冲量阶段,这不是你想留下的印象。

脚本只用 Python 标准库,不需要 pip install,没有依赖。如果只用元数据生成器和台账,你需要的只是 Python 3.9 或更新版本。

小机器上,一次只跑一个进程

整套流水线跑在一台1 vCPU、2 GB 内存、没有 GPU的服务器上。这个约束塑造了它的每一个习惯:

  • 单核上绝不要并行铺开图片任务。实践中顺序执行更快,因为你不再让机器来回抖动。
  • 每个素材处理完调用gc.collect(),让内存在条目之间真正释放。
  • resource.getrusage(RUSAGE_SELF).ru_maxrss测峰值内存,而不是平均占用。被 OOM 杀掉的是峰值。
  • 重的渲染步骤一个文件一个子进程,子进程退出时由操作系统回收内存。
  • 预览按 60 dpi 检查,成品按 300 渲染。用全分辨率做检查,是他见过最常见的浪费。

子进程这条规则是踩出来的:一次渲染步骤吃光了机器,内核在 90 个素材中的第 30 个时杀掉了批次。台账让重跑从第 31 个开始,这也是他对它保持忠诚的另一个原因。

让目录保持清醒的文件夹结构

素材过了几百个之后,结构就不再是可选项。这套工具假定的布局是:

  • assets/:原始输出,一个素材一个文件
  • output/:待提交文件加 metadata.csv
  • packs/:成品压缩包加封面
  • research/:笔记、抓取日志、来源
  • scripts/:工具

他要划线强调 research/。早期他为了“清理”删过一次抓取日志,两个月后重建一条产品线时又需要它们。永久保留,它们是下一个产品的原材料。

台账和元数据生成器处在提交层。围绕它们,上层流水线负责打包产品:md2pdf.py 通过 reportlab 把 Markdown 文档转成带样式的 PDF,pack_product.py 压缩产品并用 Pillow 渲染一张 1280x720 封面和一张 600x600 缩略图。总共两个第三方包,且只服务于这两个脚本。整套东西在同一台 2 GB 机器上打包了39 个产品、约856 MB输出,背后是约19000 行流水线代码和300 多页研究支撑着脚本所执行的规则。

这些都不聪明。一个写对的表头,一个记得什么已经发出去的文本文件,一台一次只做一件事的机器。就是这套组合,让他不必再手工复核每一次提交。