#!/usr/bin/env bun /** * Find the NeetCode explanation video for every docs page that has none. * * A finished solution page ends with `## Explanation` holding one * `` — NeetCode's walkthrough of the problem. * `sync.ts` never writes that section (it owns only `## Solution`), so pages * accumulate without one. This script lists every numbered page lacking a * `` blob of a YouTube page, parsed. * YouTube intermittently answers 200 with a page that lacks the blob or cuts * it short, so a bad page is retried a few times before it is an error. */ async function initialData(url: string): Promise { let reason = ""; for (let attempt = 0; attempt < 3; attempt++) { if (attempt) await Bun.sleep(500 * attempt); const res = await fetch(url, { headers: HEADERS }); if (!res.ok) { reason = `status ${res.status}`; continue; } const html = await res.text(); // Slice rather than regex: the blob is ~1 MB, and a lazy `.*?` across it // is what made the first cut of this script fail at random. const open = html.search(/ytInitialData\s*=\s*\{/); const close = open === -1 ? -1 : html.indexOf("", open); if (close === -1) { reason = `no ytInitialData in ${html.length}-byte page`; continue; } try { return JSON.parse(html.slice(html.indexOf("{", open), close).replace(/;\s*$/, "")); } catch { reason = "truncated ytInitialData"; } } throw new Error(`GET ${url} -> ${reason}`); } /** Every videoRenderer in a channel search page, in the page's own order. */ async function channelSearch(channel: string, query: string): Promise { const url = `https://www.youtube.com/@${channel}/search?query=${encodeURIComponent(query)}`; const data = await initialData(url); const videos: Video[] = []; const walk = (node: unknown): void => { if (!node || typeof node !== "object") return; if ("videoRenderer" in node) { const v = node.videoRenderer; if (v && typeof v === "object" && "videoId" in v && typeof v.videoId === "string") { const runs = "title" in v && v.title && typeof v.title === "object" && "runs" in v.title ? v.title.runs : undefined; const title = Array.isArray(runs) ? runs.map((r) => (r && typeof r === "object" && "text" in r ? String(r.text) : "")).join("") : ""; videos.push({ id: v.videoId, title, channel }); } return; } for (const child of Object.values(node)) walk(child); }; walk(data); return videos; } /** The LC number a NeetCode title names (`… - Leetcode 226 - …`), if any. */ function titledNumber(title: string): number | undefined { const m = title.match(/\bleetcode\s*#?\s*(\d+)\b/i); return m ? Number(m[1]) : undefined; } async function findVideo(num: number): Promise