[KongchangAI]
· 2 min read· 1,365 words

Four Python Scripts to Package and Manage 39 Digital Products

Four Python Scripts to Package and Manage 39 Digital Products

An independent creator uses four minimalist Python scripts to solve metadata, duplicate submissions, PDF packaging, and low-spec server operation for stock uploads.

The article recounts how an independent creator, after mass rejections on Adobe Stock due to mismatched CSV header columns, developed a minimalist Python toolchain relying only on the standard library plus Pillow and reportlab. make_metadata.py generates exact platform-specific headers, upload_tracker.py uses a ledger to prevent duplicate submissions, and md2pdf.py and pack_product.py convert Markdown to styled PDFs and package zips with covers. The author also shares habits for running a 19,000-line pipeline on a 1-core, 2GB server: single process, gc.collect(), peak RSS measurement, on-demand resolution rendering, and the insistence that the research/ folder must be kept forever.

Meta Description

An independent creator uses four Python scripts to solve metadata format issues, duplicate submissions, PDF conversion, and product packaging for stock photo uploads—processing 39 products and 856MB of output on a 1-core, 2GB server. Includes folder structure and memory management tips.

Article Content

An independent creator had 40 of the first 50 works rejected on Adobe Stock due to mismatched CSV header column counts. That lesson spawned a minimalist Python toolchain: using only the standard library and two third-party packages, it processed 39 products and 856MB of output on a 1-core, 2GB server. This article breaks down the design thinking and practical details of four core scripts.

Metadata is a format problem, not a creativity problem

The three major stock channels (Adobe Stock, Vecteezy, Dreamstime) all validate CSV headers before even looking at the images. Adobe requires 5 columns, Vecteezy requires 4, Dreamstime requires 15—if the column count is wrong, the batch is rejected outright, never even reaching human review. The author initially hand-wrote CSVs assuming cross-platform compatibility, and ended up spending an entire week re-uploading.

make_metadata.py solves exactly this: point it at a folder, declare the platform name, and the script outputs the exact header that platform requires—not one column more, not one less. It relies only on the Python standard library, requires no pip install, and won't break six months later due to library updates.

Metadata script illustration

The script has one honest flaw: if no title file is passed in, it converts filenames into title case (e.g., blue_flower_0042.jpg becomes "Blue Flower 0042"). The author warns this is only for first drafts and must be replaced before submission. Reviewers can spot this lazy naming instantly, and weak titles and keywords are the second-biggest rejection reason after format errors.

CSV header validation becomes the first gate on stock platforms because they rely on structured data with fixed column names for batch import, automatic categorization, and copyright verification. When header column counts or names don't match, the import program can't parse subsequent rows, and the entire batch is returned by the system before entering the human review queue. Adobe Stock's 5 columns typically cover filename, title, keywords, category, and copyright statement; Vecteezy's 4 columns are more streamlined; Dreamstime's 15 columns include more descriptive fields like model releases and editorial use flags. This variation stems from differences in each platform's internal asset management systems and search logic, so no universal CSV template exists. Independent creators hand-assembling headers are highly prone to column-order or required-field errors, and platforms usually return only vague rejection reasons, further raising the cost of trial and error.

Duplicate submissions are the fastest way to lose your account

After the first partial failure, the author re-ran the entire batch, and files that had already passed were submitted a second time. Duplicate submissions trigger review flags, and with enough flags, reviewers start distrusting everything you submit afterward.

upload_tracker.py is a minimalist ledger: done "asset-001.jpg" marks an item complete, pending items.txt shows only outstanding items, and status gives a global overview. On re-runs, the tracker remembers what's already been submitted, physically preventing duplicates. This script also uses only the standard library, with no external dependencies.

Stock platform review systems automatically flag duplicate submissions of the same file or highly similar metadata. A few duplicates may only trigger warnings, but once a threshold accumulates, the account gets demoted—manifesting as longer review cycles, lower approval rates, and even direct escalation to manual review or temporary bans. This is because duplicate submissions are seen as abusing the upload channel and wasting review resources, similar to risk signals for malicious spam or copyright fraud. A more insidious risk: when re-running batches, files that already passed review may be resubmitted, and the platform may classify them as duplicate content and take down the original works—losing both download revenue and ranking weight already earned. So the core value of an upload ledger isn't tracking progress, but providing an unavoidable submission history that structurally eliminates duplicate actions.

