--- title: TutorialMaker emoji: ๐Ÿ’ป colorFrom: indigo colorTo: purple sdk: gradio sdk_version: 6.19.0 python_version: '3.13' app_file: app.py pinned: false license: mit short_description: Make Tutorials from YouTube Videos --- # YouTube โ†’ Tutorial Post Generator Give a **topic** and your **Hugging Face token**, and this Space builds a downloadable **`.docx` tutorial** (text + AI-captioned screenshots) from the single best YouTube video on that topic. ## Pipeline 1. **Search** โ€” top 5 videos via the [`adarshajay/youtube-search`](https://huggingface.co/spaces/adarshajay/youtube-search) Space. 2. **Sentiment rank** โ€” fetch top comments per video with `yt-dlp` and score them with the BERT classifier [`OmarMedhat7/youtube-sentiment-analysis-model`](https://huggingface.co/OmarMedhat7/youtube-sentiment-analysis-model); the video with the highest positive share wins. 3. **Download** the winner with `yt-dlp` and extract audio with `ffmpeg`. 4. **Transcribe** locally with `faster-whisper` (segment timestamps). 5. **Candidate frames** are extracted densely from the video, then the **video is auto-deleted** โ€” only small JPEGs and the transcript remain. 6. **Tutorial text** โ€” `deepseek-ai/DeepSeek-V3` (HF Inference Providers, billed to your token) turns the transcript into an **answer-engine-optimized** post: an answer-first paragraph, H2 step headings, an FAQ, a meta description, a URL slug, and a last-updated/source citation. Optional **primary/secondary keyword** placement (primary ~3ร— + in title/slug/meta/intro/H2; each secondary once). 7. **Screenshot selection** โ€” a weighted indicator blends each step's LLM-suggested timestamp with Whisper's actual speech timing. 8. **Captions** โ€” a vision model (default `Qwen/Qwen2.5-VL-72B-Instruct`, billed to your token) captions each screenshot. 9. **Assemble** the `.docx` for download. ## Notes - **Your HF token is used only for the LLM and vision-model calls** and is billed to your account. Create a fine-grained token with *"Make calls to Inference Providers"* at . - **Free CPU tier:** Whisper runs on CPU, so transcription is slow โ€” keep videos short (default cap ~20 min). - **YouTube usually blocks the Space's datacenter IP.** Each visitor can supply their own access in the **"YouTube access โ€” cookies / proxy"** panel (used only for that run, then deleted): - **Cookies:** a `youtube.com` cookies.txt (Netscape format, raw or base64) exported from a **throwaway** Google account. - **Proxy:** a **residential** proxy URL. **Free *datacenter* proxies (e.g. Webshare's free tier) usually do *not* bypass YouTube's block** and have tight bandwidth caps. - An operator can set shared defaults via the `YT_COOKIES` / `YT_PROXY` Space secrets. - A hosted Space **cannot** open or read a visitor's browser โ€” auth must be supplied explicitly. ## PO token guide (free, no proxy) YouTube increasingly requires a **Proof-of-Origin (PO) token** to serve video from datacenter IPs. A matching **PO token + visitor data** pair can get the Space past the "Sign in to confirm you're not a bot" wall **without any proxy** โ€” and it's free. It's fiddly to extract by hand and the tokens expire (hours), so re-do this when downloads start failing. Paste the values into the app's **"YouTube access โ€” cookies / proxy"** panel: **PO token** field and **Visitor data** field. ### Easiest: the PO Token Grabber extension (one click) This repo ships a tiny Chrome/Edge extension in [`extension/`](extension/) that reads the PO token + visitor data for you. Grab it with the **โฌ‡๏ธ Download the PO Token Grabber extension (.zip)** button in the app's *YouTube access* panel (or from [`extension/`](extension/)), unzip it, and load it unpacked (`chrome://extensions` โ†’ Developer mode โ†’ Load unpacked). Open a YouTube video and press play, then click the extension **while on the YouTube tab** to capture the values. Open this Space in another tab and hit **โคต Fill the Space tab** to inject them straight into the fields below (or use the Copy buttons and paste). See [`extension/README.md`](extension/README.md). (It's unpublished/sideloaded and may need updates when YouTube changes; the manual steps below always work as a fallback.) ### Get them manually (web client, ~2 min) 1. Open a fresh **Incognito** window and go to (a throwaway logged-in account is fine; if you log in, also export that session's cookies). 2. Open **DevTools โ†’ Network** (F12), then **play any video**. 3. **Visitor data:** filter Network for `v1/player`, open the request to `youtubei/v1/player`, and in the **Request payload** copy `context.client.visitorData` (a string ending in `%3D%3D`). Paste it into the **Visitor data** field. 4. **PO token (gvs):** filter Network for `googlevideo.com`, open a `videoplayback` request, and copy the value of its **`pot`** query parameter. In the **PO token** field enter it prefixed with the client + context: ``` web.gvs+ ``` You can supply more than one, comma-separated, e.g. `web.gvs+, web.player+` (the player PO token comes from the `v1/player` request's response, field `...poToken`). 5. Run the Space. When a PO token is present it automatically uses the **web** player client so the token applies. **Tips** - The PO token is bound to the **visitor data** (and cookies) it was made with โ€” always submit them together, from the same session. - Prefer using the **same Incognito session** for cookies + visitor data + PO token. - Tokens are short-lived; refresh when you next get blocked. ### Automated / operator option yt-dlp can auto-generate PO tokens via the [`bgutil-ytdlp-pot-provider`](https://github.com/Brainicism/bgutil-ytdlp-pot-provider) plugin, but that needs a small provider server running alongside yt-dlp โ€” not bundled in this hosted Space. A self-hosting operator can run it and set shared defaults via the `YT_POT` / `YT_VISITOR_DATA` Space secrets. See the authoritative, up-to-date method in the [yt-dlp PO Token Guide](https://github.com/yt-dlp/yt-dlp/wiki/PO-Token-Guide). ## Local run ```bash pip install -r requirements.txt # needs ffmpeg on PATH python app.py ```