From Prompt To Packaged Product In Under An Hour: The Four Scripts That Made 39 Stock Assets
Last spring I had 39 finished assets sitting in a folder and zero of them uploaded. The bottleneck wasn't the art. It was that Adobe's uploader rejected my CSV twice in a row because I had the wrong column count in the header, and I almost re-posted a batch I'd already submitted because I couldn't remember what I'd sent the week before. That second one is the scary one. Double-posting is the fastest way to get an account flagged, and I was one tired evening away from doing it. That failure is why I built four small scripts. Together they took a prompt engine's output and packaged 39 finished products, 856 MB of output, on a server with 1 vCPU, 2 GB RAM, and no GPU. Here's what actually worked. Metadata is a formatting problem, not a creative one Every stock channel has a fixed CSV header and rejects anything else instantly. Adobe wants 5 columns. Vecteezy wants 4. Dreamstime wants 15. I used to hand-build these in a spreadsheet, which meant copy-pasting filenames, title-casing by hand, and hoping the header matched the template I downloaded three weeks ago. make_metadata.py ended that. You point it at a folder of files and name the platform: python make_metadata.py ./my-assets --platform adobe --out metadata.csv --ext .jpg It writes the exact header that channel demands and nothing else. The three CSVs for a batch took under a minute to generate. One honest caveat: without a titles file, the script title-cases the filename and uses that as the title. That's fine for a first pass, but you should replace it with real titles and keywords before you submit. Filenames like asset-001.jpg make terrible listings. A ledger beats memory The double-posting fix was the simplest script of the four. upload_tracker.py is just a ledger that remembers what you've already posted: python upload_tracker.py pending items.txt python upload_tracker.py done "asset-001.jpg" python upload_tracker.py status Before every batch I run pending and only upload what it shows. Re-running the batch is now safe by construction, not by memory. It uses the standard library alone, no install, no database. If you take one idea from this post, take this one: the tool that prevents an account flag doesn't need to be clever, it needs to be boring and always run. Turning a doc into a product in one command Half my products are documents: guides, pattern sheets, license notes. The gap between "I have the content" and "this looks like a product" used to be an afternoon of fiddling in a word processor. md2pdf.py collapses it to: python md2pdf.py content.md product.pdf "My Product Title" It handles headings, tables, lists, and links through reportlab, which is one of only two third-party packages in the whole kit. The other is Pillow for covers. Everything else, including the metadata and tracking scripts, runs on stock Python. Packaging: a zip with a cover sells, a bare file does not The last script bundles everything. pack_product.py zips the files and renders a cover at 1280×720 plus a thumbnail at 600×600: python pack_product.py my-product "My Product" "A short subtitle" 9 Output lands in a _system folder next to where you run it, and you can redirect it with --dir or the PACK_ROOT environment variable. No editing the script. Those two image sizes matter because marketplace listings crop differently than product pages, and one render pass covers both. The folder layout that saved me from a junk drawer Structure matters more than tooling once you pass about twenty assets. This is the layout the whole pipeline assumes: project/ assets/ raw output (one file per asset) output/ ready-to-submit files + metadata.csv packs/ finished product zips + covers research/ your notes and sources scripts/ these tools One hard-won rule: keep research/ forever. I once deleted my scrape logs and notes to "clean up" and lost the raw material for three follow-up products. Never again. Running this on a tiny box The whole thing ran on 1 vCPU and 2 GB RAM, so a few habits carried the load: One process at a time. Never fan out image jobs in parallel on a 1-core box. Call gc.collect() after each asset to free memory between items. Measure peak RSS, not average. resource.getrusage(RUSAGE_SELF).ru_maxrss tells you the real ceiling. Run heavy render steps one file per subprocess so memory returns to the OS. Render at the resolution you need. Inspecting a preview at 60 dpi beats rendering at 300. None of this is exotic. It's just what a 2 GB box forces you to learn, and learning it on your own costs a few crashed batches. What this added up to Four scripts, about 19,000 lines of pipeline code in the parent project behind them, 300+ pages of research behind the rules the scripts enforce, and 39 finished products out the other end. The making of the art was maybe a third of the work. The other two thirds was metadata headers, upload tracking, PDFs, and packaging, and that's the part almost nobody writes about because it isn't fun. I've bundled these four scripts, with the install steps and the folder layout above, into the ai sticker factory playbook. It's the same packaging layer I run, documented honestly, including the caveats like the filename-title fallback. If you're stuck at the "assets done, nothing shipped" stage I was stuck at, this is the tool built from getting unstuck. Get ai sticker factory playbook Building digital products? Free guides & kits for digital product sellers.
This is a summary aggregated from Dev.to. Read the complete article on the original site:
Read full article at Dev.to