diff --git a/resources/lib/emby/client.py b/resources/lib/emby/client.py index f5a2847c..d78fc07d 100644 --- a/resources/lib/emby/client.py +++ b/resources/lib/emby/client.py @@ -17,6 +17,7 @@ LOG = logging.getLogger('Emby.'+__name__) ################################################################################################# def callback(message, data): + ''' Callback function should received message, data message: string data: json dictionary @@ -35,8 +36,7 @@ class EmbyClient(object): self.http = HTTP(self) self.wsc = WSClient(self) self.auth = ConnectionManager(self) - self.emby = api - self.emby.client = self.http + self.emby = api.API(self.http) self.callback_ws = callback self.callback = callback @@ -100,8 +100,6 @@ class EmbyClient(object): return self.auth.__shortcuts__(key.replace('auth/', "", 1)) elif key.startswith('api'): - self.emby.client = self.http # Since api is not a class, re-assign global var to correct http adapter - return self.emby elif key == 'connected': diff --git a/resources/lib/emby/core/api.py b/resources/lib/emby/core/api.py index 8a537953..7dbdc19a 100644 --- a/resources/lib/emby/core/api.py +++ b/resources/lib/emby/core/api.py @@ -2,25 +2,7 @@ ################################################################################################# -client = None - -################################################################################################# - -def _http(action, url, request={}): - request.update({'type': action, 'handler': url}) - - return client.request(request) - -def _get(handler, params=None): - return _http("GET", handler, {'params': params}) - -def _post(handler, json=None, params=None): - return _http("POST", handler, {'params': params, 'json': json}) - -def _delete(handler, params=None): - return _http("DELETE", handler, {'params': params}) - -def emby_url(handler): +def emby_url(client, handler): return "%s/emby/%s" % (client.config['auth.server'], handler) def basic_info(): @@ -45,295 +27,318 @@ def music_info(): ################################################################################################# -# Bigger section of the Emby api +class API(object): -################################################################################################# + ''' All the api calls to the server. + ''' + def __init__(self, client, *args, **kwargs): + self.client = client -def try_server(): - return _get("System/Info/Public") + def _http(self, action, url, request={}): + request.update({'type': action, 'handler': url}) -def sessions(handler="", action="GET", params=None, json=None): + return self.client.request(request) - if action == "POST": - return _post("Sessions%s" % handler, json, params) - elif action == "DELETE": - return _delete("Sessions%s" % handler, params) - else: - return _get("Sessions%s" % handler, params) + def _get(self, handler, params=None): + return self._http("GET", handler, {'params': params}) -def users(handler="", action="GET", params=None, json=None): + def _post(self, handler, json=None, params=None): + return self._http("POST", handler, {'params': params, 'json': json}) - if action == "POST": - return _post("Users/{UserId}%s" % handler, json, params) - elif action == "DELETE": - return _delete("Users/{UserId}%s" % handler, params) - else: - return _get("Users/{UserId}%s" % handler, params) + def _delete(self, handler, params=None): + return self._http("DELETE", handler, {'params': params}) -def items(handler="", action="GET", params=None, json=None): - - if action == "POST": - return _post("Items%s" % handler, json, params) - elif action == "DELETE": - return _delete("Items%s" % handler, params) - else: - return _get("Items%s" % handler, params) + ################################################################################################# -def user_items(handler="", params=None): - return users("/Items%s" % handler, params=params) + # Bigger section of the Emby api -def shows(handler, params): - return _get("Shows%s" % handler, params) + ################################################################################################# -def videos(handler): - return _get("Videos%s" % handler) + def try_server(self): + return self._get("System/Info/Public") -def artwork(item_id, art, max_width, ext="jpg", index=None): + def sessions(self, handler="", action="GET", params=None, json=None): - if index is None: - return emby_url("Items/%s/Images/%s?MaxWidth=%s&format=%s" % (item_id, art, max_width, ext)) + if action == "POST": + return self._post("Sessions%s" % handler, json, params) + elif action == "DELETE": + return self._delete("Sessions%s" % handler, params) + else: + return self._get("Sessions%s" % handler, params) - return emby_url("Items/%s/Images/%s/%s?MaxWidth=%s&format=%s" % (item_id, art, index, max_width, ext)) + def users(self, handler="", action="GET", params=None, json=None): -################################################################################################# + if action == "POST": + return self._post("Users/{UserId}%s" % handler, json, params) + elif action == "DELETE": + return self._delete("Users/{UserId}%s" % handler, params) + else: + return self._get("Users/{UserId}%s" % handler, params) -# More granular api + def items(self, handler="", action="GET", params=None, json=None): + + if action == "POST": + return self._post("Items%s" % handler, json, params) + elif action == "DELETE": + return self._delete("Items%s" % handler, params) + else: + return self._get("Items%s" % handler, params) -################################################################################################# + def user_items(self, handler="", params=None): + return self.users("/Items%s" % handler, params=params) -def get_users(): - return _get("Users") + def shows(self, handler, params): + return self._get("Shows%s" % handler, params) -def get_public_users(): - return _get("Users/Public") + def videos(self, handler): + return self._get("Videos%s" % handler) -def get_user(user_id=None): - return users() if user_id is None else _get("Users/%s" % user_id) + def artwork(self, item_id, art, max_width, ext="jpg", index=None): -def get_views(): - return users("/Views") + if index is None: + return emby_url(self.client, "Items/%s/Images/%s?MaxWidth=%s&format=%s" % (item_id, art, max_width, ext)) -def get_media_folders(): - return users("/Items") + return emby_url(self.client, "Items/%s/Images/%s/%s?MaxWidth=%s&format=%s" % (item_id, art, index, max_width, ext)) -def get_item(item_id): - return users("/Items/%s" % item_id) + ################################################################################################# -def get_items(item_ids): - return users("/Items", params={ - 'Ids': ','.join(str(x) for x in item_ids), - 'Fields': info() - }) + # More granular api -def get_sessions(): - return sessions(params={'ControllableByUserId': "{UserId}"}) + ################################################################################################# -def get_device(device_id): - return sessions(params={'DeviceId': device_id}) + def get_users(self): + return self._get("Users") -def post_session(session_id, url, params=None, data=None): - return sessions("/%s/%s" % (session_id, url), "POST", params, data) + def get_public_users(self): + return self._get("Users/Public") -def get_images(item_id): - return items("/%s/Images" % item_id) + def get_user(self, user_id=None): + return self.users() if user_id is None else self._get("Users/%s" % user_id) -def get_suggestion(media="Movie,Episode", limit=1): - return users("/Suggestions", { - 'Type': media, - 'Limit': limit - }) + def get_views(self): + return self.users("/Views") -def get_recently_added(media=None, parent_id=None, limit=20): - return user_items("/Latest", { - 'Limit': limit, - 'UserId': "{UserId}", - 'IncludeItemTypes': media, - 'ParentId': parent_id, - 'Fields': info() - }) + def get_media_folders(self): + return self.users("/Items") -def get_next(index=None, limit=1): - return shows("/NextUp", { - 'Limit': limit, - 'UserId': "{UserId}", - 'StartIndex': None if index is None else int(index) - }) + def get_item(self, item_id): + return self.users("/Items/%s" % item_id) -def get_adjacent_episodes(show_id, item_id): - return shows("/%s/Episodes" % show_id, { - 'UserId': "{UserId}", - 'AdjacentTo': item_id, - 'Fields': "Overview" - }) + def get_items(self, item_ids): + return self.users("/Items", params={ + 'Ids': ','.join(str(x) for x in item_ids), + 'Fields': info() + }) -def get_genres(parent_id=None): - return _get("Genres", { - 'ParentId': parent_id, - 'UserId': "{UserId}", - 'Fields': info() - }) + def get_sessions(self): + return self.sessions(params={'ControllableByUserId': "{UserId}"}) -def get_recommendation(parent_id=None, limit=20): - return _get("Movies/Recommendations", { - 'ParentId': parent_id, - 'UserId': "{UserId}", - 'Fields': info(), - 'Limit': limit - }) + def get_device(self, device_id): + return self.sessions(params={'DeviceId': device_id}) -def get_items_by_letter(parent_id=None, media=None, letter=None): - return user_items(params={ - 'ParentId': parent_id, - 'NameStartsWith': letter, - 'Fields': info(), - 'Recursive': True, - 'IncludeItemTypes': media - }) + def post_session(self, session_id, url, params=None, data=None): + return self.sessions("/%s/%s" % (session_id, url), "POST", params, data) -def get_channels(): - return _get("LiveTv/Channels", { - 'UserId': "{UserId}", - 'EnableImages': True, - 'EnableUserData': True - }) + def get_images(self, item_id): + return self.items("/%s/Images" % item_id) -def get_intros(item_id): - return user_items("/%s/Intros" % item_id) + def get_suggestion(self, media="Movie,Episode", limit=1): + return self.users("/Suggestions", { + 'Type': media, + 'Limit': limit + }) -def get_additional_parts(item_id): - return videos("/%s/AdditionalParts" % item_id) + def get_recently_added(self, media=None, parent_id=None, limit=20): + return self.user_items("/Latest", { + 'Limit': limit, + 'UserId': "{UserId}", + 'IncludeItemTypes': media, + 'ParentId': parent_id, + 'Fields': info() + }) -def delete_item(item_id): - return items("/%s" % item_id, "DELETE") + def get_next(self, index=None, limit=1): + return self.shows("/NextUp", { + 'Limit': limit, + 'UserId': "{UserId}", + 'StartIndex': None if index is None else int(index) + }) -def get_local_trailers(item_id): - return user_items("/%s/LocalTrailers" % item_id) + def get_adjacent_episodes(self, show_id, item_id): + return self.shows("/%s/Episodes" % show_id, { + 'UserId': "{UserId}", + 'AdjacentTo': item_id, + 'Fields': "Overview" + }) -def get_transcode_settings(): - return _get('System/Configuration/encoding') + def get_genres(self, parent_id=None): + return self._get("Genres", { + 'ParentId': parent_id, + 'UserId': "{UserId}", + 'Fields': info() + }) -def get_ancestors(item_id): - return items("/%s/Ancestors" % item_id, params={ - 'UserId': "{UserId}" - }) + def get_recommendation(self, parent_id=None, limit=20): + return self._get("Movies/Recommendations", { + 'ParentId': parent_id, + 'UserId': "{UserId}", + 'Fields': info(), + 'Limit': limit + }) -def get_items_theme_video(parent_id): - return users("/Items", params={ - 'HasThemeVideo': True, - 'ParentId': parent_id - }) + def get_items_by_letter(self, parent_id=None, media=None, letter=None): + return self.user_items(params={ + 'ParentId': parent_id, + 'NameStartsWith': letter, + 'Fields': info(), + 'Recursive': True, + 'IncludeItemTypes': media + }) -def get_themes(item_id): - return items("/%s/ThemeMedia" % item_id, params={ - 'UserId': "{UserId}", - 'InheritFromParent': True - }) + def get_channels(self): + return self._get("LiveTv/Channels", { + 'UserId': "{UserId}", + 'EnableImages': True, + 'EnableUserData': True + }) -def get_items_theme_song(parent_id): - return users("/Items", params={ - 'HasThemeSong': True, - 'ParentId': parent_id - }) + def get_intros(self, item_id): + return self.user_items("/%s/Intros" % item_id) -def get_plugins(): - return _get("Plugins") + def get_additional_parts(self, item_id): + return self.videos("/%s/AdditionalParts" % item_id) -def get_seasons(show_id): - return shows("/%s/Seasons" % show_id, params={ - 'UserId': "{UserId}", - 'EnableImages': True, - 'Fields': info() - }) + def delete_item(self, item_id): + return self.items("/%s" % item_id, "DELETE") -def get_date_modified(date, parent_id, media=None): - return users("/Items", params={ - 'ParentId': parent_id, - 'Recursive': False, - 'IsMissing': False, - 'IsVirtualUnaired': False, - 'IncludeItemTypes': media or None, - 'MinDateLastSaved': date, - 'Fields': info() - }) + def get_local_trailers(self, item_id): + return self.user_items("/%s/LocalTrailers" % item_id) -def get_userdata_date_modified(date, parent_id, media=None): - return users("/Items", params={ - 'ParentId': parent_id, - 'Recursive': True, - 'IsMissing': False, - 'IsVirtualUnaired': False, - 'IncludeItemTypes': media or None, - 'MinDateLastSavedForUser': date, - 'Fields': info() - }) + def get_transcode_settings(self): + return self._get('System/Configuration/encoding') -def refresh_item(item_id): - return items("/%s/Refresh" % item_id, "POST", json={ - 'Recursive': True, - 'ImageRefreshMode': "FullRefresh", - 'MetadataRefreshMode': "FullRefresh", - 'ReplaceAllImages': False, - 'ReplaceAllMetadata': True - }) + def get_ancestors(self, item_id): + return self.items("/%s/Ancestors" % item_id, params={ + 'UserId': "{UserId}" + }) -def favorite(item_id, option=True): - return users("/FavoriteItems/%s" % item_id, "POST" if option else "DELETE") + def get_items_theme_video(self, parent_id): + return self.users("/Items", params={ + 'HasThemeVideo': True, + 'ParentId': parent_id + }) -def get_system_info(): - return _get("System/Configuration") + def get_themes(self, item_id): + return self.items("/%s/ThemeMedia" % item_id, params={ + 'UserId': "{UserId}", + 'InheritFromParent': True + }) -def post_capabilities(data): - return sessions("/Capabilities/Full", "POST", json=data) + def get_items_theme_song(self, parent_id): + return self.users("/Items", params={ + 'HasThemeSong': True, + 'ParentId': parent_id + }) -def session_add_user(session_id, user_id, option=True): - return sessions("/%s/Users/%s" % (session_id, user_id), "POST" if option else "DELETE") + def get_plugins(self): + return self._get("Plugins") -def session_playing(data): - return sessions("/Playing", "POST", json=data) + def get_seasons(self, show_id): + return self.shows("/%s/Seasons" % show_id, params={ + 'UserId': "{UserId}", + 'EnableImages': True, + 'Fields': info() + }) -def session_progress(data): - return sessions("/Playing/Progress", "POST", json=data) + def get_date_modified(self, date, parent_id, media=None): + return self.users("/Items", params={ + 'ParentId': parent_id, + 'Recursive': False, + 'IsMissing': False, + 'IsVirtualUnaired': False, + 'IncludeItemTypes': media or None, + 'MinDateLastSaved': date, + 'Fields': info() + }) -def session_stop(data): - return sessions("/Playing/Stopped", "POST", json=data) + def get_userdata_date_modified(self, date, parent_id, media=None): + return self.users("/Items", params={ + 'ParentId': parent_id, + 'Recursive': True, + 'IsMissing': False, + 'IsVirtualUnaired': False, + 'IncludeItemTypes': media or None, + 'MinDateLastSavedForUser': date, + 'Fields': info() + }) -def item_played(item_id, watched): - return users("/PlayedItems/%s" % item_id, "POST" if watched else "DELETE") + def refresh_item(self, item_id): + return self.items("/%s/Refresh" % item_id, "POST", json={ + 'Recursive': True, + 'ImageRefreshMode': "FullRefresh", + 'MetadataRefreshMode': "FullRefresh", + 'ReplaceAllImages': False, + 'ReplaceAllMetadata': True + }) -def get_sync_queue(date, filters=None): - return _get("Emby.Kodi.SyncQueue/{UserId}/GetItems", params={ - 'LastUpdateDT': date, - 'filter': filters or None - }) + def favorite(self, item_id, option=True): + return self.users("/FavoriteItems/%s" % item_id, "POST" if option else "DELETE") -def get_server_time(): - return _get("Emby.Kodi.SyncQueue/GetServerDateTime") + def get_system_info(self): + return self._get("System/Configuration") -def get_play_info(item_id, profile): - return items("/%s/PlaybackInfo" % item_id, "POST", json={ - 'UserId': "{UserId}", - 'DeviceProfile': profile, - 'AutoOpenLiveStream': True - }) + def post_capabilities(self, data): + return self.sessions("/Capabilities/Full", "POST", json=data) -def get_live_stream(item_id, play_id, token, profile): - return _post("LiveStreams/Open", json={ - 'UserId': "{UserId}", - 'DeviceProfile': profile, - 'OpenToken': token, - 'PlaySessionId': play_id, - 'ItemId': item_id - }) + def session_add_user(self, session_id, user_id, option=True): + return self.sessions("/%s/Users/%s" % (session_id, user_id), "POST" if option else "DELETE") -def close_live_stream(live_id): - return _post("LiveStreams/Close", json={ - 'LiveStreamId': live_id - }) + def session_playing(self, data): + return self.sessions("/Playing", "POST", json=data) -def close_transcode(device_id): - return _delete("Videos/ActiveEncodings", params={ - 'DeviceId': device_id - }) + def session_progress(self, data): + return self.sessions("/Playing/Progress", "POST", json=data) -def delete_item(item_id): - return items("/%s" % item_id, "DELETE") + def session_stop(self, data): + return self.sessions("/Playing/Stopped", "POST", json=data) + + def item_played(self, item_id, watched): + return self.users("/PlayedItems/%s" % item_id, "POST" if watched else "DELETE") + + def get_sync_queue(self, date, filters=None): + return self._get("Emby.Kodi.SyncQueue/{UserId}/GetItems", params={ + 'LastUpdateDT': date, + 'filter': filters or None + }) + + def get_server_time(self): + return self._get("Emby.Kodi.SyncQueue/GetServerDateTime") + + def get_play_info(self, item_id, profile): + return self.items("/%s/PlaybackInfo" % item_id, "POST", json={ + 'UserId': "{UserId}", + 'DeviceProfile': profile, + 'AutoOpenLiveStream': True + }) + + def get_live_stream(self, item_id, play_id, token, profile): + return self._post("LiveStreams/Open", json={ + 'UserId': "{UserId}", + 'DeviceProfile': profile, + 'OpenToken': token, + 'PlaySessionId': play_id, + 'ItemId': item_id + }) + + def close_live_stream(self, live_id): + return self._post("LiveStreams/Close", json={ + 'LiveStreamId': live_id + }) + + def close_transcode(self, device_id): + return self._delete("Videos/ActiveEncodings", params={ + 'DeviceId': device_id + }) + + def delete_item(self, item_id): + return self.items("/%s" % item_id, "DELETE")