Plex page: play/pause state and progress per stream

The EL512 Plex streams sensor now reads the Plex media players
(media_player.plex_*) every 5 s: who, title, playing/paused, position and
duration, falling back to the server sensor's list without them. The Plex
page shows a play/pause icon, position / duration and a thin progress bar
per stream (dotted while paused), counting on between updates.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
mangavalkandClaude Opus 5.5 committed 2026-10-19 00:03:44 +02:00
1 parent 1e8a9a5958
commit 921a4c3aa6
2 files changed
+71 -7

No files matched your search

+30 -5
View File
@@ -112,18 +112,43 @@ template:
| map('string') | map('replace', '|', '/') | join('|') }}
{%- endif -%}
# Plex: the server sensor has one attribute per stream ("user - client": "title").
- sensor:
# Plex streams with play/pause state and position, from the Plex integration's
# media players (media_player.plex_*); position advances every 5 s. Without
# any Plex players, falls back to the server sensor, which has one attribute
# per stream ("user - client": "title") but no state or position.
- triggers:
- trigger: time_pattern
seconds: "/5"
sensor:
- name: EL512 Plex streams
unique_id: el512_plex_streams
icon: mdi:plex
state: "{{ states('sensor.mangavalkserver') }}"
attributes:
# "user - client|title;..."
# "who|title|playing or paused|position s|duration s;..."
# (fallback: "user - client|title;...")
streams: >-
{%- set s = states.sensor.mangavalkserver -%}
{%- set ns = namespace(out=[]) -%}
{%- if s -%}
{%- for p in states.media_player
if p.entity_id.startswith('media_player.plex_') and p.state in ['playing', 'paused'] -%}
{%- set a = p.attributes -%}
{%- set pos = a.media_position | default(0) -%}
{%- if p.state == 'playing' and a.media_position_updated_at is defined and a.media_position_updated_at -%}
{%- set pos = pos + (now() - as_datetime(a.media_position_updated_at)).total_seconds() -%}
{%- endif -%}
{%- set dur = a.media_duration | default(0) -%}
{%- set pos = [pos, dur] | min if dur else pos -%}
{%- set title = a.media_title | default('') -%}
{%- if a.media_series_title | default('') -%}
{%- set title = a.media_series_title ~ ' - ' ~ title -%}
{%- endif -%}
{%- set who = a.username | default(a.friendly_name | default(p.entity_id)) -%}
{%- set ns.out = ns.out + [[who, title, p.state, pos | int, dur | int]
| map('string') | map('replace', '|', '/') | map('replace', ';', ',')
| join('|')] -%}
{%- endfor -%}
{%- set s = states.sensor.mangavalkserver -%}
{%- if not ns.out and s -%}
{%- for k, v in s.attributes.items()
if k not in ['unit_of_measurement', 'friendly_name', 'icon', 'device_class', 'state_class'] -%}
{%- set ns.out = ns.out + [(k | replace('|', '/') | replace(';', ',')) ~ '|' ~