diff --git a/src/emby.py b/src/emby.py index 5e0ba82..ddcd0c5 100644 --- a/src/emby.py +++ b/src/emby.py @@ -1,4 +1,5 @@ from src.jellyfin_emby import JellyfinEmby +from packaging import version class Emby(JellyfinEmby): @@ -8,7 +9,7 @@ class Emby(JellyfinEmby): 'Client="JellyPlex-Watched", ' 'Device="script", ' 'DeviceId="script", ' - 'Version="0.0.0"' + 'Version="6.0.2"' ) headers = { "Accept": "application/json", @@ -19,3 +20,6 @@ class Emby(JellyfinEmby): super().__init__( server_type="Emby", baseurl=baseurl, token=token, headers=headers ) + + def is_partial_update_supported(self, server_version): + return server_version > version.parse("4.4") diff --git a/src/jellyfin.py b/src/jellyfin.py index 282beea..7424613 100644 --- a/src/jellyfin.py +++ b/src/jellyfin.py @@ -1,5 +1,5 @@ from src.jellyfin_emby import JellyfinEmby - +from packaging import version class Jellyfin(JellyfinEmby): def __init__(self, baseurl, token): @@ -8,7 +8,7 @@ class Jellyfin(JellyfinEmby): 'Client="JellyPlex-Watched", ' 'Device="script", ' 'DeviceId="script", ' - 'Version="5.2.0", ' + 'Version="6.0.2", ' f'Token="{token}"' ) headers = { @@ -19,3 +19,6 @@ class Jellyfin(JellyfinEmby): super().__init__( server_type="Jellyfin", baseurl=baseurl, token=token, headers=headers ) + + def is_partial_update_supported(self, server_version): + return server_version >= version.parse("10.9.0") diff --git a/src/jellyfin_emby.py b/src/jellyfin_emby.py index f50f591..390bf63 100644 --- a/src/jellyfin_emby.py +++ b/src/jellyfin_emby.py @@ -125,7 +125,6 @@ class JellyfinEmby: raise Exception(f"{self.server_type} token not set") self.session = requests.Session() - self.version = version.parse(self.info(version=True)) self.users = self.get_users() def query(self, query, query_type, identifiers=None, json=None): @@ -178,17 +177,13 @@ class JellyfinEmby: ) raise Exception(e) - def info(self, version=False) -> str: + def info(self) -> str: try: query_string = "/System/Info/Public" response = self.query(query_string, "get") if response: - # Return version only if requested - if version: - return response['Version'] - return f"{self.server_type} {response['ServerName']}: {response['Version']}" else: return None @@ -197,6 +192,19 @@ class JellyfinEmby: logger(f"{self.server_type}: Get server name failed {e}", 2) raise Exception(e) + def get_server_version(self): + try: + response = self.query('/System/Info/Public', 'get') + + if response: + return version.parse(response['Version']) + else: + return None + + except Exception as e: + logger(f"{self.server_type}: Get server version failed: {e}", 2) + raise Exception(e) + def get_users(self): try: users = {} @@ -505,7 +513,7 @@ class JellyfinEmby: raise Exception(e) def update_user_watched( - self, user_name, user_id, library, library_id, videos, dryrun + self, user_name, user_id, library, library_id, videos, update_partial, dryrun ): try: logger( @@ -565,33 +573,29 @@ class JellyfinEmby: library, jellyfin_video.get("Name"), ) - else: - # Handle partially watched movies not supported in jellyfin < 10.9.0 - if self.server_type == "Jellyfin" and self.version < version.parse("10.9.0"): - logger(f"{self.server_type}: Skipping movie {jellyfin_video.get('Name')} as partially watched not supported in Jellyfin < 10.9.0", 4) - else: - msg = f"{self.server_type}: {jellyfin_video.get('Name')} as partially watched for {floor(movie_status['time'] / 60_000)} minutes for {user_name} in {library}" + elif update_partial: + msg = f"{self.server_type}: {jellyfin_video.get('Name')} as partially watched for {floor(movie_status['time'] / 60_000)} minutes for {user_name} in {library}" - if not dryrun: - logger(msg, 5) - playback_position_payload = { - "PlaybackPositionTicks": movie_status["time"] - * 10_000, - } - self.query( - f"/Users/{user_id}/Items/{jellyfin_video_id}/UserData", - "post", - json=playback_position_payload, - ) - else: - logger(msg, 6) - - log_marked( - user_name, - library, - jellyfin_video.get("Name"), - duration=floor(movie_status["time"] / 60_000), + if not dryrun: + logger(msg, 5) + playback_position_payload = { + "PlaybackPositionTicks": movie_status["time"] + * 10_000, + } + self.query( + f"/Users/{user_id}/Items/{jellyfin_video_id}/UserData", + "post", + json=playback_position_payload, ) + else: + logger(msg, 6) + + log_marked( + user_name, + library, + jellyfin_video.get("Name"), + duration=floor(movie_status["time"] / 60_000), + ) else: logger( f"{self.server_type}: Skipping movie {jellyfin_video.get('Name')} as it is not in mark list for {user_name}", @@ -698,39 +702,35 @@ class JellyfinEmby: jellyfin_episode.get("SeriesName"), jellyfin_episode.get("Name"), ) - else: - # Handle partially watched episodes not supported in jellyfin < 10.9.0 - if self.server_type == "Jellyfin" and self.version < version.parse("10.9.0"): - logger(f"{self.server_type}: Skipping episode {jellyfin_episode.get('Name')} as partially watched not supported in Jellyfin < 10.9.0", 4) + elif update_partial: + msg = ( + f"{self.server_type}: {jellyfin_episode['SeriesName']} {jellyfin_episode['SeasonName']} Episode {jellyfin_episode.get('IndexNumber')} {jellyfin_episode.get('Name')}" + + f" as partially watched for {floor(episode_status['time'] / 60_000)} minutes for {user_name} in {library}" + ) + + if not dryrun: + logger(msg, 5) + playback_position_payload = { + "PlaybackPositionTicks": episode_status[ + "time" + ] + * 10_000, + } + self.query( + f"/Users/{user_id}/Items/{jellyfin_episode_id}/UserData", + "post", + json=playback_position_payload, + ) else: - msg = ( - f"{self.server_type}: {jellyfin_episode['SeriesName']} {jellyfin_episode['SeasonName']} Episode {jellyfin_episode.get('IndexNumber')} {jellyfin_episode.get('Name')}" - + f" as partially watched for {floor(episode_status['time'] / 60_000)} minutes for {user_name} in {library}" - ) + logger(msg, 6) - if not dryrun: - logger(msg, 5) - playback_position_payload = { - "PlaybackPositionTicks": episode_status[ - "time" - ] - * 10_000, - } - self.query( - f"/Users/{user_id}/Items/{jellyfin_episode_id}/UserData", - "post", - json=playback_position_payload, - ) - else: - logger(msg, 6) - - log_marked( - user_name, - library, - jellyfin_episode.get("SeriesName"), - jellyfin_episode.get("Name"), - duration=floor(episode_status["time"] / 60_000), - ) + log_marked( + user_name, + library, + jellyfin_episode.get("SeriesName"), + jellyfin_episode.get("Name"), + duration=floor(episode_status["time"] / 60_000), + ) else: logger( f"{self.server_type}: Skipping episode {jellyfin_episode.get('Name')} as it is not in mark list for {user_name}", @@ -754,6 +754,15 @@ class JellyfinEmby: self, watched_list, user_mapping=None, library_mapping=None, dryrun=False ): try: + server_version = self.get_server_version() + update_partial = self.is_partial_update_supported(server_version) + + if not update_partial: + logger( + f"{self.server_type}: Server version {server_version} does not support updating playback position.", + 2, + ) + for user, libraries in watched_list.items(): logger(f"{self.server_type}: Updating for entry {user}, {libraries}", 1) user_other = None @@ -826,7 +835,13 @@ class JellyfinEmby: if library_id: self.update_user_watched( - user_name, user_id, library, library_id, videos, dryrun + user_name, + user_id, + library, + library_id, + videos, + update_partial, + dryrun ) except Exception as e: