summaryrefslogtreecommitdiffstats
path: root/packages/meshbay-node/src/meshbay_node/indexer/title_parse.py
diff options
context:
space:
mode:
authorChristophe Besson <cbesson@gmail.com>2026-09-19 02:12:47 +0200
committerChristophe Besson <cbesson@gmail.com>2026-09-19 02:12:47 +0200
commit20a824118c09af15d6c338db4c9480ffe5cbcdb6 (patch)
tree39fa0c2056b12e3423eefe0cda78cf160ce17131 /packages/meshbay-node/src/meshbay_node/indexer/title_parse.py
parentcc0820de8d8c33560c44bd6a0864de30e33a0109 (diff)
downloadmeshbay-20a824118c09af15d6c338db4c9480ffe5cbcdb6.tar.gz
docs: cite MESHBAY_DESIGN.md and a section instead of the merged notes
The per-feature design notes were merged into docs/MESHBAY_DESIGN.md and deleted from the tree on 2026-09-11, but ~230 comments across the three packages still named them — usually written `docs/musicbay.md §3.2`, as though the file were still in docs/. A reader had to know §16 existed to resolve any of them. They now name the section directly. Every mapping comes from §16, the concordance, which already records where each old section landed: musicbay -> §9.8, mediacenter -> §9.7 for the Videos app and §6.5 where the subject is derived data, photos -> §9.9, auth-confirm -> §3.6, refactoring-search -> §9.11, invite-pairing-v1 -> §3.4, per-node-identity-v1 -> §3.2, captcha -> §7.7, chat-sender-keys -> §4.5, apps/refactor-groups -> §9.1–§9.4, desktop-client-v1 per section. Bare citations of the same documents (`draft-v6 §2.11`, `§4.8`, `§3.4`) are retargeted too: those collide with real section numbers in the design document, so leaving them would have been worse than the named form. Four cases the concordance does not cover, each decided rather than guessed: Sub-item references into documents that no longer exist — mediacenter's `§3.3 row 4`, `§3.4b/c`, `apps.md §3b` — name rows and sub-items §9.7 and §9.2 do not reproduce. The module-level citation stays; the sub-item pointer is dropped. The V-findings keep their labels but lose the dead `§10.1/` prefix. §13.8 lists V1–V13 as per-application open items, which is not what the labels mean in these comments, so pointing them at §13.8 would have been a false citation. `apps.md §5`'s virtualization requirement has no counterpart anywhere in the design document. The requirement is stated in the comment itself, so the citation is dropped rather than aimed at a section that does not say it. Comments that attributed a *sentence* to an old note — musicbay's "several thousand files" example, its "what got measured" note, its measured ~11%/~26% cover-art figures, the "original no root, whole shared tree" call — state the fact without attribution now. §9.8 does not contain those sentences and citing it for them would have been wrong. CLAUDE.md's "a reference to a document that no longer exists" row now says the concordance is for git history and out-of-tree material; the code cites sections directly. Verified: 2851 passed, 4 skipped. The 12 errors in the run are the Firefox leg of test_sticky_header.py's browser harness, which is broken at the browser level on this machine — headless Firefox (snap) dies with `[GFX1-]: RenderCompositorSWGL failed mapping default framebuffer`, renders nothing, and the probe exits `{"error": "no measurement"}` after its full 90s wait. Chrome runs the same 12 assertions in 3.2s and passes. Nothing here can affect it: every changed line in style.css is inside a comment. Also checked: ast.parse on every changed .py, `node --check` on every changed .js, the /* */ balance in style.css, and that no changed line exceeds the width its file already used. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Diffstat (limited to 'packages/meshbay-node/src/meshbay_node/indexer/title_parse.py')
-rw-r--r--packages/meshbay-node/src/meshbay_node/indexer/title_parse.py31
1 files changed, 16 insertions, 15 deletions
diff --git a/packages/meshbay-node/src/meshbay_node/indexer/title_parse.py b/packages/meshbay-node/src/meshbay_node/indexer/title_parse.py
index beb0d3f..14728ff 100644
--- a/packages/meshbay-node/src/meshbay_node/indexer/title_parse.py
+++ b/packages/meshbay-node/src/meshbay_node/indexer/title_parse.py
@@ -1,18 +1,18 @@
"""
Filename -> title/year/season/episode parsing for the Videos group app.
-Wraps `guessit` and layers the fixes from docs/mediacenter.md §3.3/§3.4 on
+Wraps `guessit` and layers the fixes from docs/MESHBAY_DESIGN.md §9.7 on
top of it: none of them are per-title hacks, each is a generic rule found
by validating guessit's raw output against real TMDB search results over a
~1950-file library (movies, TV shows, and a small franchise set).
-Scope is deliberately narrow (§3.5): title, year, season, episode. Technical
+Scope is deliberately narrow: title, year, season, episode. Technical
facts (resolution, codec, duration) come from ffprobe, never the filename —
a mislabeled `1080p` tag is a real, observed failure mode.
This module never touches the filesystem or the network. The orchestration
that decides *which* file supplies a show's title (a representative episode
-filename, not the folder name — §3.4) lives in the indexer, which has the
+filename, not the folder name) lives in the indexer, which has the
directory listing; this module only parses strings it's handed.
"""
@@ -91,7 +91,7 @@ _YEAR_RE = re.compile(r"(?<!\d)(?:19|20)\d{2}(?!\d)")
def year_in(text: str) -> int | None:
"""First 19xx/20xx in `text`, or None — used to lift a year off a show
- folder name ("Some.Show.2022.S01") for the search fallback (§10.1/V8)."""
+ folder name ("Some.Show.2022.S01") for the search fallback (V8)."""
m = _YEAR_RE.search(text or "")
return int(m.group(0)) if m else None
@@ -102,7 +102,7 @@ def clean_query(s: str) -> str:
parenthesized-year stripping `naive_title` does. `naive_title` assumes
a real filename; a show's `display_title` is a folder basename
("Some.Show.Name" — `rsplit('.', 1)` would eat ".Name"), so it needs a
- gentler normaliser (§10.1/V8).
+ gentler normaliser (V8).
"""
s = re.sub(r"[._-]+", " ", s or "")
s = _strip_editions(s)
@@ -115,7 +115,7 @@ def _strip_editions(title: str) -> str:
def naive_title(filename: str) -> str:
"""
- The mandated fallback (§3.6, §4.1): strip the extension, replace every
+ The mandated fallback: strip the extension, replace every
`.`/`_`/`-` with a space, drop a trailing parenthesized year, collapse
whitespace. Always computable, never fails, used both as the flat-mode
display name of last resort and as a second TMDB query candidate.
@@ -150,14 +150,14 @@ def sequel_variants(title: str) -> list[str]:
A trailing sequel index often has no exact match in the real TMDB
title: the file has a digit where TMDB uses a Roman numeral (or the
reverse), spells the number out, or wraps it as "Part N" / "Chapitre N"
- (§3.3 row 4, §10.1/V10). Returns extra candidate titles to try — the
+ (V10). Returns extra candidate titles to try — the
index re-rendered as digit and as Roman numeral, plus (only when there
is no "Part"/"Episode"/… keyword) the bare base.
The bare base is withheld for a keyword'd index — "<Saga> Chapter III"
→ "<Saga>" — because a franchise's bare name is very often a real,
*different* film (the series' first entry), and that variant matched
- every later entry to it (§10.1/V14). Without the keyword ("<Franchise>
+ every later entry to it (V14). Without the keyword ("<Franchise>
3") the number is decoration and the bare base is the right thing to
try.
"""
@@ -190,7 +190,7 @@ def sequel_variants(title: str) -> list[str]:
def season_from_folder_name(name: str) -> int | None:
"""
- §3.4: a season-like ancestor folder, vocabulary-driven rather than
+ A season-like ancestor folder, vocabulary-driven rather than
assuming a numeric convention everywhere. A specials/bonus/extras
folder maps to season 0 (matching TMDB's own `season_number: 0`).
Returns None if `name` doesn't look like a season folder at all.
@@ -212,7 +212,8 @@ def season_from_folder_name(name: str) -> int | None:
@dataclass
class ParsedName:
display_title: str | None # None => caller must supply from elsewhere (e.g. a sibling file)
- alt_title: str | None = None # guessit's alternative_title, a second query candidate (§3.3 row 1)
+ alt_title: str | None = None # guessit's alternative_title, a second
+ # query candidate
naive_title: str = "" # always available, fully punctuation-normalized fallback
year: int | None = None
season: int | None = None
@@ -249,7 +250,7 @@ def parse_movie_filename(filename: str) -> ParsedName:
-# ── Music app (docs/musicbay.md §2.1) ────────────────────────────────────────
+# ── Music app (docs/MESHBAY_DESIGN.md §9.8) ────────────────────────────────────────
#
# Filename parsing is the *fallback* here, not the primary source (unlike
# Videos, where guessit does all the work): embedded ID3/Vorbis tags are read
@@ -307,7 +308,7 @@ def strip_track_prefix(text: str) -> str:
# "Season 1"/"Saison 1". guessit will also invent a season+episode from a
# bare 3-4 digit run ("1080p" truncated to "108" -> S01E08; "1280" ->
# S12E80), which is how a plain movie ends up shelved as a series
-# (§10.1/V14). The indexer uses this to tell a real flat-library episode
+# (V14). The indexer uses this to tell a real flat-library episode
# from that hallucination.
_EPISODE_MARKER_RE = re.compile(
r"s\d{1,2}[\s._-]*e\d{1,3}"
@@ -326,9 +327,9 @@ def has_episode_marker(filename: str) -> bool:
def parse_episode_filename(filename: str) -> ParsedName:
"""
Parse an episode filename. `display_title` may come back None (e.g.
- `S08E02.SUBFRENCH.720p.mkv` carries no show name at all, §3.2) — the
+ `S08E02.SUBFRENCH.720p.mkv` carries no show name at all) — the
indexer then supplies the show title from a representative sibling
- filename in the same folder rather than the folder name itself (§3.4).
+ filename in the same folder rather than the folder name itself.
"""
g = guessit(filename)
title = g.get("title")
@@ -351,7 +352,7 @@ def parse_episode_filename(filename: str) -> ParsedName:
)
-# A bare leading episode number, no show name attached (§3.4c) — the same
+# A bare leading episode number, no show name attached — the same
# shape as music's _TRACK_PREFIX_RE, capped at 3 digits for the same reason:
# a leading year ("2010 - Episode.mkv") is 4 digits and must not match.
# guessit's own `episode` is not a substitute here: given exactly 3 digits it