Skip to content

About

Generate vertical short-form videos from a topic using Gemini, Edge TTS, Whisper captions, Pexels backgrounds, and MoviePy rendering.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

10 Commits

Folders and files

Repository files navigation

SlopEngine

SlopEngine generates vertical short-form videos from a topic.

Launch the interactive workspace with python -m slopengine. The existing python shorts_core.py --topic "Example" CLI remains available.

The pipeline asks Gemini for a rewritten YouTube title, spoken narration, Pexels search keywords, and a visual search query. It then uses Edge TTS for narration, Whisper for word-level captions, Pexels for portrait background video, and MoviePy to render a 9:16 MP4. It can also upload the finished video to YouTube Shorts.

Screenshots

SlopEngine dashboard with setup status and recent generation summary

Create view with a sample topic, output filename, and upload consent

Outputs

Generated files go under outputs/ by default:

  • <timestamp>-<topic>.mp4: rendered vertical video
  • <timestamp>-<topic>.metadata.json: topic, generated title, script payload, word events, background files, output path, and YouTube upload metadata when present

Temporary media is created under /tmp/shorts_core by default and is cleaned after each run unless you pass --keep-temp.

Requirements

  • Python 3.11+; Python 3.12 is recommended for media dependency compatibility
  • FFmpeg installed and available on PATH
  • A Gemini API key
  • A Pexels API key
  • Optional: YouTube OAuth client secrets for upload

Install FFmpeg before generating videos. On Debian or Ubuntu, run sudo apt install ffmpeg; on macOS, run brew install ffmpeg. On Windows, install FFmpeg from the official download page and add its bin directory to PATH. Confirm it is available with ffmpeg -version.

Install

Clone the repository:

git clone https://github.com/Papajittan/SlopEngine.git
cd SlopEngine

Create and activate a virtual environment. On Linux or macOS:

python3.12 -m venv .venv
source .venv/bin/activate

On Windows PowerShell:

py -3.12 -m venv .venv
.\.venv\Scripts\Activate.ps1

Install SlopEngine and its Python dependencies, then create your local config:

python -m pip install --upgrade pip
python -m pip install -e .
cp .env.example .env

In PowerShell, use Copy-Item .env.example .env for the last command. Edit .env and set GEMINI_API_KEY and PEXELS_API_KEY to your own keys. Keep .env private; it is ignored by git. The dashboard can open without credentials, but generating a video needs both keys, the media dependencies, and FFmpeg. The dashboard does not load Whisper, Torch, or MoviePy or call external providers. CPU Whisper is the default.

To run the legacy CLI without installing the package command, install dependencies with python -m pip install -r requirements.txt and run python shorts_core.py ... from the repository.

Interactive workspace

The Textual interface has seven views:

View Features
Dashboard Local dependency/key readiness, video count, latest output, active job
Create Manual or Auto mode, shared voice/transcription/music options, upload consent, summary
Monitor Actual pipeline stages, elapsed time, live logs, cancellation, saved output or errors
Queue Persistent jobs, bulk add, independent logs, retry/recovery, reordering, concurrency controls
Library Existing MP4s, titles/topics, timestamps, sizes, upload status, metadata, open/copy path, topic reuse
Settings Persistent non-secret engine, voice, output, music, caption, and upload privacy preferences
Logs Live events and saved logs from previous generation jobs

Use Tab / Shift+Tab to move focus, Enter to activate buttons, Space to toggle checkboxes, and arrow keys to navigate tabs, tables and selections. Forms and panels scroll in smaller terminals. Advanced Create options expand with Enter.

Shortcut Action
Ctrl+1 / Ctrl+2 / Ctrl+3 / Ctrl+4 / Ctrl+5 / Ctrl+6 / Ctrl+7 Dashboard, Create Manual, Library, Settings, Logs, Monitor, Queue
Ctrl+8 Open Create in Auto Mode
Ctrl+G Start the selected Create mode
Ctrl+X Cancel the current generation
Ctrl+Q / Ctrl+C Quit (asks before cancelling an active job)

To generate manually: open Create, choose Manual, enter a topic or detailed prompt, optionally name the MP4, expand shared options if needed, review the summary, and choose Generate. Plain filenames go into your configured output directory; paths with directories are used as entered. Existing video or metadata files are never overwritten. Leave the voice blank for automatic language selection, or enter an Edge TTS voice such as en-US-GuyNeural to override it. The monitor follows Gemini, Edge TTS, Whisper, Pexels, rendering, saving, and optional upload. It shows stage states and elapsed time without inventing percentages. The persistent queue allows up to two active jobs by default, while limiting concurrent renders to one and GPU Whisper stages to one. Preparation can overlap a render; adjust these limits in Queue. The app must remain open to advance queued work.

