I made 1,700 assets before my first $0.99 sale. That number is not a brag. Most of it was rework, and every hour of rework came from four problems I kept solving by hand: metadata, double posts, documents that did not look like products, and bare zips with no cover.
The worst one was small. Adobe rejected a 400 row batch because my CSV header was wrong. Not the art. The header. Five columns, my file had four. Whole batch refused at the door. I fixed it by hand, re-uploaded, and then realized a chunk of it had already gone up in the earlier run, so I had just posted part of it twice. That day I stopped doing it manually and wrote four scripts.
None of them are clever. They are the four steps that break a catalogue, and each one is one file.
Wrong header, dead batch
Adobe takes five columns. Vecteezy takes four. Dreamstime takes fifteen. Wrong count or wrong order and the file is refused whole, no partial accept.
make_metadata.py writes the header the platform demands and nothing else. Pass --platform adobe, --platform vecteezy, or --platform dreamstime, point it at a folder, give it --ext .jpg, and it drops the CSV.
python make_metadata.py ./my-assets --platform adobe --out metadata.csv --ext .jpg
Default title is the filename, title cased. That is fine for a first pass and not fine for submitting. Pass --titles titles.json once you have real titles and keywords. I do not let the script pretend a filename is a title when I have better data sitting right there.
Standard library only. No install.
Double posting gets accounts flagged
Fastest way to lose an account is running the same batch twice. I did it. Once is a mistake. A pattern is a review.
upload_tracker.py is a ledger. Mark a file done and it never shows up as pending again.
python upload_tracker.py pending items.txt
python upload_tracker.py done "asset-001.jpg"
python upload_tracker.py status
Run pending before every submit. That costs one command, an account review costs weeks.
Standard library only. No install.
A document is not a product
Two separate problems here, two separate scripts.
md2pdf.py turns a Markdown file into a styled PDF with headings, tables, lists and links intact. One command:
python md2pdf.py content.md product.pdf "My Product Title"
pack_product.py does the packaging. A zip with a real cover sells. A bare file does not.
python pack_product.py my-product "My Product" "A short subtitle" 9
That writes the zip, a 1280x720 cover, and a 600x600 thumbnail. Point the output elsewhere with --dir or the PACK_ROOT environment variable. No editing the script to move a folder.
These two need Pillow and reportlab. Two packages, that is the whole dependency list.
It has to run on 1 vCPU and 2 GB
The full pipeline never touched a GPU and never had more than 2 GB of RAM. It held together because of habits, not hardware:
- One process at a time. Never fan out image jobs on one core.
- Free memory between items.
gc.collect()after each asset. - Measure peak RSS, not average.
resource.getrusage(RUSAGE_SELF).ru_maxrssgives the real ceiling. - Run heavy renders as one file per subprocess, so memory goes back to the OS.
- Render at the resolution you need. A preview at 60 dpi beats a 300 dpi render you throw away.
The instinct on a small box is to parallelize. That is the wrong instinct. Serial jobs that finish beat parallel jobs that swap.
What the numbers actually say
Four scripts packaged 39 products, 856 MB of output, behind about 300 pages of research. The parent pipeline is roughly 19,000 lines and it all ran on 1 vCPU, 2 GB, no GPU.
The honest part: I have made around 1,700 assets and 58 are live on Adobe. The gap is the real lesson. Making assets is cheap now, so most of the work is choosing what not to submit. A ledger and a correct header matter more than another batch.
Where this leads
If you want the same four tools, they are the packaging layer of the Digital Asset Factory, the full system built from this work. It plugs into a free stack: Hermes Agent for scheduling and retries, 9Router for local LLM access, and the four scripts for metadata, tracking, PDFs and packaging.
Start with make_metadata.py and upload_tracker.py. They are standard library, no install, and they fix the two mistakes that cost me the most.
Building digital products? Free guides & kits for digital product sellers.
Top comments (0)