Documents must look like products before they can sell

The author had 300+ pages of research material, but Markdown suits writing, not selling. md2pdf.py converts Markdown to a styled PDF with one command—headings, tables, lists, and links all render correctly. This is one of only two third-party dependencies in the entire toolkit (reportlab).

pack_product.py handles the other half: packaging product files into a zip and using Pillow to generate a 1280x720 cover and a 600x600 thumbnail. The author learned from his own conversion data: zips with real covers sell; bare files don't. Output goes to the _system folder by default, redirectable via the --dir parameter or the PACK_ROOT environment variable—no code changes needed.

Folder structure: the part nobody warns you about

After 39 products, an unstructured directory becomes a junk drawer. The toolkit assumes a plain layout:

  • assets/: raw output
  • output/: files to submit and their metadata CSVs
  • packs/: finished zips and covers
  • research/: notes and logs
  • scripts/: tool scripts

The author stresses one iron rule: keep research/ forever. He once deleted scraped logs to "clean up," and needed them again two products later. Notes and logs are raw material for future products—a hard drive is far cheaper than redoing research.

Habits that keep 19,000 lines of code alive on a small server

The underlying pipeline is roughly 19,000 lines of code, all running on a 1-core, 2GB machine. Key practices:

  • Run only one process at a time. Parallelizing image tasks on a single core doesn't speed things up—it just causes memory swapping.
  • Free memory between tasks. Execute gc.collect() after each asset to prevent slow memory creep over long batches.
  • Measure peak RSS, not averages. resource.getrusage(RUSAGE_SELF).ru_maxrss shows the real ceiling. Averages lie; the peak is the number that triggers the OOM killer.
  • Re-render steps handle only one file per subprocess, ensuring the OS actually reclaims memory.
  • Render at the resolution you need. Use 60 dpi previews instead of 300 dpi checks—render time drops sharply, and previews never needed full resolution anyway.

Peak RSS (Resident Set Size) is the maximum physical memory a process actually occupies over its lifetime, not the average at any given moment. On a 1-core, 2GB server, the OS and background services typically already consume hundreds of MB, leaving limited headroom for the Python pipeline. Averages may show flat memory usage, but instantaneous peaks during image processing or PDF rendering can suddenly approach the limit and trigger the OOM killer to terminate the process outright. resource.getrusage(RUSAGE_SELF).ru_maxrss returns exactly this historical peak, in KB (Linux). Monitoring peak RSS helps developers locate the source of memory creep in long batch tasks—such as unreleased image buffers or accumulated intermediate objects. Combined with active gc.collect() reclamation and single-process serial execution, the memory curve can stay sawtoothed across tasks rather than continuously rising.

Where the tools fit

These four scripts aren't magic. They're boring, small, standard-library-first, and solve exactly the four things that actually block independent creators: metadata headers that pass validation, a ledger that prevents duplicate submissions, one-command PDF generation, and packaging with real covers. They handled 39 products and run on any Python 3.9 environment, including a 2GB-memory server. The author packaged them as a starter toolkit containing the four scripts, a dependency file with only Pillow and reportlab, and the folder conventions above.

One-line Summary

An independent creator uses four minimalist Python scripts to solve metadata, duplicate submissions, PDF packaging, and low-spec server operation for stock uploads.

Paragraph Summary

The article recounts how an independent creator, after mass rejections on Adobe Stock due to mismatched CSV header columns, developed a minimalist Python toolchain relying only on the standard library plus Pillow and reportlab. make_metadata.py generates exact platform-specific headers, upload_tracker.py uses a ledger to prevent duplicate submissions, and md2pdf.py and pack_product.py convert Markdown to styled PDFs and package zips with covers. The author also shares habits for running a 19,000-line pipeline on a 1-core, 2GB server: single process, gc.collect(), peak RSS measurement, on-demand resolution rendering, and the insistence that the research/ folder must be kept forever. The full toolkit processed 39 products and 856MB of output, and runs on any Python 3.9 environment.

#Python scripts#digital products#stock photo upload#metadata CSV#duplicate submission#PDF conversion#memory management#independent creator
Share:

Related articles