From 0aefa0ecf08d4cf23d4163213e85b48aaedbde88 Mon Sep 17 00:00:00 2001 From: Ray Ellison Date: Wed, 24 Jun 2026 20:21:24 +0930 Subject: [PATCH 1/2] Fix KeyError crash browsing Watchlist when sibling season lacks metadata 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. --- plugin.video.amazon-test/resources/lib/web_api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin.video.amazon-test/resources/lib/web_api.py b/plugin.video.amazon-test/resources/lib/web_api.py index 053c2b53..94558392 100644 --- a/plugin.video.amazon-test/resources/lib/web_api.py +++ b/plugin.video.amazon-test/resources/lib/web_api.py @@ -917,7 +917,7 @@ def ParseSinglePage(oid, o, bCacheRefresh, data=None, url=None): bEpisodesOnly = oid == gti siblings = [] if bEpisodesOnly else vd['siblings'][:] siblings.append(gti) - siblings = sorted(siblings, key=(lambda k: self._videodata[k]['metadata']['videometa']['season'])) + siblings = sorted(siblings, key=(lambda k: ((self._videodata.get(k) or {}).get('metadata') or {}).get('videometa', {}).get('season', 999))) for gti in siblings: # Add season if we're not inside a season already if (not bEpisodesOnly) and (gti not in o): From d0d015855bbcc6d772ed42e5de62c9096fc04388 Mon Sep 17 00:00:00 2001 From: Ray Ellison Date: Fri, 26 Jun 2026 16:35:14 +0930 Subject: [PATCH 2/2] Fix JSON corruption when season page URL fails URN extraction 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. --- plugin.video.amazon-test/resources/lib/web_api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin.video.amazon-test/resources/lib/web_api.py b/plugin.video.amazon-test/resources/lib/web_api.py index 94558392..ee271f30 100644 --- a/plugin.video.amazon-test/resources/lib/web_api.py +++ b/plugin.video.amazon-test/resources/lib/web_api.py @@ -1129,7 +1129,7 @@ def ParseSinglePage(oid, o, bCacheRefresh, data=None, url=None): # Meta prep if 'metadata' not in vd: - vd['metadata'] = {'compactGTI': urn, 'artmeta': {}, 'videometa': {}} + vd['metadata'] = {'compactGTI': urn if urn is not None else title_id, 'artmeta': {}, 'videometa': {}} bUpdated = True if 'artmeta' not in vd['metadata']: vd['metadata']['artmeta'] = {}