fix(plex): honor the admin "max concurrent transcodes" setting (config drift)
stream.py enforced a hardcoded _MAX_SESSIONS = 4 and never read the DB-overridable plex_max_transcodes ConfigSpec, so the Configuration → Plex → "Max concurrent transcodes" knob was dead (same env-vs-DB drift class as the Downloads/Admin fixes). _enforce_cap(cap) now takes the cap from sysconfig.get_int(db, "plex_max_transcodes") (>=1 so playback can't be capped to zero). Bumped the config default 1→4 so the effective default matches the old hardcoded cap (no behavior change for non-overriders; the knob now works).
This commit is contained in:
parent
e92751dbce
commit
3c7a8c7a14
2 changed files with 8 additions and 6 deletions
|
|
@ -211,7 +211,7 @@ class Settings(BaseSettings):
|
||||||
plex_watch_reconcile_interval_min: int = 1440
|
plex_watch_reconcile_interval_min: int = 1440
|
||||||
# Max concurrent transcodes for the P3 fallback. Low by default — CPU-only transcode is
|
# Max concurrent transcodes for the P3 fallback. Low by default — CPU-only transcode is
|
||||||
# expensive; direct-serve (browser-compatible files) has no such limit.
|
# expensive; direct-serve (browser-compatible files) has no such limit.
|
||||||
plex_max_transcodes: int = 1
|
plex_max_transcodes: int = 4
|
||||||
# Where on-the-fly HLS remux segments are written (transient, reaped). Empty → a `.plex-hls`
|
# Where on-the-fly HLS remux segments are written (transient, reaped). Empty → a `.plex-hls`
|
||||||
# dir under download_root. On localdev the download_root is a slow Windows bind-mount, so point
|
# dir under download_root. On localdev the download_root is a slow Windows bind-mount, so point
|
||||||
# this at a fast container-local path (e.g. /var/tmp/plex-hls); prod's download_root is fast
|
# this at a fast container-local path (e.g. /var/tmp/plex-hls); prod's download_root is fast
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ from pathlib import Path
|
||||||
|
|
||||||
from sqlalchemy.orm import Session as DbSession
|
from sqlalchemy.orm import Session as DbSession
|
||||||
|
|
||||||
|
from app import sysconfig
|
||||||
from app.config import settings
|
from app.config import settings
|
||||||
from app.models import PlexItem
|
from app.models import PlexItem
|
||||||
from app.plex import paths
|
from app.plex import paths
|
||||||
|
|
@ -31,7 +32,6 @@ log = logging.getLogger("siftlode.plex")
|
||||||
|
|
||||||
_HLS_ROOT = Path(settings.plex_hls_dir) if settings.plex_hls_dir else Path(settings.download_root) / ".plex-hls"
|
_HLS_ROOT = Path(settings.plex_hls_dir) if settings.plex_hls_dir else Path(settings.download_root) / ".plex-hls"
|
||||||
_SEG_SECONDS = 6
|
_SEG_SECONDS = 6
|
||||||
_MAX_SESSIONS = 4 # concurrent remux sessions (safety valve for the CPU-only host)
|
|
||||||
_SESSION_IDLE_S = 600 # reap a session with no access for this long
|
_SESSION_IDLE_S = 600 # reap a session with no access for this long
|
||||||
|
|
||||||
_lock = threading.Lock()
|
_lock = threading.Lock()
|
||||||
|
|
@ -168,11 +168,11 @@ def _kill(s: HlsSession) -> None:
|
||||||
shutil.rmtree(s.dir, ignore_errors=True)
|
shutil.rmtree(s.dir, ignore_errors=True)
|
||||||
|
|
||||||
|
|
||||||
def _enforce_cap() -> None:
|
def _enforce_cap(cap: int) -> None:
|
||||||
# Caller holds _lock. Drop the least-recently-accessed sessions over the cap.
|
# Caller holds _lock. Drop the least-recently-accessed sessions over the cap.
|
||||||
if len(_sessions) <= _MAX_SESSIONS:
|
if len(_sessions) <= cap:
|
||||||
return
|
return
|
||||||
for key, s in sorted(_sessions.items(), key=lambda kv: kv[1].last_access)[: len(_sessions) - _MAX_SESSIONS]:
|
for key, s in sorted(_sessions.items(), key=lambda kv: kv[1].last_access)[: len(_sessions) - cap]:
|
||||||
_kill(s)
|
_kill(s)
|
||||||
_sessions.pop(key, None)
|
_sessions.pop(key, None)
|
||||||
|
|
||||||
|
|
@ -211,7 +211,9 @@ def start_session(
|
||||||
)
|
)
|
||||||
s = HlsSession(key, directory, proc, start_s, "master.m3u8" if is_multi else "index.m3u8")
|
s = HlsSession(key, directory, proc, start_s, "master.m3u8" if is_multi else "index.m3u8")
|
||||||
_sessions[key] = s
|
_sessions[key] = s
|
||||||
_enforce_cap()
|
# Admin-configurable concurrency cap (Configuration → Plex → Max concurrent transcodes);
|
||||||
|
# at least 1 so playback can't be capped to zero.
|
||||||
|
_enforce_cap(max(1, sysconfig.get_int(db, "plex_max_transcodes")))
|
||||||
# Learn the REAL start offset K from the first VIDEO segment (outside the lock — this blocks on
|
# Learn the REAL start offset K from the first VIDEO segment (outside the lock — this blocks on
|
||||||
# ffmpeg producing it, and we must not hold up other sessions). The client reads `media_start_s`, so
|
# ffmpeg producing it, and we must not hold up other sessions). The client reads `media_start_s`, so
|
||||||
# its absolute clock + subtitle shift key off the true keyframe, not the requested offset. On
|
# its absolute clock + subtitle shift key off the true keyframe, not the requested offset. On
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue