live: heartbeat sync 2026-10-30T18:26:49-07:00 (Refs #11)

This commit is contained in:
Frank committed 2026-10-30 18:26:49 -07:00
1 parent 674a22be48
commit 69f983f94d
9 files changed
+216 -9

No files matched your search

@@ -0,0 +1,73 @@
---
name: plex-metadata-title-cache-read
description: "Read the live Plex library DB read-only for clean titles/file paths (no sqlite3 binary, server running), and use it as the title authority over filename parsing."
---
Plex's metadata cache already holds a *clean* title for every file it matched
(`Alien`, not `Alien.Directors.Cut.1979.1080p.BRrip.x265-RARBG`). Read it instead
of parsing filenames, and name folders / group duplicates from it.
## Where it lives
Host package: data dir `/var/lib/plexmediaserver`, DB at
```
/var/lib/plexmediaserver/Library/Application Support/Plex Media Server/Plug-in Support/Databases/com.plexapp.plugins.library.db
```
(`Resources/com.plexapp.plugins.library.db` under `/usr/lib/plexmediaserver` is a
blank template — not the library.) The dir is `dank:dank`, so no sudo needed.
Containers: check `podman ps` first; on Dankserver Plex runs as a host process.
## Read it while Plex is RUNNING
No `sqlite3` binary on the fleet hosts — use `python3 -c` with `sqlite3`. Open
immutable read-only so no WAL/SHM is touched and no lock is taken:
```python
con = sqlite3.connect(f"file:{db}?mode=ro&immutable=1", uri=True)
```
A long local `find /` can hit the tool's own deadline; scope `find` with
`-maxdepth` or use the path above directly.
## Schema traps
* `library_sections` → column is **`section_type`**, not `type`. Movies = 1,
TV = 2, Music = 8.
* **`metadata_titles` does not exist** (empty name in the table list). Titles are
on `metadata_items`: `title`, `original_title`, `edition_title`, `year`,
`metadata_type`, `parent_id`, `deleted_at`.
* File path is `media_parts.file`; join
`media_parts → media_items (id = media_item_id) → metadata_items
(id = metadata_item_id)`, and `LEFT JOIN metadata_items par ON par.id =
mi.parent_id` for the show/movie parent.
* **Movies use the LEAF title** (`mi.title`); the parent row is empty. TV uses
the parent. Filter `p.deleted_at IS NULL AND mi.deleted_at IS NULL` or deleted
scans pollute the census.
```sql
select p.file, mi.title, mi.original_title, mi.edition_title, mi.year, m.container,
m.video_codec, m.audio_codec, m.width, m.height
from media_parts p
join media_items m on m.id = p.media_item_id
join metadata_items mi on mi.id = m.metadata_item_id
where p.file like '/mnt/entropy/Movies/%'
and p.deleted_at is null and mi.deleted_at is null
```
`media_items` also carries codec/resolution already — often no ffprobe pass is
needed for matched files.
## Use it as the title authority
Reject a Plex title only if it looks like a filename
(`2160p|1080p|x26[45]|hevc|bluray|web-?dl`) — a healthy cache scores **0** junk
titles. Coverage expectation measured on `/mnt/entropy/Movies`: 3,754 of 4,698
media files matched; the unmatched remainder is extras, BDMV disc trees, TV
episodes misfiled into Movies, and collection box sets — exactly the classes a
filename parser must still handle.
Propagate one match to every copy of a film (a group of versions) so sidecars,
`.nfo` and media files share one stem; fall back to the filename parser only
when no row exists.