Title: Fix two crashes browsing Watchlist seasons (KeyError + JSON corruption)Fix watchlist season keyerror#832
Open
Mozzie-AU wants to merge 2 commits into
Open
Conversation
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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.