Preserve masked secrets on settings save, tolerate malformed background add requests, escape background catalog values, and skip terminal clearing when TERM is unset.
Tested: rtk docker compose run --rm test
Replace eval() with safe type-coercion dicts in console/settings/gui_utils.
Replace os.system() with subprocess.run() in TTS engine_wrapper.
Remove shell=True from all subprocess/Popen calls in main + ffmpeg_install.
Redact credentials from error logs and settings page HTML.
Fix 6 bare except clauses across the codebase.
Bug fixes:
- Config overwrite crash: set config={} after writing empty file
- Playwright TimeoutError: import correct exception class
- Lambda closure: default arg captures loop variable value
- Redundant ffmpeg: single concat run after all segments generated
- Audio IndexError: explicit check before accessing clips_durations[0]
- NSFW selector: use generic role-based button instead of hardcoded post ID
- Dead macOS branch: sys.platform == "darwin" instead of os.name == "mac"
Hardening:
- Flask secret_key from env var, rotate per startup
- Docker non-root user (appuser)
- CSRF check via Origin header on mutating requests
- Security headers: X-Content-Type-Options, X-Frame-Options
- Citation path traversal sanitization
- Temp file cleanup in ProgressFfmpeg.__exit__
Co-Authored-By: RuFlo <ruv@ruv.net>
Add keywords input to Create page to override search_queries per run.
Split /create into two panels: left controls + progress, right
real-time scraper activity feed with stage diagram and typed event
cards. Emit structured events from scraper and auth modules. Add
blocked_words fields to Settings page Content tab.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Web scraper (platforms/threads/scraper.py) with div-based card parsing
- Multi-source discovery: For You feed + configurable search queries
- Engagement filtering (min_engagement) and post age filter (max_post_age)
- Shared Playwright auth module (platforms/threads/auth.py)
- Migrated ffmpeg-python to av (PyAV) for in-process media probing
- Video composition uses subprocess ffmpeg (av filter graph segfault workaround)
- Updated CLAUDE.md with Threads scraping and macOS-specific notes
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Build one shared container image for the Flask GUI and CLI pipeline, with Playwright, FFmpeg, and spaCy preinstalled so first runs are reliable. Add bootstrap logic for missing runtime files, bind the GUI to 0.0.0.0 in containers, and preserve state through a repo mount.
Constraint: Local development needs a single image that supports both entrypoints without introducing extra services or dependencies.
Rejected: Separate GUI and CLI images | duplicated maintenance and no runtime benefit for this repo.
Confidence: high
Scope-risk: moderate
Directive: Keep runtime state creation in the container bootstrap layer; do not reintroduce host-specific assumptions into GUI startup.
Tested: docker compose build; docker compose run --rm gui python -c '...'; docker compose run --rm cli python -c 'import main'; docker compose up -d gui; curl -I http://localhost:4000
Not-tested: Full end-to-end video generation with live credentials in this environment.
## Summary
Implements multi-platform support for VideoMakerBot, starting with Meta Threads as a new content source alongside Reddit. Uses a platform-agnostic factory pattern to route content fetching and screenshot capture.
## Changes
### New Files
- platforms/__init__.py: Factory dispatch for platform selection
- platforms/threads/__init__.py: Threads package marker
- platforms/threads/fetcher.py: Threads Graph API integration
- platforms/threads/screenshot.py: Playwright-based Threads screenshotter
- CLAUDE.md: Comprehensive development guide
- AGENT.md: Guidelines for AI agents working on the codebase
### Modified Files
- main.py: Updated to use platform factory instead of direct Reddit imports
- utils/.config.template.toml: Added [settings].platform, [settings].post_lang, [threads.*] sections
- utils/videos.py: Added check_done_by_id() function, guarded praw import with TYPE_CHECKING
- reddit/subreddit.py: Added thread_category field to content dict
- TTS/engine_wrapper.py: Fixed post_lang to use fallback chain
- video_creation/final_video.py: Fixed post_lang fallback + thread_category-based output naming
- requirements.txt: Fixed yt-dlp version to 2025.10.14
## Architecture
- Platform-agnostic data contract: content_object dict with standard keys
- Factory pattern in platforms/__init__.py routes to correct fetcher/screenshotter
- All platforms return same dict shape for seamless pipeline integration
- Minimal changes to existing Reddit code; purely additive design
## Testing
- Reddit mode tested and verified to maintain backward compatibility
- Threads mode functional with Graph API and Playwright screenshot capture
- Both platforms route output to platform-specific folders (results/{subreddit}/ vs results/threads/)
## Future
Adding X/Twitter or other platforms requires only:
1. New platform module (fetcher + screenshot)
2. Config section in .config.template.toml
3. Two elif branches in platforms/__init__.py
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>