- Python 98.1%
- Dockerfile 1.9%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
|
All checks were successful
Build and Push / build-and-push (push) Successful in 2m51s
|
||
| .forgejo/workflows | ||
| yt2plex-poller | ||
| .env.example | ||
| .gitignore | ||
| CHANGELOG.md | ||
| docker-compose.build.yml | ||
| docker-compose.yml | ||
| README.md | ||
YTLive2PlexTV
Monitor YouTube livestreams and scheduled broadcasts in Plex Live TV/DVR through xTeVe.
What it does
- Discovers live and upcoming videos from each channel's YouTube Streams tab every five minutes. It makes no
search.listAPI calls. - Batches active/scheduled video IDs into
videos.listcalls for descriptions, thumbnails, and actual/scheduled start times. With up to 50 tracked videos and a five-minute interval, this is at most 288 metadata requests/day; idle channels without tracked events need none. - Keeps schedules in
/shared/state.jsonacross restarts and API failures. If metadata API access fails, yt-dlp supplies metadata where possible. API quota errors cause a one-hour backoff. - Writes escaped XMLTV atomically, uses UTC offsets correctly, and never treats publication time as a scheduled broadcast time. Plex converts UTC to the viewer's timezone.
- Keeps existing
yt1,yt2, etc. mappings on the first upgrade and remembers them when channels are reordered later. - Publishes stable stream URLs. At tune-in it resolves fresh YouTube URLs and remuxes video/audio into MPEG-TS with FFmpeg. H.264/AAC up to 1080p is preferred; lower quality is used if 1080p is unavailable. No upscaling or routine transcoding is performed.
- Reloads xTeVe/Plex when the guide changes instead of every poll. Failed reloads are retried.
Setup
Requires Docker Compose, Plex with Live TV/DVR access, and xTeVe's API enabled. The included xTeVe container uses host networking on Linux.
cp .env.example .env
# Edit .env with channel triplets and your own credentials.
docker compose pull yt2plex-poller
docker compose up -d
In xTeVe, use /shared/playlist.m3u and /shared/guide.xml, enable the API, and choose FFmpeg buffering. Map the channels once. In Plex, attach xTeVe at http://SERVER_IP:34400 and its XMLTV guide at http://SERVER_IP:34400/xmltv/xteve.xml.
The poller's stream port is bound to 127.0.0.1:8098, reachable by xTeVe on host networking. STREAM_BASE_URL must be reachable by the process running xTeVe's FFmpeg. If you change networking, adjust the binding and URL accordingly. Use XTEVE_URL=http://host.docker.internal:34400 in the bridged poller container; Compose adds the Linux host gateway. The default localhost inside that container would point to the poller itself.
Plex URL, token and DVR ID enable automatic guide refresh. Tokens are sent in headers and error logs omit credential-bearing URLs. Keep .env and data/ out of Git.
Configuration
| Variable | Default | Purpose |
|---|---|---|
YOUTUBE_CHANNELS |
required | ChannelID|Name|Icon triplets separated by pipes |
YOUTUBE_API_KEY |
optional | Rich batched video metadata; no search quota used |
POLL_INTERVAL |
300 | Seconds between discovery cycles, minimum 60 |
GUIDE_REFRESH_INTERVAL |
1800 | Refresh unchanged guide boundaries and fallback metadata |
DEFAULT_EVENT_HOURS |
3 | Estimated event duration if YouTube supplies no end time |
EVENT_DURATION_OVERRIDES |
empty | JSON mapping of title substrings to estimated hours, e.g. {"Motul Petit Le Mans | WeatherTech Championship":10} |
STREAM_BASE_URL |
http://127.0.0.1:8098 in Compose |
Address xTeVe uses to tune a channel |
MAX_STREAMS |
5 | Maximum concurrent remux sessions |
XTEVE_URL |
host gateway in Compose | xTeVe API base URL |
PLEX_URL, PLEX_TOKEN, PLEX_DVR_ID |
empty | Optional automatic guide reload |
YTDLP_COOKIES_FILE |
unset | Optional mounted Netscape cookies file for streams requiring authentication |
Recording and limitations
Schedule recordings using the normal Plex DVR controls. No recording rules are automatically created. YouTube frequently omits end times; estimated ends are marked in descriptions. Set end padding or increase DEFAULT_EVENT_HOURS for long endurance races. Adjacent broadcasts are clipped to avoid overlapping entries on a single channel.
Offline channels remain listed but return HTTP 503 when tuned; they do not play an unrelated placeholder stream. Detection takes up to a poll interval. A channel exposing multiple simultaneous broadcasts can only play one feed through its single tuner channel. The guide covers seven days and discovery examines the first 50 stream listings per channel.
YouTube geo-restrictions, login requirements and upstream changes can still prevent playback. Cookies can be mounted if required; do not commit them. FFmpeg reconnects transient network failures, but uninterrupted 24-hour recording and upstream signature renewal during an already-open session are not guaranteed. No separate stream-start notification service is configured.
The image includes Node.js and yt-dlp's default dependencies for YouTube player challenges. Dependencies are pinned; when YouTube changes, update the yt-dlp pin and rebuild after verifying playback.
Published Docker images
Forgejo Actions builds git.yumeo.dev/sayori/yt2plex-poller for Linux amd64. Pull requests build the image and run regression tests; they do not publish. Pushes to main publish latest and sha-<full-commit> after tests pass. Version-tag pushes publish that version and its commit tag. Every image carries OCI source and revision labels.
The standard Compose file pulls this image, so KLGB1-Plex does not need to build it. Set YT2PLEX_IMAGE to an exact sha-… tag or digest to pin a release. Update with:
docker compose pull yt2plex-poller
docker compose up -d --no-deps yt2plex-poller
The publishing workflow uses the existing REGISTRY_TOKEN Actions secret, which can be defined at repository or owner scope. Registry authentication is only used on publishing runs. If pulls require authentication, log in with docker login git.yumeo.dev; keep the token out of Compose and Git.
For local development only:
docker compose -f docker-compose.yml -f docker-compose.build.yml up -d --build yt2plex-poller
Checks and rollback
cd yt2plex-poller
python -m unittest -v test_poller
http://127.0.0.1:8098/health reports discovery freshness, and Compose includes a health check. Logs report discovery failures without printing signed stream URLs or API keys.
Before upgrading, back up Compose, .env, the poller source, shared outputs, and xTeVe configuration. Tag/save the current poller image. Restore those files and the old image to roll back; replacing the poller does not require recreating the Plex DVR.
References: YouTube video metadata, video list quota, yt-dlp dependencies, Plex XMLTV setup.