refactor(plex): playlists, playback, Discover and admin through the unit; the plex package is fenced

The last Plex HTTP files do no database work of their own, so ALLOWED is empty: no route builds
SQL, touches the session or a unit's table. Discover's rails move whole into plex/discover.py; a
user's playlists, watch-state writes (the race-safe finish, an early checkpoint, a status, a
season or show at once) and the watch-sync link go through plex/queries.py and plex/service.py.

The plex package joins FENCED: it reads no other unit's tables, says whose a row is through
userscope (the rollup and the watch sync's 8 inline filters moved to owned_by), and commits only in
its named jobs — the library sync, TMDB enrichment, the watch sync and its background pushes.
A playlist's has-item probe keeps the plain key lookup, so a NUL in it is still the 422 a test pins.

Pins 178 -> 0; basedpyright baseline 118 -> 106.
This commit is contained in:
2026-10-19 22:42:46 +02:00
parent 2cf1b688d9
commit 531eb2eef1
18 changed files with 1307 additions and 1052 deletions
+7 -4
View File
@@ -14,6 +14,7 @@ from sqlalchemy import select
from app.db import SessionLocal
from app.plex.models import PlexItem, PlexLibrary, PlexState
from app.plex import service as plex_service
from app.routes.plex import playback
@@ -36,10 +37,12 @@ def test_two_racing_finishes_flip_the_row_once(db, make_user):
first, second = SessionLocal(), SessionLocal()
try:
assert playback._mark_finished(first, user.id, item.id, now) is True # holds the row lock
assert (
plex_service.mark_finished(first, user.id, item.id, now) is True
) # holds the row lock
out: list[bool] = []
racer = threading.Thread(
target=lambda: out.append(playback._mark_finished(second, user.id, item.id, now))
target=lambda: out.append(plex_service.mark_finished(second, user.id, item.id, now))
)
racer.start()
racer.join(0.5)
@@ -57,9 +60,9 @@ def test_a_first_ever_finish_inserts_and_counts_once(db, make_user):
user = make_user()
item = _item(db)
now = datetime.now(timezone.utc)
assert playback._mark_finished(db, user.id, item.id, now) is True
assert plex_service.mark_finished(db, user.id, item.id, now) is True
db.commit()
assert playback._mark_finished(db, user.id, item.id, now + timedelta(seconds=10)) is False
assert plex_service.mark_finished(db, user.id, item.id, now + timedelta(seconds=10)) is False
db.commit()
st = db.execute(select(PlexState).where(PlexState.item_id == item.id)).scalars().one()
assert (st.status, st.position_seconds) == ("watched", 0)