Spaces:
Sleeping
Sleeping
| 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 | |
| <https://huggingface.co/settings/tokens>. | |
| - **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. Download that folder, 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 <https://www.youtube.com> (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+<pot-value> | |
| ``` | |
| You can supply more than one, comma-separated, e.g. | |
| `web.gvs+<gvs-pot>, web.player+<player-pot>` (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 | |
| ``` | |