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:
@@ -109,12 +109,7 @@ UNIT_ROUTES = {
|
||||
|
||||
# What each HTTP file still does, by file: the debt a unit's sprint pays off. Exact counts. A core
|
||||
# route's count is only the unit tables it imports; it is paid by the sprint of the unit it reaches.
|
||||
ALLOWED = {
|
||||
"plex/admin.py": 12,
|
||||
"plex/discover.py": 44,
|
||||
"plex/playback.py": 42,
|
||||
"plex/playlists.py": 80,
|
||||
}
|
||||
ALLOWED: dict[str, int] = {}
|
||||
|
||||
# The session methods that read or write data. `commit` and `rollback` stay with the handler.
|
||||
SESSION_DATA = {
|
||||
@@ -342,11 +337,19 @@ UNIT_PACKAGES = {
|
||||
"sync/subscriptions.py",
|
||||
"sync/videos.py",
|
||||
),
|
||||
# The Plex mirror: its sync, the watch-state sync with a linked account, TMDB enrichment, the
|
||||
# pages' reads and writes.
|
||||
"plex": ("plex/",),
|
||||
}
|
||||
# The units fenced so far; the rest join with their sprint.
|
||||
FENCED = {"capture", "reader", "catalog"}
|
||||
FENCED = {"capture", "reader", "catalog", "plex"}
|
||||
# Whose tables a unit's own code may READ. Core code reads a fenced unit's tables through its queries.
|
||||
READS = {"capture": {"catalog", "plex"}, "reader": {"catalog", "plex"}, "catalog": set()}
|
||||
READS = {
|
||||
"capture": {"catalog", "plex"},
|
||||
"reader": {"catalog", "plex"},
|
||||
"catalog": set(),
|
||||
"plex": set(),
|
||||
}
|
||||
# The columns that say whose a row is.
|
||||
OWNER_COLUMNS = {"user_id", "to_user_id", "from_user_id", "created_by"}
|
||||
# Where a fenced unit's code may commit: the jobs that own their session (the worker and what it
|
||||
@@ -399,6 +402,26 @@ UNIT_COMMITS = {
|
||||
"sync/videos.py:run_shorts_classification",
|
||||
"sync/videos.py:ensure_videos",
|
||||
},
|
||||
# The Plex jobs commit per step too: a library sync per section and per enrich/probe batch, the
|
||||
# TMDB enrichment per batch, the watch sync per pull and push. The pushes and a person's bio
|
||||
# fetch run as background tasks after the response, on a session of their own; the owner's
|
||||
# first import runs after the handler committed the link it reads.
|
||||
"plex": {
|
||||
"plex/people.py:prune_orphan_people",
|
||||
"plex/sync.py:sync",
|
||||
"plex/sync.py:_probe_media_batch",
|
||||
"plex/sync.py:_enrich_people_batch",
|
||||
"plex/tmdb.py:enrich_batch",
|
||||
"plex/tmdb.py:backfill_country_codes",
|
||||
"plex/tmdb.py:enrich_person",
|
||||
"plex/tmdb.py:enrich_people_batch",
|
||||
"plex/watch_sync.py:import_owner_watch_state",
|
||||
"plex/watch_sync.py:push_state_to_plex",
|
||||
"plex/watch_sync.py:push_bulk_state_to_plex",
|
||||
"plex/watch_sync.py:_resolve_account_id",
|
||||
"plex/watch_sync.py:run_plex_watch_sync",
|
||||
"plex/watch_sync.py:run_plex_watch_reconcile",
|
||||
},
|
||||
}
|
||||
SQL_WRITES = {"insert", "update", "delete", "pg_insert"}
|
||||
|
||||
@@ -533,7 +556,8 @@ PACKAGE_CASES = {
|
||||
("downloads/x.py", "from app.models import Video\nupdate(Video)"): 1,
|
||||
("downloads/x.py", "from app.downloads.models import DownloadJob\nDownloadJob()"): 0,
|
||||
("search.py", "from app.downloads.models import DownloadJob"): 1, # core reads capture
|
||||
("search.py", "from app.models import PlexItem\nPlexItem()"): 0, # neither side fenced yet
|
||||
("search.py", "from app.plex.models import PlexItem\nPlexItem()"): 2, # core reads, writes plex
|
||||
("plex/x.py", "from app.catalog.models import Video"): 1, # no plex→catalog edge
|
||||
("search.py", "from app.models import Video\nVideo()"): 2, # core reads and writes catalog
|
||||
("sync/videos.py", "from app.models import Playlist"): 1, # no catalog→reader edge
|
||||
("downloads/x.py", "q = DownloadJob.user_id == 1"): 1,
|
||||
|
||||
Reference in New Issue
Block a user