DEV Community

Cover image for Two Packages, One Server: Metadata CSVs, Covers and PDFs for 39 Products

Two Packages, One Server: Metadata CSVs, Covers and PDFs for 39 Products

Two Packages, One Server: Metadata CSVs, Covers and PDFs for 39 Products

The first time a stock platform rejected one of my upload batches, it took me four hours to understand why. One column was out of order in the CSV. That's it. I had generated 39 products, zipped them, written the docs, and the batch died on a header row.

That rejection changed how I build. I stopped treating metadata and packaging as the boring afterthought and wrote scripts that enforce the rules instead of leaving them to my attention span at 1 a.m. Here is what actually matters.

Three platforms, three headers, no mercy

Adobe wants five columns. Vecteezy wants four. Dreamstime wants fifteen. Get one wrong and the whole file bounces before a human ever sees your art. I built one script, make_metadata.py, that writes the exact header each platform demands and nothing else. You point it at a folder:

python make_metadata.py ./my-assets --platform adobe --out metadata.csv --ext .jpg
Enter fullscreen mode Exit fullscreen mode

It title-cases the filename and uses that as a first pass. Fine for a dry run, not fine for submission. Pass --titles titles.json to supply real titles and keywords before you upload. The script does not guess, it writes the columns.

If you only use this one and the tracker, you need no install at all. Standard library only.

A ledger beats your memory

The fastest way to get an account flagged is running a batch twice. I got close once. It was 861 files, a re-run after a crash, and only a gut feeling that stopped me. After that I wrote upload_tracker.py. It remembers what you posted:

python upload_tracker.py pending items.txt   # what is NOT done yet
python upload_tracker.py done "asset-001.jpg"
python upload_tracker.py status
Enter fullscreen mode Exit fullscreen mode

A re-run of the same list cannot double-post, because the ledger knows. This is the least glamorous tool in the kit and the one I would pay for.

Docs that look like products

You have the content. You need it to look like something worth buying. md2pdf.py turns a Markdown file into a clean styled PDF with headings, tables, lists and links:

python md2pdf.py content.md product.pdf "My Product Title"
Enter fullscreen mode Exit fullscreen mode

Packaging: a zip alone does not sell

pack_product.py zips the files and renders two images: a cover at 1280×720 and a thumbnail at 600×600.

python pack_product.py my-product "My Product" "A short subtitle" 9
Enter fullscreen mode Exit fullscreen mode

It writes the zip, cover and thumb into a _system folder next to where you run it. Point it elsewhere with --dir or the PACK_ROOT environment variable. No editing the script.

That is the entire dependency story: two third-party packages across four scripts. Pillow for the covers, reportlab for the PDFs. Nothing else.

It ran on 1 vCPU and 2 GB of RAM

The full pipeline produced 39 products, 856 MB of output, from a single-core server with no GPU. It works because of five habits, not hardware:

  • One process at a time. Never fan out image jobs in parallel on a one-core box.
  • Free memory between items. gc.collect() after each asset.
  • Measure peak RSS, not average. resource.getrusage(RUSAGE_SELF).ru_maxrss tells you the real ceiling.
  • One file per subprocess for heavy render steps, so memory returns to the OS.
  • Render at the resolution you need. Inspecting a preview at 60 dpi beats rendering it at 300.

The folder layout matters too. Keep assets/, output/, packs/, research/ and scripts/ separate. And keep research/ forever. I deleted scrape logs once to "clean up." They were the raw material for the next three products. I won't repeat that.

What this came from

These four scripts sit under a larger pipeline: roughly 19,000 lines of code in the parent project, with 300+ pages of research behind the rules the scripts enforce. The tools are the packaging layer of everything I sell.

I packaged them as the compliance metadata kit: the four working scripts, the folder structure, and the RAM notes above. Not a tutorial that ends at "here's how you'd do it." The same tools that shipped 39 products on a 2 GB server.

If you have ever lost a day to a rejected CSV column, start there.

Get compliance metadata kit


Building digital products? Free guides & kits for digital product sellers.

Top comments (0)