fix(url): route URL-keyed hosts to markitdown and upgrade the transcript API - #131
Open
lufzle wants to merge 1 commit into
Open
fix(url): route URL-keyed hosts to markitdown and upgrade the transcript API#131lufzle wants to merge 1 commit into
lufzle wants to merge 1 commit into
Conversation
youtube-to-markdown returns the YouTube page footer instead of a transcript. Two independent causes, both needed for a fix. 1. URL routing. Every URL tool downloads the page to a temp .html file and passes that path to markitdown. markitdown's YouTubeConverter and BingSerpConverter match on stream_info.url, which is unset for a local file, so accepts() returns false and the generic HTML converter runs. Fixed with an allowlist rather than passing every URL through, because markitdown fetches with requests' default User-Agent and some hosts reject it: en.wikipedia.org and stackoverflow.com answer 403 to markitdown but 200 to this server's fetch. A blanket passthrough turns Wikipedia's working 63 KB of output into a hard 403. The allowlist covers the two hosts whose converters actually key off the URL and leaves every other host on the existing download path. safeFetch now returns the post-redirect URL so youtu.be and m.youtube.com normalize into the www.youtube.com/watch?v= form the converter accepts. Per-hop SSRF validation is unchanged, and redirect bodies are cancelled rather than left dangling. 2. Transcript library. markitdown pins youtube-transcript-api~=1.0.0, and 1.0.x no longer parses YouTube's current responses: it raises ParseError, which markitdown swallows, emitting the page with no transcript. Routing alone does not fix this, verified on a clean venv. setup.sh and setup.bat now upgrade it in a second step, since installing both constraints at once fails with ResolutionImpossible. pip check reports no broken requirements afterwards. Verified end to end: canonical and youtu.be YouTube URLs return the transcript, Bing returns parsed results instead of localized SERP chrome, and Wikipedia, StackOverflow and generic pages are unchanged. bun test 95/95. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The bug
youtube-to-markdownreturns the YouTube page footer instead of a transcript:There are two independent causes. Fixing either one alone leaves the tool broken, which I think is why this has been reported more than once.
Cause 1: URL routing
All three URL tools download the page to a temp
.htmlfile and pass that path to markitdown. ButYouTubeConverter.accepts()andBingSerpConverter.accepts()match onstream_info.url, which is unset for a local file:So
accepts()returnsFalse, the generic HTML converter runs, and you get page chrome. Same for Bing, which returns localized SERP boilerplate instead of parsed results.Cause 2: markitdown's transcript pin
markitdown requires
youtube-transcript-api~=1.0.0, and 1.0.x no longer parses YouTube's current transcript responses:markitdown swallows that and emits the page without a transcript. Verified on a clean venv built by the current
setup.sh: fixing the routing alone still yields no transcript. 1.2.4 parses correctly.The fix
Routing (
src/utils.ts,src/Markdownify.ts) — an allowlist of hosts whose markitdown converters key off the URL, checked after redirect resolution. Everything else keeps the existing download path.Why an allowlist rather than passing every URL through (which is what #100 and #106 do): markitdown fetches with
requests' default User-Agent, and some hosts reject it while accepting this server'sfetch.en.wikipedia.org/wiki/Markdownstackoverflow.com/questions/tagged/pythonWikipedia is the sharp case: markitdown ships a
WikipediaConverter, but it can never run on a live fetch, so a blanket passthrough trades working output for a hard 403. Confirmed by running both paths side by side.safeFetchnow returns the post-redirect URL alongside the response, soyoutu.beandm.youtube.comlinks normalize into thewww.youtube.com/watch?v=form the converter requires (youtu.be/ID→303→www.youtube.com/watch?v=ID&feature=youtu.be). Per-hop SSRF validation from #80 is unchanged; redirect and unused response bodies are now cancelled rather than left dangling.Host matching is exact rather than suffix-based, so
www.youtube.com.evil.testandevil-www.youtube.comdo not match, and non-httpsis rejected.Dependency (
setup.sh,setup.bat) — upgradeyoutube-transcript-apiin a second step. It has to be two steps: installing both constraints at once fails withResolutionImpossibleagainst markitdown's~=1.0.0. Afterwardspip checkreportsNo broken requirements found.Verification
bun test— 95/95 pass (79 existing + 16 new).bun run buildandtsc --noEmitclean.End to end through the MCP protocol:
youtube-to-markdowncanonical URLyoutube-to-markdownyoutu.beshort linkbing-search-to-markdownwebpage-to-markdownWikipediawebpage-to-markdownStackOverflowwebpage-to-markdownexample.comNew tests cover the allowlist boundaries (canonical/extra-params/no-video-id/non-watch paths, Bing search vs non-search, lookalike hosts, http, malformed URLs, Wikipedia staying off the list), that a YouTube URL reaches
_markitdownas a URL, that ayoutu.beredirect resolves first, that non-allowlisted URLs still go to a temp file, and that a redirect to a private IP is still rejected.Relation to #100 and #106
Both propose the routing half via a blanket passthrough. That fixes YouTube but regresses Wikipedia and StackOverflow to 403, and neither addresses cause 2, so
youtube-to-markdownstill returns no transcript on a freshly built venv. Happy to fold this into either if you'd prefer one of those as the base. Likely also fixes #33, and #34's 1.2 MBmaxBufferblowup goes away since the watch page is no longer piped through stdout.Notes
pyproject.toml/uv.lockleft alone deliberately: the lock is already stale (pins markitdown 0.1.5, no[all]extras, no transcript dep) and nothing in the repo invokesuv, sosetup.shis the real install path. Happy to add the override there too if you want the lock refreshed.🤖 Generated with Claude Code