去年春天,一位卖家把 Gumroad 后台和存着 40 个成品的文件夹并排打开,然后感到一阵尴尬。产品本身没问题,问题出在目录上——它看起来像四十个陌生人各自做出来的东西。一个封面是深蓝配衬线字体,一个是荧光绿配剪贴画,还有一个干脆就是压缩包的截图。
有买家发邮件来问:这些东西真的都出自同一家店吗?就是那一刻,他不再把包装当成事后补丁,而是把整个目录当成一个产品来做。整套流程跑在一台 1 vCPU、2 GB 内存、没有 GPU 的服务器上。
目录是一个产品,只是有很多 SKU
让他想通的那次认知转变是:买家评估的不是一个个压缩包,而是这家店。如果封面、文件名和文件夹结构前后不一致,每上一个新品,店铺的可信度不是增加而是减少。
于是他选定一套封面模板,之后再没动过。他的 pack_product.py 用同一段 Pillow 代码路径、同一款字体、同一套版式,把每张封面渲染成 1280x720、每张缩略图渲染成 600x600,只改标题和副标题。它接收产品名、副标题和文件数量,一条命令就写出压缩包、封面和缩略图:
python pack_product.py my-product "My Product" "A short subtitle" 9
做到第九个产品时,封面已经可以互换。这就是目标——喜欢过某个产品的买家,一眼就能认出下一个。
命名和文件夹要先于一切
没有固定结构,目录迟早变成杂货抽屉。整套流水线默认的布局是这样的:
- assets/ 原始输出,每个素材一个文件
- output/ 待提交文件加 metadata.csv
- packs/ 成品压缩包加封面
- research/ 笔记和来源
- scripts/ 工具
有两条听起来无聊但很重要的规则。第一,文件名会变成标题。没有提供标题文件时,元数据脚本会把文件名转成标题格式,这意味着 botanical-border-04.jpg 第一遍就能变成可用标题。如果你的文件名是 final_final_v3.jpg,你的 CSV 就会继承这个毛病。第二,research/ 要永久保留。他曾为了"清理"删掉抓取日志,结果丢了三个后续产品的原始素材,再也不敢了。
元数据是图库平台先审判你的地方
如果同时在图库渠道卖货,目录问题会翻倍,因为每个平台要求的 CSV 形状不同,表头错一个就立刻被拒。Adobe Stock 要 5 列表头,Vecteezy 要 4 列,Dreamstime 要 15 列。错一列,整批上传在人工看到你的作品之前就被弹回来。
他写了 make_metadata.py,只写每个平台要求的那套表头,别的不写。同一个素材文件夹,三条命令:
python make_metadata.py ./my-assets --platform adobe --out metadata.csv --ext .jpg
python make_metadata.py ./my-assets --platform vecteezy --out vecteezy.csv --ext .jpg
python make_metadata.py ./my-assets --platform dreamstime --out dreamstime.csv --ext .jpg
一致性收益和封面一样:每个平台上的每个素材,标题和关键词都来自同一个真相源,所以买家无论在 Adobe 还是在你自己的收银台遇到你,看到的品牌是同一个。
唯一会让账号被标记的错误
这一条和好看无关,和生存有关。让图库账号被标记最快的方式,是把上传批次跑两遍。他早期干过一次,重跑了一个部分失败的脚本,结果发出去 30 个重复项。清理花了一个晚上,还算走运。
现在 upload_tracker.py 是一本普通账本,记住什么已经发过:
python upload_tracker.py pending items.txt # 显示还没做的
python upload_tracker.py done "asset-001.jpg"
python upload_tracker.py status
重跑永远不会重复发布,因为入队之前会先查账本。它只用 Python 标准库,完全不用安装。
把文档变成看起来像产品的产品
他目录里有一半不是美术文件,而是文档:指南、清单、提示词手册。一个裸 Markdown 文件不算产品。md2pdf.py 接收一个 Markdown 文件,渲染出带样式标题、表格、列表和链接的干净 PDF:
python md2pdf.py content.md product.pdf "My Product Title"
它用 reportlab,这就是全部依赖。每次排版都一样,所以目录里的 PDF 和旁边的封面是配套的。
让小服务器扛住的小习惯
这一切都不需要更大的机器,但需要纪律。一次只跑一个进程,绝不在单核上并行展开图片任务。每个素材处理完调用 gc.collect() 释放内存。用 resource.getrusage(RUSAGE_SELF).ru_maxrss 测峰值内存而不是平均占用,因为杀死 2 GB 机器的是峰值。重渲染步骤一个文件一个子进程,让内存归还给操作系统。只需要检查版式时,用 60 dpi 看预览,而不是渲染 300 dpi。
最终结果:39 个成品、856 MB 打包输出,压在大约 19000 行流水线代码之下,全部在同一台 1 vCPU、2 GB 内存的服务器上验证过。
上面这些不是事后写下的建议,而是四个独立的 Python 脚本:make_metadata.py、upload_tracker.py、md2pdf.py 和 pack_product.py。没有框架,没有云账号,第三方包总共两个——Pillow 和 reportlab,一半脚本只需要 Python 本身。它们是更大流水线里的打包层,也是把杂货抽屉变成"看起来像一个品牌"的目录的东西。
热门跟贴