What
Add a youtube.js adapter that turns a YouTube watch URL into read-only tools: get_video (title, channel, published date, duration, view count), get_description, and get_thumbnail.
Why it's valuable
From ADAPTERS_WANTED.md (Easy column): agents that summarize or queue content need video metadata. The approach is OpenGraph meta tags plus a parse of the ytInitialData blob embedded in the page — read-only, no auth, no cart.
Where to start
- Copy
adapters/_template → adapters/youtube.js, ID = "youtube" (see adapters/CONTRACT.md).
detect() (sync, no network): match youtube.com/watch?v=<id> and youtu.be/<id> (handle m.youtube.com too). Reject channel/playlist/shorts-listing pages if you only support watch pages in v1. Return { adapter: ID, videoId, url }.
extract(): prefer the meta already passed in ctx (the chain pre-parses OG/twitter meta — see detect input shape in CONTRACT.md and how jsonld.js reads ctx.meta). For view count/duration that aren't in OG, fetch the watch page with CHROME_UA + credentials: "omit" and parse the inline ytInitialData / ytInitialPlayerResponse JSON. Wrap parsing in try/catch and degrade gracefully to OG-only fields rather than throwing.
- Read-only adapter:
export const actions = {}.
- Add a fixture in
_fixtures/ (a watch page, trimmed under ~200KB per _fixtures/README.md) and a detect() + extract() test in _test/run.mjs. Run node adapters/_test/run.mjs. Register in worker/src/index.ts.
Acceptance criteria
What
Add a
youtube.jsadapter that turns a YouTube watch URL into read-only tools:get_video(title, channel, published date, duration, view count),get_description, andget_thumbnail.Why it's valuable
From
ADAPTERS_WANTED.md(Easy column): agents that summarize or queue content need video metadata. The approach is OpenGraph meta tags plus a parse of theytInitialDatablob embedded in the page — read-only, no auth, no cart.Where to start
adapters/_template→adapters/youtube.js,ID = "youtube"(seeadapters/CONTRACT.md).detect()(sync, no network): matchyoutube.com/watch?v=<id>andyoutu.be/<id>(handlem.youtube.comtoo). Reject channel/playlist/shorts-listing pages if you only support watch pages in v1. Return{ adapter: ID, videoId, url }.extract(): prefer themetaalready passed inctx(the chain pre-parses OG/twitter meta — seedetectinput shape in CONTRACT.md and howjsonld.jsreadsctx.meta). For view count/duration that aren't in OG, fetch the watch page withCHROME_UA+credentials: "omit"and parse the inlineytInitialData/ytInitialPlayerResponseJSON. Wrap parsing in try/catch and degrade gracefully to OG-only fields rather than throwing.export const actions = {}._fixtures/(a watch page, trimmed under ~200KB per_fixtures/README.md) and adetect()+extract()test in_test/run.mjs. Runnode adapters/_test/run.mjs. Register inworker/src/index.ts.Acceptance criteria
detect()matcheswatch?v=,youtu.be/,m.youtube.comand returnsnullfor non-video URLs.extract()returns{ product, variants: [], tools }with at leastget_videoandget_description.ytInitialDataparse fails (no hard crash on layout changes).node adapters/_test/run.mjspasses; registered inworker/src/index.ts.ADAPTERS_WANTED.md— read-only public metadata only.