From 501128deb6243beb835792bf06d50b92bf36a7c4 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Tue, 10 Mar 2026 14:18:04 +0000 Subject: [PATCH] Fix functional bugs in utilities and scrobbler - Fix findEpisodeMatchInList bug in utilities.py where 'list' was used instead of 'list_data'. - Fix Python 3 compatibility issue in scrobbler.py by replacing 'e.message' with 'str(e)'. - Improve defensive programming in scrobbler.py to handle missing keys in API results. - Add regression test for findEpisodeMatchInList. Co-authored-by: razzeee <5943908+razzeee@users.noreply.github.com> --- resources/lib/scrobbler.py | 19 ++++++++++++------- resources/lib/utilities.py | 2 +- tests/test_utilities.py | 23 +++++++++++++++++++++++ 3 files changed, 36 insertions(+), 8 deletions(-) diff --git a/resources/lib/scrobbler.py b/resources/lib/scrobbler.py index 10f0e630..0baf3a44 100644 --- a/resources/lib/scrobbler.py +++ b/resources/lib/scrobbler.py @@ -240,7 +240,7 @@ def playbackStarted(self, data: Dict) -> None: else: self.videoDuration = xbmc.Player().getTotalTime() except Exception as e: - logger.debug("Suddenly stopped watching item: %s" % e.message) + logger.debug("Suddenly stopped watching item: %s" % str(e)) self.curVideo = None return @@ -409,9 +409,11 @@ def playbackStarted(self, data: Dict) -> None: def __preFetchUserRatings(self, result: Dict) -> None: if result: - if utilities.isMovie( - self.curVideo["type"] - ) and kodiUtilities.getSettingAsBool("rate_movie"): + if ( + utilities.isMovie(self.curVideo["type"]) + and kodiUtilities.getSettingAsBool("rate_movie") + and "movie" in result + ): # pre-get summary information, for faster rating dialog. logger.debug( "Movie rating is enabled, pre-fetching summary information." @@ -422,9 +424,12 @@ def __preFetchUserRatings(self, result: Dict) -> None: result["movie"]["ids"]["trakt"], "trakt" ) } - elif utilities.isEpisode( - self.curVideo["type"] - ) and kodiUtilities.getSettingAsBool("rate_episode"): + elif ( + utilities.isEpisode(self.curVideo["type"]) + and kodiUtilities.getSettingAsBool("rate_episode") + and "episode" in result + and "show" in result + ): # pre-get summary information, for faster rating dialog. logger.debug( "Episode rating is enabled, pre-fetching summary information." diff --git a/resources/lib/utilities.py b/resources/lib/utilities.py index 954642da..72183480 100644 --- a/resources/lib/utilities.py +++ b/resources/lib/utilities.py @@ -204,7 +204,7 @@ def findSeasonMatchInList(id: str, seasonNumber: int, listToMatch: Dict, idType: def findEpisodeMatchInList(id: str, seasonNumber: int, episodeNumber: int, list_data: Dict, idType: str) -> Dict: - season = findSeasonMatchInList(id, seasonNumber, list, idType) + season = findSeasonMatchInList(id, seasonNumber, list_data, idType) if season: for episode in season["episodes"]: if episode["number"] == episodeNumber: diff --git a/tests/test_utilities.py b/tests/test_utilities.py index 5d434551..15aec372 100644 --- a/tests/test_utilities.py +++ b/tests/test_utilities.py @@ -632,3 +632,26 @@ def test_createError(): error_msg = utilities.createError(e) assert "ValueError" in error_msg assert "test error" in error_msg + + +def test_findEpisodeMatchInList(): + # Mocking a structure that would be returned by Trakt API + class MockItem: + def __init__(self, data, keys): + self.data = data + self.keys = keys + + def to_dict(self): + return self.data + + episode_data = {"number": 1, "title": "Winter Is Coming"} + season_data = {"number": 1, "episodes": [episode_data]} + show_data = {"title": "Game of Thrones", "seasons": [season_data]} + + mock_show = MockItem(show_data, [("tvdb", "121361")]) + list_data = {"121361": mock_show} + + # This should trigger the bug where 'list' is passed instead of 'list_data' + # and fail with AttributeError: type object 'list' has no attribute 'items' + result = utilities.findEpisodeMatchInList("121361", 1, 1, list_data, "tvdb") + assert result == episode_data