diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5cd5990..289bc98 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -53,7 +53,7 @@ jobs: docker-compose -f JellyPlex-Watched-CI/plex/docker-compose.yml up -d docker-compose -f JellyPlex-Watched-CI/jellyfin/docker-compose.yml up -d # Wait for containers to start - sleep 5 + sleep 10 docker-compose -f JellyPlex-Watched-CI/plex/docker-compose.yml logs docker-compose -f JellyPlex-Watched-CI/jellyfin/docker-compose.yml logs diff --git a/.gitignore b/.gitignore index 3093d0a..84d832d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -**.env +**.env* *.prof # Byte-compiled / optimized / DLL files diff --git a/src/jellyfin.py b/src/jellyfin.py index 23bdbb9..cfa0243 100644 --- a/src/jellyfin.py +++ b/src/jellyfin.py @@ -25,23 +25,34 @@ def get_guids(item): - guids = {"title": item["Name"]} + if item.get("Name"): + guids = {"title": item.get("Name")} + else: + logger(f"Jellyfin: Name not found in {item.get('Id')}", 1) + guids = {"title": None} if "ProviderIds" in item: guids.update({k.lower(): v for k, v in item["ProviderIds"].items()}) + else: + logger(f"Jellyfin: ProviderIds not found in {item.get('Name')}", 1) if "MediaSources" in item: guids["locations"] = tuple( [x["Path"].split("/")[-1] for x in item["MediaSources"] if "Path" in x] ) else: + logger(f"Jellyfin: MediaSources not found in {item.get('Name')}", 1) guids["locations"] = tuple() - guids["status"] = { - "completed": item["UserData"]["Played"], - # Convert ticks to milliseconds to match Plex - "time": floor(item["UserData"]["PlaybackPositionTicks"] / 10000), - } + if "UserData" in item: + guids["status"] = { + "completed": item["UserData"]["Played"], + # Convert ticks to milliseconds to match Plex + "time": floor(item["UserData"]["PlaybackPositionTicks"] / 10000), + } + else: + logger(f"Jellyfin: UserData not found in {item.get('Name')}", 1) + guids["status"] = {} return guids @@ -132,7 +143,7 @@ def query(self, query, query_type, session=None, identifiers=None): ) if response.status_code != 200: raise Exception( - f"Query failed with status {response.status} {response.reason}" + f"Query failed with status {response.status_code} {response.reason}" ) results = response.json() @@ -142,7 +153,7 @@ def query(self, query, query_type, session=None, identifiers=None): ) if response.status_code != 200: raise Exception( - f"Query failed with status {response.status} {response.reason}" + f"Query failed with status {response.status_code} {response.reason}" ) results = response.json() @@ -221,6 +232,9 @@ def get_user_library_watched( for movie in watched["Items"] + in_progress["Items"]: if "MediaSources" in movie and movie["MediaSources"] != {}: + if "UserData" not in movie: + continue + # Skip if not watched or watched less than a minute if ( movie["UserData"]["Played"] == True @@ -256,6 +270,9 @@ def get_user_library_watched( # Filter the list of shows to only include those that have been partially or fully watched watched_shows_filtered = [] for show in watched_shows["Items"]: + if not "UserData" in show: + continue + if "PlayedPercentage" in show["UserData"]: if show["UserData"]["PlayedPercentage"] > 0: watched_shows_filtered.append(show) @@ -613,7 +630,7 @@ def update_user_watched( else: logger( f"Jellyfin: Skipping movie {jellyfin_video.get('Name')} as it is not in mark list for {user_name}", - 1, + 3, ) # TV Shows diff --git a/src/plex.py b/src/plex.py index 548b5d6..e891809 100644 --- a/src/plex.py +++ b/src/plex.py @@ -64,11 +64,25 @@ def extract_guids_from_item(item: Union[Movie, Show, Episode]) -> Dict[str, str] def get_guids(item: Union[Movie, Episode], completed=True): + if not item.locations: + logger( + f"Plex: {item.title} has no locations", + 1, + ) + + if not item.guids: + logger( + f"Plex: {item.title} has no guids", + 1, + ) + return { "title": item.title, - "locations": tuple([location.split("/")[-1] for location in item.locations]) - if generate_locations - else tuple(), + "locations": ( + tuple([location.split("/")[-1] for location in item.locations]) + if generate_locations + else tuple() + ), "status": { "completed": completed, "time": item.viewOffset, @@ -84,11 +98,11 @@ def get_user_library_watched_show(show, process_episodes, threads=None): ( { "title": show.title, - "locations": tuple( - [location.split("/")[-1] for location in show.locations] - ) - if generate_locations - else tuple(), + "locations": ( + tuple([location.split("/")[-1] for location in show.locations]) + if generate_locations + else tuple() + ), } | extract_guids_from_item(show) ).items() # Merge the metadata and guid dictionaries diff --git a/src/watched.py b/src/watched.py index 57f020d..4d4f7cc 100644 --- a/src/watched.py +++ b/src/watched.py @@ -248,7 +248,7 @@ def filter_episode_watched_list_2_keys_dict( # Iterate through episode_watched_list_2_keys_dict["season"] and find the indecies that match season for season_index, season_value in enumerate( - episode_watched_list_2_keys_dict["season"] + episode_watched_list_2_keys_dict.get("season") ): if season_value == season: season_indecies.append(season_index)