Upload is off for every new TUI job or Auto session regardless of YOUTUBE_UPLOAD_ENABLED. Check the shared consent box to upload one manual video; in Auto mode, the same checkbox covers every video in that session. Privacy and voice, transcription, music, and OAuth paths come from the shared Create settings. Privacy defaults to private. Consent and those settings are saved with the Auto session, so an explicit resume keeps the original choices. A new session needs a new checkbox opt-in. OAuth can open your browser during upload. If an Auto upload fails, the finalized MP4 stays in Library, counts toward the target, and pauses the session with the upload error. Resume continues with remaining videos without rerendering or automatically retrying that upload.

Open Library to inspect finished outputs or reuse a topic. Missing or malformed metadata does not prevent listing a nonempty MP4. The system opener requires xdg-open on Linux or open on macOS. Clipboard support depends on your terminal's OSC 52 support; the full path is also displayed for manual copying.

Preferences, execution and logs

Configuration precedence is environment / .env defaults, then saved application preferences, then temporary Create options. Exported environment variables take precedence over .env. CLI runs continue to use environment configuration only. Settings are stored in $XDG_STATE_HOME/slopengine/preferences.json, defaulting to ~/.local/state/slopengine/preferences.json; jobs.sqlite3 and job logs are in that same state directory and its logs/ subdirectory. API keys are never saved in preferences. Key status shows presence only. If the Gemini key is missing or still contains the .env.example placeholder, Dashboard shows a masked input. Enter the key and press Enter or choose Use Gemini key to configure it for the current session, including generation workers. To keep it across restarts, configure GEMINI_API_KEY in .env or your environment. Entered keys are not written to preferences or logs.

Generation runs in an isolated Python process, keeping Whisper and MoviePy off the UI event loop and preserving the existing main-thread SIGALRM timeout. Structured events and captured diagnostic output feed the monitor and saved JSONL logs. Known environment secrets and credential fields are redacted. Cancellation sends termination to the process group and escalates after four seconds if required. Normal cancellation cleans temporary and staging files. Forced termination, crashes, or power loss can leave hidden .slopengine-* staging directories or temporary runs; these are not listed as completed videos. Keep temporary media intentionally retains temporary diagnostics. Never remove unrelated files when cleaning abandoned runs.

POSIX systems support process-group cancellation. Windows termination is more limited: descendant process cleanup and SIGALRM timeouts are not guaranteed there. Generation and the existing external-service integrations should be exercised in your own environment before relying on unattended runs.

For Whisper CUDA, avoid Python 3.14. Use a Python 3.12 environment and keep WHISPER_DEVICE=cuda in .env:

python3.12 -m venv .venv312
.venv312/bin/python -m pip install --upgrade pip
.venv312/bin/python -m pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu130
.venv312/bin/python -m pip install -r requirements.txt
.venv312/bin/python shorts_core.py --upload

If your GPU driver needs a different CUDA wheel, choose the matching pip command from the PyTorch install selector.

If Whisper or MoviePy cannot read media, check FFmpeg first:

ffmpeg -version

Auto Mode

Open Create and select Auto Mode, or press Ctrl+8. Enter a niche, then enter a positive whole number in Number of Videos. Leave it blank to run without a target. Check the shared upload-consent box to upload all videos in the session; leave it unchecked for local-only videos. Auto Mode asks Gemini for up to five topic ideas at a time, while reserving at most three not-yet-started jobs in the existing resource-aware queue. The default limits remain two active jobs, one render at a time, a 7 GiB render-stage reservation, and 3 GiB of system memory headroom. Auto Mode shares these limits with manual jobs. It keeps requesting replacement topics after individual video failures. A finite target counts only videos whose MP4 and metadata file both exist and are nonempty, with metadata that parses as a JSON object; it stops after exactly that many finalized MP4s. If an opted-in upload fails, the verified video still counts, remains available locally, and pauses the session with an actionable error; resuming continues without rerendering or retrying that upload. For example, set the niche to Space mysteries and the count to 10; leave the count blank to run until you press S or X.

The Auto section in Create shows the niche, target, generated count, active and queued jobs, duplicate rejections, topic-request usage, each accepted topic's current stage, and the count of completed pipeline stages. It never estimates render percentages. Its event log is saved in the same jobs.sqlite3 database as the job queue.

Use P to pause, R to resume, S to stop after started Auto jobs finish, and X to cancel only jobs owned by the current Auto session. Pause stops new topic requests and worker dispatch, then lets an active pipeline stage finish before holding at the next stage boundary. The reserved queue stays saved. Stop cancels Auto jobs that have not started and lets active Auto jobs finish; cancel also terminates active Auto workers. Neither action touches manual jobs. These shortcuts work only when Create is set to Auto and are ignored while a text input has focus. ? shows help.

