{"id":48542205,"url":"https://github.com/gnh1201/dnt-yt","last_synced_at":"2026-04-08T05:02:44.758Z","repository":{"id":330993738,"uuid":"1124773332","full_name":"gnh1201/dnt-yt","owner":"gnh1201","description":"DNT-YT is a lightweight YouTube caching + offline browsing API.","archived":false,"fork":false,"pushed_at":"2026-02-06T07:09:01.000Z","size":1263,"stargazers_count":14,"open_issues_count":0,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-05T11:22:41.368Z","etag":null,"topics":["alternative-frontends","audio","cache","caching","fastapi","music","offline","offline-browsing","redis","video","youtube","youtube-dl","youtube-dl-wrapper","yt-dlp"],"latest_commit_sha":null,"homepage":"https://dnt-yt.catswords.net/wLp_c3M-nPA","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gnh1201.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-12-29T15:36:41.000Z","updated_at":"2026-02-20T03:00:36.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/gnh1201/dnt-yt","commit_stats":null,"previous_names":["gnh1201/dnt-yt"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/gnh1201/dnt-yt","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gnh1201%2Fdnt-yt","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gnh1201%2Fdnt-yt/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gnh1201%2Fdnt-yt/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gnh1201%2Fdnt-yt/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gnh1201","download_url":"https://codeload.github.com/gnh1201/dnt-yt/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gnh1201%2Fdnt-yt/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31540828,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-07T16:28:08.000Z","status":"online","status_checked_at":"2026-04-08T02:00:06.127Z","response_time":54,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["alternative-frontends","audio","cache","caching","fastapi","music","offline","offline-browsing","redis","video","youtube","youtube-dl","youtube-dl-wrapper","yt-dlp"],"created_at":"2026-04-08T05:02:32.084Z","updated_at":"2026-04-08T05:02:44.740Z","avatar_url":"https://github.com/gnh1201.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# DNT-YT\n\n[![Discord chat](https://img.shields.io/discord/359930650330923008?logo=discord)](https://discord.gg/sZPCYDGWGM?utm_source=gnh1201)\n\nDNT-YT (Do-Not-Track YouTube) is a lightweight YouTube caching + offline browsing API.\n\n![DNT-YT structure overview](app/static/overview.png)\n\nInspired by [**Piped**](https://github.com/TeamPiped/Piped?utm_source=gnh1201) and [**Invidious**](https://github.com/iv-org/invidious?utm_source=gnh1201). However, their goals and typical use-cases differ from what I need, so I created **DNT-YT**.\n\n**DNT-YT prioritizes offline YouTube video exploration above everything else.** In fact, this is the only purpose of the source code in this repository.\n\n## What it does\n\n* Accepts various YouTube URL formats (or a raw `video_id`)\n* Automatically requests caching when missing\n* Stores cached media (video/audio, thumbnail and subtitles) and serves them as browser-playable URLs\n* Serves an HTML watch page that:\n\n  * polls cache status every 5 seconds when not ready\n  * auto-plays video (muted) once ready\n  * uses a **Mute/Unmute toggle** as the user gesture to enable audio\n  * keeps A/V synchronized in the browser (no FFmpeg)\n  * supports thumbnails and multilingual subtitles\n\n## Architecture\n\n* **API**: FastAPI\n* **Queue**: RQ\n* **Storage/State**: Redis (jobs/status) + local media volume\n* **Downloader**: yt-dlp (caching audio/video separately; no FFmpeg required)\n\n## Endpoints\n\n### Watch (HTML)\n\nThese routes render the HTML player page.\nIf the cache is missing, the server should enqueue a caching job automatically, then the page waits/polls until the cache becomes ready.\n\n#### 1) Root `/\u003cvideo_id\u003e`\n\n```text\n/wLp_c3M-nPA\n```\n\n#### 2) Path-based watch\n\n```text\n/watch/wLp_c3M-nPA\n```\n\n#### 3) Query `v=\u003cvideo_id\u003e` (YouTube-like)\n\n```text\n/watch?v=wLp_c3M-nPA\n```\n\n#### 4) Query `url=\u003cfull-youtube-url\u003e`\n\n```text\n/watch?url=https://www.youtube.com/watch?v=wLp_c3M-nPA\n```\n\n### API (JSON)\n\n#### Request caching / play intent\n\nQueues a cache job if missing.\n\n```text\nGET /v1/yt/play?url=\u003cyoutube_url\u003e\n```\n\nExample:\n\n```bash\ncurl \"http://localhost:58000/v1/yt/play?url=https://www.youtube.com/watch?v=wLp_c3M-nPA\"\n```\n\nTypical response:\n\n```json\n{\n  \"ok\": true,\n  \"ready\": false,\n  \"video_id\": \"wLp_c3M-nPA\",\n  \"job_id\": \"...\"\n}\n```\n\n#### Cache status\n\nReturns whether cache is ready and (when ready) URLs for cached media.\n\n```text\nGET /v1/yt/status?video_id=\u003cvideo_id\u003e\n```\n\nExample:\n\n```bash\ncurl \"http://localhost:58000/v1/yt/status?video_id=wLp_c3M-nPA\"\n```\n\nTypical response:\n\n```json\n{\n  \"ok\": true,\n  \"ready\": true,\n  \"video_id\": \"wLp_c3M-nPA\",\n  \"video_url\": \"/media/wLp_c3M-nPA/video\",\n  \"audio_url\": \"/media/wLp_c3M-nPA/audio\",\n}\n```\n\n### Media (cached files)\n\nThese URLs are browser-playable once caching completes.\n\n```text\nGET /media/\u003cvideo_id\u003e/video\nGET /media/\u003cvideo_id\u003e/audio\nGET /media/\u003cvideo_id\u003e/thumbnail  # thumbnail image\nGET /media/\u003cvideo_id\u003e/subtitles  # the list of all subtitles\nGET /media/\u003cvideo_id\u003e/subtitles/\u003clang\u003e  # subtitles (vtt format)\n```\n\nExample:\n\n```text\n/media/wLp_c3M-nPA/video\n/media/wLp_c3M-nPA/audio\n/media/wLp_c3M-nPA/thumbnail  # thumbnail image\n/media/wLp_c3M-nPA/subtitles  # the list of all subtitles\n/media/wLp_c3M-nPA/subtitles/en  # subtitles (vtt format)\n```\n\n## Content negotiation (HTML vs JSON)\n\nDNT-YT can decide response format based on request headers. Typical behavior:\n\n* If the client requests `text/html`, return the watch page\n* If the client requests `application/json`, return JSON (status or play response)\n* (Optional) `oEmbed` / OpenGraph can be added for social previews\n\n## Playback model (no FFmpeg)\n\nDNT-YT downloads **audio and video separately** using yt-dlp and serves them as separate files.\n\nThe watch page:\n\n* starts video playback automatically (usually requires `muted` for autoplay)\n* uses a **Mute/Unmute toggle** button as the explicit user action to enable audio reliably\n* keeps audio aligned to video time (periodic drift correction and seek sync)\n\nThis avoids any server-side muxing/merging and therefore avoids FFmpeg.\n\n## Dependencies\n\n* **yt-dlp** (required)\n* Redis\n* FastAPI / Uvicorn\n* RQ\n\n## Quick start (Docker)\n\nTypical:\n\n```bash\ndocker compose up --build\n```\n\nThen open:\n\n* Watch page: `http://localhost:58000/wLp_c3M-nPA`\n* API: `http://localhost:58000/v1/yt/play?url=...`\n\n## Goals / non-goals\n\n**Goals**\n\n* Offline-first YouTube exploration\n* Simple caching API\n* Browser-playable cached URLs\n* Minimal server-side processing (no FFmpeg)\n\n**Non-goals**\n\n* Full UI like a Piped or Invidious\n* Account features / subscriptions / comments\n* Complex transcoding pipelines\n\n## CDN Cache Rules\nFor scenarios where a CDN is used for **long-distance data transfer**, it is recommended to configure appropriate cache rules to reduce bandwidth usage and improve performance.\n\nThe following example shows a cache rule configuration based on [Cloudflare](https://www.cloudflare.com/?utm_source=gnh1201):\n\n```text\n(http.request.full_uri wildcard r\"https://domain.tld/media/*/video\")\nor\n(http.request.full_uri wildcard r\"https://domain.tld/media/*/audio\")\nor\n(http.request.full_uri wildcard r\"https://domain.tld/media/*/thumbnail\")\n```\n\n## Use cases\n* [Preventing YouTube Tracking Links on ActivityPub Servers](https://github.com/gnh1201/activitypub/blob/main/youtube.md?utm_source=gnh1201)\n\n## Screenshots\n![DNT-YT screenshot](app/static/screenshot.png)\n\n## My test videos\n* https://dnt-yt.catswords.net/wLp_c3M-nPA (SKC VHS Visual Doctor)\n* https://dnt-yt.catswords.net/kvAfmYNtugQ (Dolby Atmos Sample Video)\n* https://dnt-yt.catswords.net/mkggXE5e2yk (LG TV Sample Video)\n\n## Disclaimer\nThis software is licensed under the **GNU General Public License v3.0** and is provided **without any warranty**, to the extent permitted by applicable law. See the GPL v3.0 license for details.\n\nThe authors and contributors shall not be held liable for any damages arising from the use of this software. Any illegal or unauthorized use is solely the responsibility of the user, who must ensure compliance with all applicable laws and regulations.\n\n## Join the community\nI am always open. Collaboration, opportunities, and community activities are all welcome.\n\n* ActivityPub [@catswords_oss@catswords.social](https://catswords.social/@catswords_oss?utm_source=gnh1201)\n* XMPP [catswords@conference.omemo.id](xmpp:catswords@conference.omemo.id?join)\n* [Join Catswords OSS on Microsoft Teams (teams.live.com)](https://teams.live.com/l/community/FEACHncAhq8ldnojAI?utm_source=gnh1201)\n* [Join Catswords OSS #dnt-yt on Discord (discord.gg)](https://discord.gg/sZPCYDGWGM?utm_source=gnh1201)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgnh1201%2Fdnt-yt","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgnh1201%2Fdnt-yt","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgnh1201%2Fdnt-yt/lists"}