Skip to content

DeliverVideo: accept a yt-dlp-compatible URL as well as a file - #84

Draft
magent-cryptograss wants to merge 1 commit into
cryptograss:productionfrom
magent-cryptograss:ytdlp-url
Draft

DeliverVideo: accept a yt-dlp-compatible URL as well as a file#84
magent-cryptograss wants to merge 1 commit into
cryptograss:productionfrom
magent-cryptograss:ytdlp-url

Conversation

@magent-cryptograss

@magent-cryptograss magent-cryptograss commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Adds a "Fetch from a URL" field beside the dropzone on Special:DeliverVideo. delivery-kid runs yt-dlp against the URL and lands the result in the same draft the dropzone would have produced — nothing downstream (ReleaseDraft page, review, metadata, AV1 HLS on finalize) can tell the two apart.

Depends on cryptograss/maybelle-config#98, which adds POST /draft-content/from-url. Merge that first; this is inert without it.

Flow

Identical to the file path through the first two steps — /init mints a draft_id, the stub ReleaseDraft page is written before any bytes move — and only then does the URL go over.

What differs is the middle. delivery-kid answers 202 and works detached, so instead of watching XHR upload progress the client polls GET /draft-content/{id} and reads status + upload_log until it reads uploaded or upload_failed. The bytes never touch the user's device, so there's no upload progress to measure locally; the bar is driven by the percentages in yt-dlp's own output, which the server logs one per decile.

Decisions

  • File and URL are mutually exclusive, enforced in the UI. Both at once leaves it ambiguous which one the Release is of.
  • Title stays required for a file upload, optional for a URL — we fall back to the title the source already carries, same for description. Anything the user typed always wins; these only fill blanks.
  • Polling survives network blips rather than abandoning a long fetch. A ceiling just past delivery-kid's own timeout decides when to stop.
  • parseDkError() split into a text-taking form so the fetch path and the existing XHR path share one error parser.

Testing

  • PHP lints clean (8.2), JS passes node --check.
  • CSS verified by rendering the markup standalone — the or divider, field widths (needed input[type="url"] added to the width rule), progress bar, and the monospace fetch-log box all render as intended.

Not yet verified: the page has not been rendered inside an actual wiki. The only running instance on hunter serves Justin's checkout read-only and I'm not writing into that. Worth a look on a scratch instance before this comes out of draft.

Known gap — YouTube

YouTube currently fails from a datacenter IP with Sign in to confirm you're not a bot. Instagram and generic media URLs work today (verified end to end against a live 48MB Instagram video). A cookie story for YouTube is unresolved and deliberately out of scope here.

https://claude.ai/code/session_015YGcYQ1UzPuNAxQhHTcCz6

Adds a "Fetch from a URL" field beside the dropzone. delivery-kid runs
yt-dlp against the URL and lands the result in the same draft the
dropzone would have produced, so nothing downstream — ReleaseDraft page,
review, metadata, AV1 HLS on finalize — can tell the two apart.

Musicians keep asking to get video that's already on a hosting service
into a Release without first pulling it down to a laptop and pushing it
back up. The whole flow already existed; the only thing it couldn't do
was take a URL.

Requires POST /draft-content/from-url, added in maybelle-config#98.

Flow is deliberately the same as the file path through the first two
steps: /init mints a draft_id, the stub ReleaseDraft page is written
before any bytes move, and only then does the URL go over. What differs
is the middle — delivery-kid answers 202 and works detached, so instead
of watching XHR upload progress the client polls GET /draft-content/{id}
and reads status + upload_log until it reads uploaded or upload_failed.
The bytes never touch the user's device, so there is no upload progress
to measure; the bar is driven by the percentages in yt-dlp's own output,
which the server logs one per decile.

Details worth knowing:

- File and URL are mutually exclusive, enforced in the UI. Both at once
  leaves it ambiguous which one the Release is of.
- Title stays required for a file upload but is optional for a URL,
  where we fall back to the title the source already carries. Same for
  description. Anything the user typed always wins — these only fill
  blanks.
- Polling survives network blips rather than abandoning a long fetch;
  a ceiling just past delivery-kid's own timeout decides when to stop.
- parseDkError() split into a text-taking form so the fetch path and the
  XHR path share one error parser.

CSS verified by rendering the markup standalone. The page itself has not
been rendered inside a wiki — the only running instance here serves
Justin's checkout read-only, and I'm not writing into that.

Claude-Session: https://claude.ai/code/session_015YGcYQ1UzPuNAxQhHTcCz6
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.

1 participant