After an application restart, an interrupted Auto session is paused and needs an explicit R. Resuming reuses held job IDs, counts already finalized files from a crash window, preserves the session's upload consent and privacy configuration, and never silently starts a new session. An upload interrupted after save is recorded as a failed delivery while the finalized video remains counted and available.

Duplicate protection compares NFKC/case-folded text after punctuation and spacing normalization, conservative text similarity, and a small deterministic concept/synonym map. It checks all stored Auto sessions, manual jobs, and existing output metadata. Rejected ideas retain their match and score. This is a local heuristic rather than an embedding model; it can miss paraphrases that do not share the mapped concepts. When a rendered script title overlaps another topic, Auto Mode records the overlap and cancels that job before narration and rendering. A fallback overlap discovered after publication is annotated in history, and the finalized file is retained.

AUTO_MAX_TOPIC_REQUESTS_PER_MINUTE and AUTO_MAX_TOPIC_REQUESTS_SESSION meter Auto topic-discovery Gemini calls, including explicit fallback model lookup and generation calls. They do not meter the separate Gemini script request made by each video worker. A session budget of 0 means no request limit; these are request counts, not a dollar estimate. AUTO_TOPIC_REQUEST_COOLDOWN_SECONDS sets the minimum delay between discovery calls. AUTO_MIN_FREE_DISK_GIB sets the minimum free space required on both output and temp filesystems. Consecutive video failures and batches with no unique ideas stop in an actionable ERROR state with queued work preserved.

Configuration

Copy the example env file and fill in your own keys:

cp .env.example .env

Do not commit real credentials. .env, client_secrets.json, and .youtube_token.json are ignored by git.

Required keys:

Variable Purpose
GEMINI_API_KEY Google AI Studio key for script, title, keywords, and Pexels query generation
PEXELS_API_KEY Pexels API key for background videos

Common optional keys:

Variable Default Purpose
GEMINI_MODEL gemini-2.5-flash Gemini model for content generation
GEMINI_TIMEOUT_SECONDS 60 Gemini content generation timeout
AUTO_MAX_TOPIC_REQUESTS_PER_MINUTE 4 Maximum Auto topic-discovery Gemini calls in a rolling minute; excludes video-script requests
AUTO_MAX_TOPIC_REQUESTS_SESSION 0 Maximum Auto topic-discovery Gemini calls in one session; 0 means unlimited
AUTO_TOPIC_REQUEST_COOLDOWN_SECONDS 5 Minimum delay between topic-discovery provider calls
AUTO_MIN_FREE_DISK_GIB 1 Required free space on output and temporary-media filesystems
AUTO_MAX_CONSECUTIVE_FAILURES 5 Consecutive failed Auto video jobs before preserving work in ERROR
AUTO_DUPLICATE_BATCH_LIMIT 3 Duplicate-only topic batches before Auto pauses with an actionable error
AUTO_DUPLICATE_SIMILARITY 0.9 Conservative normalized-title similarity threshold (0–1)
EDGE_TTS_VOICE en-US-AriaNeural Edge TTS voice
EDGE_TTS_RATE +7% Speech rate
EDGE_TTS_PITCH -3Hz Speech pitch
EDGE_TTS_VOLUME +0% Speech volume
WHISPER_MODEL base Whisper model name
WHISPER_DEVICE cpu Whisper device. Keep cpu on Python 3.14 to avoid CUDA/Triton word-timestamp failures
SHORTS_OUTPUT_DIR outputs Rendered video and metadata directory
SHORTS_TEMP_ROOT /tmp/shorts_core Temporary media directory
CAPTION_FONT_PATH auto-detected Path to a scalable .ttf or .otf font
CAPTION_FONT_SIZE 220 Caption font size
BACKGROUND_MUSIC_PATH blank Optional local music file
BACKGROUND_MUSIC_VOLUME 0.12 Music volume multiplier

YouTube upload keys:

Variable Default Purpose
YOUTUBE_UPLOAD_ENABLED false Upload after rendering when true
YOUTUBE_CLIENT_SECRETS_FILE client_secrets.json OAuth client secrets file
YOUTUBE_TOKEN_FILE .youtube_token.json Stored OAuth token
YOUTUBE_PRIVACY_STATUS private private, unlisted, or public
YOUTUBE_CATEGORY_ID 22 YouTube category ID

Usage

Generate a video:

python3 shorts_core.py --topic "Why your 8-hour workday is failing"

Choose an output file:

python3 shorts_core.py --topic "The hidden cost of context switching" --output outputs/context-switching.mp4

