Skip to content

Promote manual-URL flow to primary path; Rust-only bootstrap - #5

Open
scrumlord8 wants to merge 18 commits into
pashpashpash:mainfrom
scrumlord8:main
Open

Promote manual-URL flow to primary path; Rust-only bootstrap#5
scrumlord8 wants to merge 18 commits into
pashpashpash:mainfrom
scrumlord8:main

Conversation

@scrumlord8

Copy link
Copy Markdown

Summary

Reshape the CLI around its working spine: given a sound URL and three clip URLs, produce three composed MP4s. Discovery via TikTok/X APIs stays available but is demoted to an opt-in experimental path, since the tokens are gated (TikTok Research) or paid ($200/mo X Basic).

What's new

  • Manual-URL path is now primary. scripts/build-clips-from-urls.sh imports sound + 3 clips, composes, and writes a provenance manifest to clips/. No tokens required.
  • GitHub Actions workflow (build-clips.yml) with a mode selector: urls (default) or discovery (opt-in, token-gated). Runnable from a phone.
  • Codespaces devcontainer bootstraps Rust + ffmpeg + standalone yt-dlp binary via capcut-cli deps install. No Python anywhere in the toolchain.
  • End-to-end smoke test (tests/<e2e_url_to_clip.rs>) exercises import → compose with a yt-dlp shim, so CI verifies the spine without network.
  • Committed demo fixtures (snd_demo001, clp_demo001) + top-level library/manifest.json so existing library-dependent tests pass out of the box.
  • Docs rewritten to match: README leads with the manual flow, discovery is a clearly-marked experimental section, Python references stripped.

Agent execution options

Three ways to run it, in order of friction:

  1. Local / Codespacesmake clips with URLs in env vars; full Rust toolchain, fastest iteration.
  2. GitHub Actions (urls mode) — fill in sound + 3 clip URLs, download artifacts. Works from a phone.
  3. GitHub Actions (discovery mode) — requires TIKTOK_RESEARCH_ACCESS_TOKEN and/or TWITTER_BEARER_TOKEN. Documented but unverified against live APIs.

