From 9c97a8dd2169034279a000f2ca07a7e09464e10d Mon Sep 17 00:00:00 2001 From: joncrall Date: Sun, 3 Dec 2023 14:13:02 -0500 Subject: [PATCH 1/6] allow profile to be None in get_play_info --- jellyfin_apiclient_python/api.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/jellyfin_apiclient_python/api.py b/jellyfin_apiclient_python/api.py index 37e3fdb..1c66825 100644 --- a/jellyfin_apiclient_python/api.py +++ b/jellyfin_apiclient_python/api.py @@ -634,19 +634,24 @@ def get_sync_queue(self, date, filters=None): def get_server_time(self): return self._get("Jellyfin.Plugin.KodiSyncQueue/GetServerDateTime") - def get_play_info(self, item_id, profile, aid=None, sid=None, start_time_ticks=None, is_playback=True): + def get_play_info(self, item_id, profile=None, aid=None, sid=None, start_time_ticks=None, is_playback=True): args = { 'UserId': "{UserId}", - 'DeviceProfile': profile, 'AutoOpenLiveStream': is_playback, 'IsPlayback': is_playback } + if profile is None: + args['DeviceProfile'] = profile if sid: args['SubtitleStreamIndex'] = sid if aid: args['AudioStreamIndex'] = aid if start_time_ticks: args['StartTimeTicks'] = start_time_ticks + # TODO: + # Should this be a get? + # https://api.jellyfin.org/#tag/MediaInfo + # https://api.jellyfin.org/#tag/MediaInfo/operation/GetPostedPlaybackInfo return self.items("/%s/PlaybackInfo" % item_id, "POST", json=args) def get_live_stream(self, item_id, play_id, token, profile): From 51ef381dacceb20d4d664bc4f8bace04d02c69e3 Mon Sep 17 00:00:00 2001 From: joncrall Date: Mon, 11 Dec 2023 11:46:14 -0500 Subject: [PATCH 2/6] Add experimental API mixin --- jellyfin_apiclient_python/api.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/jellyfin_apiclient_python/api.py b/jellyfin_apiclient_python/api.py index 1c66825..6fdbb89 100644 --- a/jellyfin_apiclient_python/api.py +++ b/jellyfin_apiclient_python/api.py @@ -904,6 +904,29 @@ def identify(client, item_id, provider_ids): body = {'ProviderIds': provider_ids} return client.jellyfin.items('/RemoteSearch/Apply/' + item_id, action='POST', params=None, json=body) + def get_now_playing(self, session_id): + """ + Simplified API to get now playing information for a session including the + play state. + + References: + https://github.com/jellyfin/jellyfin/issues/9665 + """ + resp = self.sessions(params={ + 'Id': session_id, + 'fields': ['PlayState'] + }) + found = None + for item in resp: + if item['Id'] == session_id: + found = item + if not found: + raise KeyError(f'No session_id={session_id}') + play_state = found['PlayState'] + now_playing = found['NowPlayingItem'] + now_playing['PlayState'] = play_state + return now_playing + class CollectionAPIMixin: """ From 9a9acac992bdaab31799117e7689bd3fc1c52ccd Mon Sep 17 00:00:00 2001 From: joncrall Date: Thu, 12 Sep 2024 15:53:39 -0400 Subject: [PATCH 3/6] Fix NowPlaying --- jellyfin_apiclient_python/api.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/jellyfin_apiclient_python/api.py b/jellyfin_apiclient_python/api.py index 6fdbb89..5704fce 100644 --- a/jellyfin_apiclient_python/api.py +++ b/jellyfin_apiclient_python/api.py @@ -923,7 +923,10 @@ def get_now_playing(self, session_id): if not found: raise KeyError(f'No session_id={session_id}') play_state = found['PlayState'] - now_playing = found['NowPlayingItem'] + now_playing = found.get('NowPlayingItem', None) + if now_playing is None: + # handle case if nothing is playing + now_playing = {'Name': None} now_playing['PlayState'] = play_state return now_playing From 01e252bc56c65b2db43bbca0003a4dce55cbd385 Mon Sep 17 00:00:00 2001 From: joncrall Date: Thu, 12 Sep 2024 17:03:14 -0400 Subject: [PATCH 4/6] Add API calls for log files --- jellyfin_apiclient_python/api.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/jellyfin_apiclient_python/api.py b/jellyfin_apiclient_python/api.py index 5704fce..d5ecd25 100644 --- a/jellyfin_apiclient_python/api.py +++ b/jellyfin_apiclient_python/api.py @@ -547,6 +547,34 @@ def favorite(self, item_id, option=True): def get_system_info(self): return self._get("System/Configuration") + def get_server_logs(self): + """ + Returns: + List[Dict] - list of information about available log files + + References: + .. [GetServerLogs] https://api.jellyfin.org/#tag/System/operation/GetServerLogs + """ + return self._get("System/Logs") + + def get_log_entries(self, startIndex=None, limit=None, minDate=None, hasUserId=None): + """ + Returns a list of recent log entries + + Returns: + Dict: with main key "Items" + """ + params = {} + if limit is not None: + params['limit'] = limit + if startIndex is not None: + params['startIndex'] = startIndex + if minDate is not None: + params['minDate'] = minDate + if hasUserId is not None: + params['hasUserId'] = hasUserId + return self._get("System/ActivityLog/Entries", params=params) + def post_capabilities(self, data): return self.sessions("/Capabilities/Full", "POST", json=data) From 34f76c15b9303b717bf7019cefd72ee3e6a6a830 Mon Sep 17 00:00:00 2001 From: joncrall Date: Thu, 12 Sep 2024 16:44:22 -0400 Subject: [PATCH 5/6] Add add_media_library --- jellyfin_apiclient_python/api.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/jellyfin_apiclient_python/api.py b/jellyfin_apiclient_python/api.py index d5ecd25..10b1899 100644 --- a/jellyfin_apiclient_python/api.py +++ b/jellyfin_apiclient_python/api.py @@ -146,6 +146,31 @@ def refresh_library(self): """ return self._post("Library/Refresh") + def add_media_library(self, name, collectionType, paths, refreshLibrary=True): + """ + Create a new media library. + + Args: + name (str): name of the new library + + collectionType (str): one of "movies" "tvshows" "music" "musicvideos" + "homevideos" "boxsets" "books" "mixed" + + paths (List[str]): + paths on the server to use in the media library + + References: + ..[AddVirtualFolder] https://api.jellyfin.org/#tag/LibraryStructure/operation/AddVirtualFolder + """ + params = { + 'name': name, + 'collectionType': collectionType, + 'paths': paths, + 'refreshLibrary': refreshLibrary, + + } + return self.virtual_folders('POST', params=params) + def items(self, handler="", action="GET", params=None, json=None): if action == "POST": return self._post("Items%s" % handler, json, params) From 835af4944e553380409d8eaaa9de48f8caf46573 Mon Sep 17 00:00:00 2001 From: joncrall Date: Thu, 12 Sep 2024 16:56:21 -0400 Subject: [PATCH 6/6] Fix formatting --- jellyfin_apiclient_python/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jellyfin_apiclient_python/api.py b/jellyfin_apiclient_python/api.py index 10b1899..1328b56 100644 --- a/jellyfin_apiclient_python/api.py +++ b/jellyfin_apiclient_python/api.py @@ -160,7 +160,7 @@ def add_media_library(self, name, collectionType, paths, refreshLibrary=True): paths on the server to use in the media library References: - ..[AddVirtualFolder] https://api.jellyfin.org/#tag/LibraryStructure/operation/AddVirtualFolder + .. [AddVirtualFolder] https://api.jellyfin.org/#tag/LibraryStructure/operation/AddVirtualFolder """ params = { 'name': name,