Keep temporary media for debugging:

python3 shorts_core.py --topic "How cities became louder" --keep-temp

Use background music for one run:

python3 shorts_core.py --topic "Why old malls feel strange" --music ost.mp3 --music-volume 0.12

Upload after rendering:

python3 shorts_core.py --topic "Why your 8-hour workday is failing" --upload

If you omit --topic, the script prompts for a topic and optional output file.

Generated Titles

The YouTube title is not the raw topic. Gemini rewrites the topic into a shorter, more engaging title and stores it in script_payload.title inside the metadata file. Upload uses that generated title when metadata is present.

Example:

Topic: The '8-hour workday' is actually a scam designed for the 1800s, and it is destroying your productivity.
Generated title: Why Your 8-Hour Workday Is Failing

If a generated title is missing, SlopEngine falls back to the normalized topic and caps it at YouTube's 100-character limit without adding ellipses.

YouTube Upload

To upload, create an OAuth desktop client in Google Cloud and save the downloaded secrets JSON as client_secrets.json, or point YOUTUBE_CLIENT_SECRETS_FILE at the file.

On the first upload, the script opens a local OAuth flow and writes .youtube_token.json. Later uploads reuse that token when possible.

If Google rejects a saved refresh token with invalid_grant, the uploader opens the browser sign-in flow again and saves the replacement credentials after sign-in succeeds. Other refresh failures are left for retry. External OAuth apps in Testing status issue refresh tokens that expire after seven days for YouTube upload scopes.

Upload metadata is merged into the rendered video's .metadata.json file:

{
  "youtube": {
    "video_id": "example-id",
    "url": "https://www.youtube.com/watch?v=example-id"
  }
}

Project Layout

Path Purpose
shorts_core.py Main pipeline, CLI, rendering, and upload code
requirements.txt Python dependencies
.env.example Safe config template
tests/ Unit tests
outputs/ Rendered videos and metadata

Verification

Run the project checks after Python changes:

python3 -m unittest discover
python3 -m py_compile shorts_core.py
python3 -m compileall -q slopengine tests

The suite includes Textual Pilot keyboard/form workflows, mocked pipeline stages, worker completion/failure, real process cancellation, settings, library handling, and the existing CLI tests. It requires no provider credentials or rendering.

For caption or visual changes, render a short sample and inspect at least one frame or preview video.

Troubleshooting

  • No module named textual: install requirements in the same Python environment used to launch python -m slopengine.
  • Failed worker or missing engine: inspect Monitor or Logs, install requirements.txt, and check FFmpeg. A failed generation leaves the application usable.
  • Invalid configuration: check the Settings validation message and numeric values in .env. Changing credentials in .env takes effect after restarting the app; exported environment variables take precedence.
  • Whisper device failures: choose cpu in Create or Settings. CUDA availability is checked by the actual engine in the worker; the dashboard never loads Torch to probe the GPU.
  • An upload failure leaves the completed video in Library. Check OAuth client configuration, browser access, and privacy settings before trying another explicitly consented upload.
  • Edge TTS WSServerHandshakeError: 403: versions through 7.2.8 use an outdated service handshake. Upgrade in the same environment that runs the script: rtk proxy .venv312/bin/python -m pip install --upgrade 'edge-tts>=7.3.1' (replace the interpreter path if you use a different environment).
  • GEMINI_API_KEY is required or PEXELS_API_KEY is required: set the missing key in .env.
  • Gemini generate_content exceeded ... seconds: increase GEMINI_TIMEOUT_SECONDS in .env or retry later if Gemini is slow.
  • Gemini high-demand warning: the script retries with another available generateContent model when possible.
  • YouTube dependency error: install the packages in requirements.txt; upload needs google-api-python-client, google-auth-oauthlib, and google-auth-httplib2.
  • Whisper CUDA or Triton timestamp errors on Python 3.14: use the Python 3.12 CUDA setup above, or set WHISPER_DEVICE=cpu.
  • Captions render with the wrong font: set CAPTION_FONT_PATH to a real scalable font file.

Persistent generation queue

The TUI Queue tab (Ctrl+7) accepts individual and bulk jobs while generation is running. Queue state survives restarts, and interrupted or restored jobs require explicit recovery; they do not resume automatically. Independent workers, logs, outputs, stage admission and RAM reservations isolate jobs. The app must stay open to advance queued work.

SlopEngine persistent generation queue

See concurrent generation for controls, memory configuration, recovery and limitations, and the opt-in paired rendering benchmark. Two simultaneous production renders remain unverified; keep the default render limit of one.

About

Generate vertical short-form videos from a topic using Gemini, Edge TTS, Whisper captions, Pexels backgrounds, and MoviePy rendering.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages