Skip to content

Title: Fix two crashes browsing Watchlist seasons (KeyError + JSON corruption)Fix watchlist season keyerror#832

Open
Mozzie-AU wants to merge 2 commits into
Sandmann79:masterfrom
Mozzie-AU:fix-watchlist-season-keyerror
Open

Title: Fix two crashes browsing Watchlist seasons (KeyError + JSON corruption)Fix watchlist season keyerror#832
Mozzie-AU wants to merge 2 commits into
Sandmann79:masterfrom
Mozzie-AU:fix-watchlist-season-keyerror

Conversation

@Mozzie-AU

Copy link
Copy Markdown

Description:

I'm no expert here, and so treat this work as a hopefully helpful... I'm using a bit of LLM to help me with getting my head around python.
Heres what Ive done... Moz

Rebased onto 1.2.2. Distinct from the compactGTI/TypeError fix in #829 (thanks for that one) — that fixed a read-site guard at line 980; these two are a still-open crash and its root cause, found while digging into the same general area.

Bug 1 — KeyError: 'metadata' browsing into a show with an unhydrated season
Season nodes are seeded into self._videodata with only {'ref', 'children', 'siblings'} when first discovered via a show's listing. They only gain metadata.videometa.season once their own page is individually parsed. The cache-hit sort in ParseSinglePage assumed every sibling already had this populated:
File ".../web_api.py", line 920, in ParseSinglePage
siblings = sorted(siblings, key=(lambda k: self._videodata[k]['metadata']['videometa']['season']))
KeyError: 'metadata'
Fix: defensive .get() chaining with a sentinel default (999), so unhydrated seasons sort after fully-loaded ones instead of crashing. They self-correct once their own page is parsed.

Bug 2 — Cache corruption / silent data loss on season-selector pages
ParseSinglePage sets metadata.compactGTI = ExtractURN(url) for any newly-seen GTI. Pages reached via a season-selector ref (?ref_=atv_dp_season_select_sN) don't match the URN-extraction regex (no trailing slash before the query string), so urn is None for every node first seen this way — including the show itself and any siblings in the same response.
That None gets written into the cache as compactGTI. Once enough accumulate, json.dump(..., sort_keys=True) in _Flush crashes with TypeError: '<' not supported between instances of 'NoneType' and 'str'. The addon then detects its own cache file is corrupted and deletes it — from the user's side, browsing an affected season silently wipes the whole cache and leaves it empty next visit. This is the same compactGTI: None root cause behind #829's symptom, just hitting a different consumer (the write site / later serialization, rather than the membership check fixed there).
Fix: fall back to title_id (the page's own pageTitleId, always valid at this point) when urn is None, instead of storing None.

Testing: Reproduced and verified via direct log capture and targeted debug logging on LibreELEC / Raspberry Pi 4, Kodi Matrix. Confirmed clean cold-cache browsing (Watchlist → show → multiple seasons → episode playback) with both fixes applied, no crashes, no cache corruption.

Mozzo added 2 commits June 26, 2026 16:43
In ParseSinglePage's cache-hit path, siblings are sorted by
metadata.videometa.season. Season nodes are seeded without metadata
when first discovered via a show's siblings list (see line ~1051),
and only gain metadata.videometa.season once their own page has been
individually parsed. Browsing into a show with an unopened/unparsed
season (e.g. via Watchlist before ever opening that season directly)
crashes the sort with KeyError: 'metadata'.

Fix: use defensive .get() chaining with a sentinel default (999) so
unhydrated season placeholders sort after fully-loaded seasons
instead of crashing. They self-correct once their page is parsed
and their real season number is set.
ParseSinglePage sets metadata.compactGTI to ExtractURN(url) for any
newly-seen GTI. Season pages reached via a season-selector ref
(?ref_=atv_dp_season_select_sN) don't match the URN regex
(no trailing slash before the query string), so urn is None for
every node first discovered this way - including the show itself,
and any season/episode entries seen alongside it in the same
response.

That None gets written into the cache as compactGTI. Once enough of
these accumulate, json.dump(..., sort_keys=True) in _Flush crashes
with TypeError: '<' not supported between instances of 'NoneType'
and 'str', since key sorting compares None against real strings
elsewhere in the structure. The addon then detects its own cache
file is corrupted and deletes it, losing all cached data - which
from the user's side looks like browsing into an affected season
silently wipes everything and leaves it empty on the next visit.

Fix: fall back to title_id (the page's own pageTitleId, always a
valid GTI string at this point) when urn is None, instead of
storing None as compactGTI.

Found and fixed alongside the Watchlist season KeyError crash in
the same investigation - this is the second commit on that branch.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants