Goal
A `forge publish` command that uploads rendered MP4s to a video host and records the mapping in the consumer repo, so help/marketing pages can embed stable links and CI can re-publish when tutorials change.
Design
- Provider interface (`PublishTarget`): upload(file, metadata) → { uri, embedUrl }, replace(uri, file), updateMetadata(uri, …), uploadCaptions(uri, srt, lang).
- Vimeo provider first. Vimeo's replace-file API keeps the same URL, review page, and stats, with version history — true "re-publish to the same link" (https://vimeo.zendesk.com/hc/en-us/articles/360000817648-Replace-a-video). Captions via the texttracks endpoint, per language.
- Mapping file `published.json` committed in the consumer repo: `{tutorialId, lang} → {provider, uri, embedUrl, contentHash, publishedAt, version}`. Publication state is part of "tutorials are source code" — reviewable in PRs.
- Idempotency: content-hash the MP4; unchanged videos skip upload, changed ones replace-in-place (Vimeo) or upload-new + unlist-old + update-mapping (providers without replace).
- Localized videos publish per language with their captions.
Provider notes
- Vimeo: replace-in-place ✓; requires requesting API upload access (light review); version-history depth varies by plan.
- YouTube (later, as a distribution channel): no file replacement ever (new upload = new ID); API uploads from unaudited projects are locked private (https://support.google.com/youtube/answer/7300965) — compliance audit required; videos.insert costs 1600/10000 daily quota units (~6 uploads/day default).
- Cloudflare Stream / Mux (maybe later): no in-place replace, but cheap/usage-based with full player control; the mapping file handles URL indirection.
Goal
A `forge publish` command that uploads rendered MP4s to a video host and records the mapping in the consumer repo, so help/marketing pages can embed stable links and CI can re-publish when tutorials change.
Design
Provider notes