DEV Community

Cover image for Building The Exact Adobe, Vecteezy And Dreamstime CSVs With One Python Script

Building The Exact Adobe, Vecteezy And Dreamstime CSVs With One Python Script

The first time I tried to upload a batch to Adobe Stock, I spent forty minutes writing what I thought was a clean CSV. It got rejected before a single file was reviewed. The error was the header row. I had the columns in the wrong order, and Adobe does not negotiate. It checks the header, and if it does not match exactly what the upload spec says, the whole file is dead on arrival. That night I stopped hand-editing spreadsheets and wrote one Python script that builds all three CSVs correctly, every time. This post is what I learned doing that, and how the script works.

The three headers are different, and that is the whole problem

Adobe Stock wants a five column CSV. Vecteezy wants four columns. Dreamstime wants fifteen. Same assets, same titles, same keywords, three completely different shapes. If you maintain three spreadsheets by hand, you will eventually upload the wrong one to the wrong platform, and the rejection is instant and silent. The file just does not appear.

So make_metadata.py takes one input, a folder of files, and emits the exact header each platform demands, nothing extra. You run it three times with a flag:

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

One folder of assets, three correct CSVs. The script uses only the Python standard library. No pip install, no dependencies, nothing to break on a fresh machine. That matters more than it sounds. When your pipeline runs on a 1 vCPU, 2 GB server with no GPU, every dependency is a liability.

Titles and keywords: the honest default

Without any extra input, the script title-cases the filename and uses it as the title. That is fine for a first pass, and I want to be clear that it is not fine for submission. Reviewers on all three platforms can tell when a title is just a filename. If you pass --titles titles.json, the script pulls real titles and real keywords per file instead. I keep that JSON next to the asset folder and fill it in before anything goes out the door. The default exists so the pipeline never blocks on missing data, but replacing it is your job, not the script's.

The mistake that gets accounts flagged: double-posting

This one cost me real time. I re-ran a batch job that had partially completed, and several assets went up twice. Duplicate submissions are the fastest way to draw attention from a review team, and once you are on that radar, every future batch gets slower scrutiny.

The fix is boring and it works. upload_tracker.py is a small ledger, standard library only, that remembers what you have already 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

Before any batch runs, it checks the ledger. A re-run now skips everything already marked done. It is about forty lines of code and it has prevented every duplicate since. If you build nothing else from this post, build the ledger.

Running this on a 2 GB server

The whole pipeline, including these scripts, ran on a single vCPU with 2 GB of RAM and no GPU. The habits that made that possible:

One process at a time. Never fan out image jobs in parallel on a one-core box, it just thrashes. Call gc.collect() after each asset to free memory between items. Measure peak RSS with resource.getrusage(RUSAGE_SELF).ru_maxrss, not average usage, because the peak is what gets you killed. For heavy render steps, run one file per subprocess so memory is actually returned to the operating system. And render at the resolution you need, inspecting a preview at 60 dpi instead of 300 saves an enormous amount of RAM.

The metadata and tracking scripts are pure text processing, so they run comfortably in that environment. The scripts that touch images, the cover renderer in pack_product.py, are the ones where the memory habits matter.

Packaging is where the sale actually happens

A zip with a real cover sells. A bare file does not. I learned this after watching one product with a proper 1280×720 cover outsell an identical one with no cover image, at the same price, in the same week.

pack_product.py takes a folder, a title, a subtitle, and a file count, and writes three things: the product zip, a 1280×720 cover, and a 600×600 thumbnail. It uses Pillow for the images, and that is one of only two third-party packages in the entire kit. The other is reportlab, which md2pdf.py uses to turn a Markdown file into a styled PDF with headings, tables, lists, and links. One command per product:

python md2pdf.py content.md product.pdf "My Product Title"
python pack_product.py my-product "My Product" "A short subtitle" 9
Enter fullscreen mode Exit fullscreen mode

The output goes to a _system folder, and you can redirect it with --dir or the PACK_ROOT environment variable without editing the script.

The folder layout that keeps a catalogue from becoming a junk drawer

This is the structure the whole kit assumes:

project/
  assets/            raw output
  output/            ready-to-submit files + metadata.csv
  packs/             finished product zips + covers
  research/          notes and sources
  scripts/           the tools
Enter fullscreen mode Exit fullscreen mode

Keep research/ forever. Your notes and logs are the raw material for future products. Deleting them to clean up is a mistake I made once and will not repeat.

Where this came from

These four scripts are the packaging layer of a larger pipeline that produced 39 finished products, 856 MB of output, from about 19,000 lines of code and 300+ pages of research. Everything ran on that same 1 vCPU, 2 GB box. I did not design the scripts first and hope they worked. I hit the failures, the rejected CSV header, the duplicate submissions, the products that did not sell bare, and wrote the smallest tool that fixed each one.

I packaged the four scripts, plus the install notes and the folder conventions, into the Pipeline Starter Kit. It is the tool built from this work, not a course, just the working code with the rules baked in.

See the kit


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

Top comments (0)