feat(#5): play YouTube/yt-dlp URLs and playlists, rebased on new pipeline

Pass any yt-dlp-supported URL where a video file goes. A single video is
downloaded (<=480p, ASCILINE only needs a tiny grid), normalized to
H.264/AAC/CFR mp4, and cached in videos/ by id so replays and --loop are
instant. A playlist/channel URL expands into one queue entry per video,
each fetched lazily as it plays so a long playlist starts immediately.

Also fixes the playlist.json eager-download bug Yusuf reported: URL entries
in a JSON playlist are now left unresolved by load_playlist and fetched
on demand by the playback loop, instead of synchronously downloading every
link before the server starts.

Ported onto the new thread-pool/zero-copy main; all integration points
(resolve_video_path, load_playlist, build_queue, websocket loop) updated.
This commit is contained in:
Nate 2026-06-19 14:16:46 -04:00
parent 51efdaf39f
commit bfbf94637b
6 changed files with 615 additions and 4 deletions

View file

@ -91,6 +91,13 @@ cd ASCILINE
```bash
pip install fastapi uvicorn opencv-python numpy websockets
```
**Optional — play from YouTube (and other yt-dlp sites):**
```bash
pip install yt-dlp
```
Only needed if you pass a URL instead of a local file. Local playback works
without it. URL playback also uses FFmpeg (see below) to normalize downloads.
### 🔈 Audio Support (FFmpeg Required)
To enable server-side audio processing (Volume 1-5), you must have FFmpeg installed.
@ -111,6 +118,19 @@ If you get a `FileNotFoundError` or don't want to modify system variables:
python stream_server.py video.mp4 --cols 240
```
**YouTube / URL (requires `yt-dlp`):** pass any yt-dlp-supported URL in place of a file.
```bash
python stream_server.py "https://youtu.be/VIDEO_ID" --cols 240
python stream_server.py "https://www.youtube.com/playlist?list=..." --cols 220 --loop
```
A single video is downloaded (≤480p — ASCILINE only needs a tiny grid) and cached
in `videos/` by id, so replays are instant. A playlist/channel URL expands into one
queue entry per video, each fetched on demand as it plays. A `playlist.json` may
also list URLs; those are fetched lazily too, so the server starts immediately
instead of downloading the whole list up front. Every download is normalized to a
standard H.264/AAC/constant-frame-rate mp4 so playback and audio stay reliable
regardless of the source codec.
**Folder mode — drop your videos into `videos/` and run:**
```bash
python stream_server.py --folder videos --cols 200