Skip to content

feat(plex): Live TV channel + EPG sync after generation - #866

Open
aresthegodofwar wants to merge 2 commits into
Pharaoh-Labs:devfrom
aresthegodofwar:feat/plex-live-tv-integration
Open

aresthegodofwar wants to merge 2 commits into
Pharaoh-Labs:devfrom
aresthegodofwar:feat/plex-live-tv-integration

Conversation

@aresthegodofwar

Copy link
Copy Markdown

Addresses #696.

Summary

After each generation run, refreshes any configured Plex servers so newly created and removed channels appear in Plex's Live TV guide without a manual rescan — the same refresh-after-generation pattern already used for Emby, Jellyfin, and Channels DVR.

  • Settings → Media Servers → Plex: URL, token, a discovered DVR/device picker (GET /livetv/dvrs), and an optional Dispatcharr channel profile to scope which managed channels get pushed to a profile-bound device.
  • PUT /media/grabbers/devices/<key>/channelmap is the only call needed. It's a full-state-replace on both the enabled-channel set and the per-channel EPG-binding params, and issuing it is what makes Plex actually refresh its guide.
  • Every enabled channel outside Teamarr's own managed range is resubmitted with its own current EPG binding on every run, unchanged, so channels from other tools sharing the same device are never disturbed.
  • Keyed on each entry's deviceIdentifier (Dispatcharr's physical channel number), never Plex's own channelKey — see findings below.

Findings from live testing (relevant to the discussion on #696)

Plex exposes no documentation for the DVR/channelmap endpoints used here, so most of the above came from testing against a real Plex + Dispatcharr HDHomeRun setup rather than from docs:

  • channelKey is not a stable channel identity. It tracks whichever EPG entry is currently matched in Plex's Channel Matching UI and can diverge from the physical channel number after a manual remap. deviceIdentifier is the field that stays fixed to the actual Dispatcharr/HDHomeRun channel number — everything here keys on that instead.
  • The channelmap PUT is full-state on both params, not just channelsEnabled. A channel listed as enabled but missing its own channelMappingByKey/channelMapping entry gets disabled anyway — there's no safe delta here, every enabled channel's binding has to be resubmitted every run, foreign ones included.
  • POST /livetv/dvrs/<id>/reloadGuide does not reliably refresh programme content. A channel reassigned to a different event (same number, new programme) kept showing stale guide data through several reloadGuide calls. The channelmap PUT is what actually triggers a full guide refresh on Plex's side — it's the same request Plex's own UI sends when you open a tuner's Channel Matching screen and hit Save with no changes. reloadGuide isn't used by this implementation at all.

@egyptiangio @pumacustom0c — flagging in case any of this overlaps with what you've each found; happy to compare notes if there's a better way to combine efforts here.

Test plan

  • ruff check teamarr/ tests/, pytest tests/ -v (3493 passed), cd frontend && npm run build all green on this branch rebased onto current dev.
  • New unit tests in tests/integrations/test_plex_client.py covering the fetch-merge-write channelmap logic, the deviceIdentifier/channelKey divergence, and URL/param handling.
  • Manually verified against a live Plex Pass server with Live TV/DVR pointed at Dispatcharr's HDHomeRun emulation: new Teamarr channels appear and get EPG-bound, channels removed from Dispatcharr drop out of the Plex lineup, and channels configured outside Teamarr (manually added, sharing the same tuner) keep their own guide data intact across repeated runs.

…#696)

After each generation run, refreshes any configured Plex servers so
newly created and removed channels appear in Plex's Live TV guide
without a manual rescan.

Settings → Media Servers → Plex: URL, token, and a discovered DVR/device
picker (GET /livetv/dvrs), plus an optional Dispatcharr channel profile
to scope which managed channels get pushed to a profile-bound device.

Refresh mechanics (teamarr/plex/client.py):
- PUT /media/grabbers/devices/<key>/channelmap is the only call needed —
  it's a full-state-replace on both the enabled-channel set and the
  per-channel EPG-binding params, and issuing it is what triggers Plex
  to actually refresh its guide (confirmed against a live server; a
  separate reloadGuide endpoint exists but does not reliably refresh
  programme content, so it isn't used here).
- Every enabled channel outside Teamarr's own managed range is resubmitted
  with its own current EPG binding on every run, unchanged — a channel
  omitted from the write gets disabled by Plex regardless of whether it's
  still listed as enabled elsewhere in the payload.
- Keyed on each entry's deviceIdentifier (Dispatcharr's physical channel
  number), never Plex's own channelKey — that field tracks whichever EPG
  entry is currently matched in Plex's Channel Matching UI and can diverge
  from the physical channel after a manual remap.

Verified against a live Plex + Dispatcharr HDHomeRun setup: new channels
appear and get EPG-bound, removed channels are dropped from the lineup,
and channels manually configured outside Teamarr keep their own guide
data untouched across repeated runs.
…hannel map (Pharaoh-Labs#696)

Plex crashed (SIGFPE) after libxml reported "Extra content at the end of the
document" on an XMLTV guide cut off mid-programme: the channelmap PUT makes
Plex fetch the DVR's guide immediately, while Dispatcharr was still rewriting
it after the run's channel/EPG updates.

Derive the guide URL from the DVR's lineup, re-point it at the configured
Dispatcharr, and hold the PUT until it parses as a whole document (90s cap).
On timeout the server is skipped for the run and retried on the next one.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant