Address PR #27 review:
- download() now parses the video id straight from the URL and returns a
cached file without calling _probe_remote(), so cached reruns no longer
hit YouTube on every startup. Unrecognized URLs fall through to the probe.
- expand_playlist() passes --yes-playlist so a watch?v=...&list=... URL
expands the full list instead of queuing a single video.
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.