Please focus review on

  • Whether promoting manual URLs over discovery matches your intended product direction
  • The yt-dlp shim contract in tests/<e2e_url_to_clip.rs> (is this the test seam you'd want?)
  • The CAPCUT_YTDLP_PATH env override in src/<config.rs> — small surface, test-only, but it is a prod code path
  • .gitignore whitelist pattern for committed demo fixtures
  • Any discovery-path docs you'd prefer kept front-and-center vs. moved to experimental

scrumlord8 and others added 18 commits April 9, 2026 00:38
Replace the Rust scaffold with a fully functional Python CLI that actually
does what the project promises. The full pipeline is operational:
- Discover trending TikTok sounds via Creative Center scraping
- Generate X/Twitter viral clip search queries with engagement filters
- Download sounds and clips from any yt-dlp-supported URL (TikTok, X, YouTube, etc.)
- Compose real MP4 videos with normalized audio, scaled/cropped clips, and muxing
- All commands output structured JSON for agent consumption

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
TikTok: API-first with layered HTML fallback (__NEXT_DATA__, script scan,
regex) so it survives SSR restructuring instead of breaking on a single
JSON path.

Twitter: execute live search via Twitter API v2 when TWITTER_BEARER_TOKEN
is set, fall back to guided discovery URLs with setup instructions.

Compose: add --loudness presets (viral -8, social -10, podcast -14,
broadcast -23 LUFS). Default changed from -14 to -8 because this tool
makes social media content, not podcasts.

https://claude.ai/code/session_019gPk1X2KQ5mw6z2QCUYStU
…apper

56 tests covering:
- TikTok: all 3 extraction strategies, normalize_sound field mapping, API
  fallback, limit enforcement
- Twitter: query building, API search with/without bearer token, min_likes
  filtering, guided fallback
- Loudness: preset values, ordering (viral > social > podcast), resolve
  with names/numeric values, error on unknown
- CLI: command structure, --loudness option presence
- FFmpeg: loudnorm filter param construction for all preset levels

https://claude.ai/code/session_019gPk1X2KQ5mw6z2QCUYStU
…se-i5LUV

Harden discovery modules and fix compose loudness for viral content
Complete Rust rewrite of the capcut-cli Python MVP. Every command now runs
natively — single binary, no Python runtime, no pip install.

Modules ported:
- config.rs: paths, loudness presets (viral/social/podcast/broadcast)
- output.rs: JSON envelope matching Python format exactly
- deps.rs: ffmpeg detection (PATH + ~/.capcut-cli/bin), yt-dlp binary download
- media/ffmpeg.rs: all 8 subprocess wrappers (normalize, trim, scale, crop,
  concat, mux, loop, get_duration)
- media/downloader.rs: yt-dlp wrapper with cookie retry on block detection
- media/compose.rs: full 5-step pipeline with loudness preset resolution
- discover/tiktok.rs: API-first + 3-strategy HTML fallback (scraper + regex)
- discover/twitter.rs: Twitter API v2 live search + guided fallback
- library.rs: asset CRUD with JSON manifest, import/list/show/delete
- cli.rs: clap subcommand tree matching Python's command structure exactly

CLI parity: deps check/install, discover tiktok-sounds/x-clips,
library import/list/show/delete, compose with --loudness.

6 unit tests passing. Zero warnings. Builds on Rust 1.94 edition 2024.

https://claude.ai/code/session_019gPk1X2KQ5mw6z2QCUYStU
The py/ directory (1,949 lines) was the original MVP. The Rust port
in src/ is a complete replacement with the same CLI interface and
JSON envelope format.

https://claude.ai/code/session_019gPk1X2KQ5mw6z2QCUYStU
…se-i5LUV

Claude/refactor discovery compose i5 luv

Ditched Python and went full Rust mode
Increases test count from 6 to 50. Covers:
- CLI argument parsing for all commands (deps, discover, library, compose)
- Clap validation: required args, defaults, error cases
- Asset/Manifest/ComposeResult JSON serialization and round-trips
- Output envelope structure (success/error, hint omission, duration)
- Platform detection (TikTok, YouTube, X/Twitter, Instagram, unknown)
- Asset type detection (explicit override, TikTok music auto-detect)
- File matching helper (found/not-found paths)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Rewrite capcut-cli in Rust and add agent-first discovery, import, and autopilot workflows
Two phone-friendly ways to run real discovery and produce three composed
MP4s alongside their source audio and clip assets:

- .github/workflows/build-clips.yml: manual-dispatch workflow that checks
  for API tokens, installs ffmpeg/yt-dlp, builds the CLI, runs discovery
  and compose via scripts/build-clips.sh, and uploads a clips/ artifact.
- .devcontainer/: Rust+Python devcontainer with a post-create step that
  wires yt-dlp into ~/.capcut-cli/bin and builds the release binary; pairs
  with `make clips` for one-command runs inside Codespaces.
- scripts/build-clips.sh: discovers one trending sound + three ranked X
  clips, imports each, composes clip_{1,2,3}.mp4, and stages the real
  source references plus a manifest.json under ./clips.
- README: documents both paths and the required repo/Codespace secrets.
The CLI is Rust-only; yt-dlp itself is distributed as a standalone Linux
binary by the upstream project, and 'deps install' already downloads it.
Using that path keeps Python off the install surface for both the Action
and the devcontainer.
Product decision: discovery depends on gated APIs (TikTok Research access,
X paid-tier search) whose availability we can't guarantee. Treat "fresh
input in, finished clip out" as the honest minimum viable truth and make
the compose pipeline the solid thing the tool does.

- README rewritten around the manual-URL flow. The Quick Start, batch
  guide, and command reference all center on library import + compose.
  The discover/autopilot commands are moved into an "Optional: API-gated
  discovery (experimental)" section with explicit caveats about token
  gating. Stale claims removed. Python references stripped.
- scripts/build-clips-from-urls.sh: primary batch path. Takes one
  supplied sound URL plus three supplied clip URLs and produces a
  self-contained clips/ folder with finished MP4s, source references,
  and a provenance manifest.
- .github/workflows/build-clips.yml: gains a mode selector; urls mode is
  the default, discovery mode is opt-in behind both repo secrets.
- tests/e2e_url_to_clip.rs: end-to-end smoke test that exercises the
  full library import → compose pipeline via a yt-dlp shim, so the
  honest minimum viable truth is verifiable without network access.
- .github/workflows/test.yml: runs cargo test --all-targets on every
  push so the spine stays provable in CI.
- library/manifest.json plus small synthetic demo fixtures under
  library/sounds/assets/snd_demo001 and library/clips/clp_demo001 so
  compose works immediately on a fresh clone and the compose smoke
  test has real bytes to exercise.
- src/config.rs: CAPCUT_YTDLP_PATH env override so tests can inject a
  yt-dlp shim. Production path unchanged.
- src/media/downloader.rs: merge two duplicate #[cfg(test)] mod tests
  blocks that were preventing cargo test from compiling at all.
- .gitignore: trimmed Python section, whitelisted the committed demo
  fixtures, anchored the batch-output ignore to the repo root.
- .env.example: reframe TWITTER_BEARER_TOKEN and TIKTOK_RESEARCH_ACCESS_TOKEN
  as optional (they only affect API-gated discovery, not the primary
  library import + compose flow). Note the pricing reality for the X
  token. Document the new CAPCUT_YTDLP_PATH test hook.
- library/sounds/README.md: reflect the actual directory layout
  (assets/ is where imports land), mark the nested manifest.json as a
  legacy seed, and point readers at the authoritative library/manifest.json.
- .devcontainer/post-create.sh: drop the Python mention from the header
  comment now that the bootstrap is entirely Rust-native.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants