Thanks for helping out. DarcAds aims to be the tool people reach for instead of paying a subscription, which means it has to stay reliable on machines we will never see.
git clone https://github.com/<your-username>/DarcAds.git
cd DarcAds
python3 -m venv venv && source venv/bin/activate
pip install -r requirements.txt
pip install -r requirements-optional.txt # optional, for testing those paths
python3 main.py --doctor # confirm ffmpeg is found
python3 -m unittest discover -s testsEvery stage must degrade, never fail.
A missing API key, a dead image URL, a provider outage, an ffmpeg build without libass, a product page with no images — none of these may stop a video from being produced. Fall back to the next-best option, log what happened, and keep going.
Concretely, if you add a provider:
- Return
Noneon failure rather than raising warn()with enough detail for the user to fix it- Make sure the caller has a fallback below you
- Add a test asserting the fallback fires
The keyless path is what most people run first. If a change makes the free output worse, it is not an improvement.
| Adding | Goes in |
|---|---|
| A storefront parser | src/ingest.py — add a strategy, keep the existing order |
| A hook framework | src/llm_director.py — HOOK_FRAMEWORKS and an offline copy template |
| A TTS engine | src/voice.py — a _tts_* function plus an ENGINE_ORDER entry |
| A video provider | src/visuals.py — a _*_generate function, wired into generate_scene_visual |
| An avatar provider | src/avatars.py |
| A caption style | src/captions.py — render_caption_frame |
| A render feature | src/compiler.py — prefer a new stage over a bigger filter graph |
Shared data structures belong in src/models.py. Anything that reads the
environment belongs in src/config.py.
- Python 3.9 compatible. Use
Optional[X]/List[X], notX | None— the pydantic models are evaluated at runtime and|unions break on 3.9. - Type hints on every function.
- Validate data crossing a module boundary with pydantic.
- Deterministic and modular. The LLM decides copy; code decides everything else. That is what keeps output debuggable.
- Comment the why, not the what. A comment explaining why crossfade headroom is added to each clip earns its place; one saying "loop over scenes" does not.
- Match the surrounding code's naming and density.
python3 -m unittest discover -s tests
python3 -m unittest tests.test_compiler # one module- No network in tests. Mock
requests, and patchsrc.voice._ENGINESto disable TTS. - Test the fallback, not just the happy path — that is where the bugs are.
- Compiler and pipeline tests run real ffmpeg and take a couple of minutes.
Keep new render tests short (1–2 second clips,
quality="draft"). - If you fix a bug, add the test that would have caught it.
- Branch from
main - Keep it focused — one concern per PR
- Run the full suite
- If you touched rendering, attach a before/after frame or clip
- Describe what a user will notice, not just what changed
Include the output of python3 main.py --doctor, your OS and Python version,
the exact command, and the product URL if it can be shared. For render issues,
the output/*_run.json manifest is the most useful single artefact.
In scope: better scraping, better copy, better renders, more providers, more platforms, docs.
Out of scope: anything that requires a hosted DarcAds service, telemetry, or that makes an API key mandatory for a stage that currently works without one.
Contributions are accepted under the MIT licence. Do not commit copyrighted music, fonts you cannot redistribute, or anyone's likeness.