From ef16562e7a9c4e6773d56c7699da6c01dc95ddfc Mon Sep 17 00:00:00 2001 From: quickmic Date: Fri, 9 Apr 2021 13:51:07 +0000 Subject: [PATCH] plugin.video.emby-next-gen-5.2.06-build 156 (ex26) --- addon.xml | 2 +- context.py | 19 +- core/artwork.py | 51 +- core/common.py | 47 +- core/listitem.py | 1182 +++++++++---------------------- core/movies.py | 162 ++--- core/music.py | 160 ++--- core/musicvideos.py | 94 ++- core/obj_ops.py | 36 +- core/queries_videos.py | 10 + core/tvshows.py | 247 +++---- database/database.py | 159 +---- database/library.py | 322 ++++----- database/queries.py | 10 +- database/sync.py | 300 ++++---- dialogs/context.py | 3 +- dialogs/serverconnect.py | 3 +- emby/connect.py | 176 +++-- emby/core/api.py | 245 ++++++- emby/core/configuration.py | 61 -- emby/core/connection_manager.py | 41 +- emby/core/http.py | 18 +- emby/core/ws_client.py | 9 +- emby/downloader.py | 252 ------- emby/main.py | 78 +- emby/views.py | 293 ++++---- events.py | 234 ++---- helper/api.py | 64 +- helper/loghandler.py | 20 - helper/setup.py | 83 +-- helper/utils.py | 139 +++- helper/xmls.py | 30 +- hooks/monitor.py | 360 ++++------ hooks/player.py | 484 ++++++++----- resources/settings.xml | 18 +- service.py | 22 +- 36 files changed, 2362 insertions(+), 3072 deletions(-) delete mode 100644 emby/core/configuration.py delete mode 100644 emby/downloader.py diff --git a/addon.xml b/addon.xml index 760717bdd..d520dd756 100644 --- a/addon.xml +++ b/addon.xml @@ -1,5 +1,5 @@ - + diff --git a/context.py b/context.py index f01334a6d..84d5ea7c3 100644 --- a/context.py +++ b/context.py @@ -35,19 +35,9 @@ def __init__(self, delete=False): self.media = xbmc.getInfoLabel('ListItem.DBTYPE') item_id = None - - - - - if not self.set_server(): return - - - - - if item_id: self.item = self.EmbyServer[self.server_id].API.get_item(item_id) else: @@ -77,10 +67,9 @@ def set_server(self): for _ in range(60): if self.Utils.window('emby.server.%s.online.bool' % server_id): ServerOnline = True - self.EmbyServer[server_id] = emby.main.Emby(server_id) - ServerData = self.Utils.window('emby.server.%s.state.json' % server_id) - self.EmbyServer[server_id].set_state(ServerData) - self.EmbyServerName[server_id] = ServerData['config']['auth.server-name'] + self.EmbyServer[server_id] = emby.main.Emby(self.Utils, server_id) + self.EmbyServer[server_id].set_state() + self.EmbyServerName[server_id] = self.EmbyServer[server_id].Data['auth.server-name'] break xbmc.sleep(500) @@ -158,7 +147,7 @@ def delete_item(self): if delete: self.EmbyServer[self.server_id].API.delete_item(self.item['Id']) - self.Utils.event("LibraryChanged", {'ItemsRemoved': [self.item['Id']], 'ItemsVerify': [self.item['Id']], 'ItemsUpdated': [], 'ItemsAdded': []}) + self.Utils.event("LibraryChanged", {'ServerId' : self.server_id, 'ItemsRemoved': [self.item['Id']], 'ItemsVerify': [self.item['Id']], 'ItemsUpdated': [], 'ItemsAdded': []}) if __name__ == "__main__": Context() diff --git a/core/artwork.py b/core/artwork.py index 550cb8c56..908392f34 100644 --- a/core/artwork.py +++ b/core/artwork.py @@ -37,21 +37,21 @@ def update(self, image_url, kodi_id, media, image): if image == 'poster' and media in ('song', 'artist', 'album'): return - try: - self.cursor.execute(queries_videos.get_art, (kodi_id, media, image,)) - url = self.cursor.fetchone()[0] - except TypeError: - self.LOG.debug("ADD to kodi_id %s art: %s" % (kodi_id, image_url)) - self.cursor.execute(queries_videos.add_art, (kodi_id, media, image, image_url)) - else: - if url != image_url: - self.delete_cache(url) + self.cursor.execute(queries_videos.get_art, (kodi_id, media, image,)) + result = self.cursor.fetchone() - if not image_url: - return + if result: + url = result[0] - self.LOG.info("UPDATE to kodi_id %s art: %s" % (kodi_id, image_url)) - self.cursor.execute(queries_videos.update_art, (image_url, kodi_id, media, image)) + if url != image_url: + self.delete_cache(url, False) + + if image_url: + self.LOG.info("UPDATE to kodi_id %s art: %s" % (kodi_id, image_url)) + self.cursor.execute(queries_videos.update_art, (image_url, kodi_id, media, image)) + else: + self.LOG.debug("ADD to kodi_id %s art: %s" % (kodi_id, image_url)) + self.cursor.execute(queries_videos.add_art, (kodi_id, media, image, image_url)) #Add all artworks def add(self, artwork, *args): @@ -88,29 +88,30 @@ def delete(self, *args): self.cursor.execute(queries_videos.get_art_url, args) for row in self.cursor.fetchall(): - self.delete_cache(row[0]) + self.delete_cache(row[0], True) #Delete cached artwork - def delete_cache(self, url): + def delete_cache(self, url, CompleteRemove): with database.database.Database(self.Utils, 'texture', True) as texturedb: cursor = texturedb.cursor + cursor.execute(queries_texture.get_cache, (url,)) + result = cursor.fetchone() - try: - cursor.execute(queries_texture.get_cache, (url,)) - cached = cursor.fetchone()[0] - except TypeError: - self.LOG.debug("Could not find cached url: %s" % url) - else: + if result: + cached = result[0] thumbnails = self.Utils.translatePath("special://thumbnails/%s" % cached) xbmcvfs.delete(thumbnails) cursor.execute(queries_texture.delete_cache, (url,)) - if self.is_music: - self.cursor.execute(queries_music.delete_artwork, (url,)) - else: - self.cursor.execute(queries_videos.delete_artwork, (url,)) + if CompleteRemove: + if self.is_music: + self.cursor.execute(queries_music.delete_artwork, (url,)) + else: + self.cursor.execute(queries_videos.delete_artwork, (url,)) self.LOG.info("DELETE cached %s" % cached) + else: + self.LOG.debug("Could not find cached url: %s" % url) #This method will sync all Kodi artwork to textures13.dband cache them locally. This takes diskspace! def cache_textures(self): diff --git a/core/common.py b/core/common.py index aec58f26c..218b7e88c 100644 --- a/core/common.py +++ b/core/common.py @@ -3,12 +3,10 @@ import database.queries class Common(): - def __init__(self, emby_db, objects, Utils, direct_path, EmbyServer): + def __init__(self, emby_db, objects, EmbyServer): self.LOG = helper.loghandler.LOG('EMBY.core.common.Common') - self.Utils = Utils self.emby_db = emby_db self.objects = objects - self.direct_path = direct_path self.EmbyServer = EmbyServer #Add streamdata @@ -16,7 +14,7 @@ def Streamdata_add(self, obj, Update): if Update: self.emby_db.remove_item_streaminfos(obj['Id']) - if "3d" in self.Utils.StringMod(obj['Item']['MediaSources'][0]['Path']): + if "3d" in self.EmbyServer.Utils.StringMod(obj['Item']['MediaSources'][0]['Path']): if len(obj['Item']['MediaSources']) >= 2: Temp = obj['Item']['MediaSources'][1] obj['Item']['MediaSources'][1] = obj['Item']['MediaSources'][0] @@ -35,7 +33,7 @@ def Streamdata_add(self, obj, Update): CountMediaSubtitle = 0 CountStreamSources = 0 DataSource = self.objects.MapMissingData(DataSource, 'MediaSources') - self.emby_db.add_mediasource(*self.Utils.values(DataSource, database.queries.add_mediasource_obj)) + self.emby_db.add_mediasource(*self.EmbyServer.Utils.values(DataSource, database.queries.add_mediasource_obj)) for DataStream in DataSource['MediaStreams']: DataStream['emby_id'] = obj['Item']['Id'] @@ -45,17 +43,17 @@ def Streamdata_add(self, obj, Update): if DataStream['Type'] == "Video": DataStream = self.objects.MapMissingData(DataStream, 'VideoStreams') DataStream['VideoIndex'] = CountMediaStreamVideo - self.emby_db.add_videostreams(*self.Utils.values(DataStream, database.queries.add_videostreams_obj)) + self.emby_db.add_videostreams(*self.EmbyServer.Utils.values(DataStream, database.queries.add_videostreams_obj)) CountMediaStreamVideo += 1 elif DataStream['Type'] == "Audio": DataStream = self.objects.MapMissingData(DataStream, 'AudioStreams') DataStream['AudioIndex'] = CountMediaStreamAudio - self.emby_db.add_audiostreams(*self.Utils.values(DataStream, database.queries.add_audiostreams_obj)) + self.emby_db.add_audiostreams(*self.EmbyServer.Utils.values(DataStream, database.queries.add_audiostreams_obj)) CountMediaStreamAudio += 1 elif DataStream['Type'] == "Subtitle": DataStream = self.objects.MapMissingData(DataStream, 'Subtitles') DataStream['SubtitleIndex'] = CountMediaSubtitle - self.emby_db.add_subtitles(*self.Utils.values(DataStream, database.queries.add_subtitles_obj)) + self.emby_db.add_subtitles(*self.EmbyServer.Utils.values(DataStream, database.queries.add_subtitles_obj)) CountMediaSubtitle += 1 CountStreamSources += 1 @@ -66,21 +64,22 @@ def Streamdata_add(self, obj, Update): def get_path_filename(self, obj, MediaID): #Native Kodi plugins starts with plugin:// -> If native Kodi plugin, drop the link directly in Kodi DB. Emby server cannot play Kodi-Plugins - KodiPluginPath = False + ForceNativeMode = False + Temp = obj['Path'].lower() - if obj['Path'].startswith("plugin://"): - KodiPluginPath = True + if Temp.startswith("plugin://") or Temp.endswith(".iso"): + ForceNativeMode = True - if self.direct_path or KodiPluginPath: - if KodiPluginPath: + if self.EmbyServer.Utils.direct_path or ForceNativeMode: + if ForceNativeMode: obj['Filename'] = obj['Path'] else: obj['Filename'] = obj['Path'].rsplit('\\', 1)[1] if '\\' in obj['Path'] else obj['Path'].rsplit('/', 1)[1] - obj['Path'] = self.Utils.StringDecode(obj['Path']) - obj['Filename'] = self.Utils.StringDecode(obj['Filename']) + obj['Path'] = self.EmbyServer.Utils.StringDecode(obj['Path']) + obj['Filename'] = self.EmbyServer.Utils.StringDecode(obj['Filename']) - if not self.Utils.validate(obj['Path']): + if not self.EmbyServer.Utils.validate(obj['Path']): return False, obj obj['Path'] = obj['Path'].replace(obj['Filename'], "") @@ -97,7 +96,7 @@ def get_path_filename(self, obj, MediaID): for AdditionalItem in AdditionalParts['Items']: AdditionalItem = self.objects.MapMissingData(AdditionalItem, 'MediaSources') - Path = self.Utils.StringDecode(AdditionalItem['Path']) + Path = self.EmbyServer.Utils.StringDecode(AdditionalItem['Path']) obj['Filename'] = obj['Filename'] + " , " + Path RunTimePart = round(float((AdditionalItem['RunTimeTicks'] or 0) / 10000000.0), 6) obj['Runtime'] = obj['Runtime'] + RunTimePart @@ -105,7 +104,7 @@ def get_path_filename(self, obj, MediaID): obj['Filename'] = "stack://" + obj['Filename'] else: - Filename = self.Utils.PathToFilenameReplaceSpecialCharecters(obj['Path']) + Filename = self.EmbyServer.Utils.PathToFilenameReplaceSpecialCharecters(obj['Path']) if MediaID == "tvshows": obj['Path'] = "http://127.0.0.1:57578/tvshows/%s/" % obj['SeriesId'] @@ -114,7 +113,7 @@ def get_path_filename(self, obj, MediaID): obj['Filename'] = "%s-%s-%s-stream-%s" % (obj['Id'], obj['Item']['MediaSources'][0]['Id'], obj['Item']['MediaSources'][0]['MediaStreams'][0]['BitRate'], Filename) except: obj['Filename'] = "%s-%s-stream-%s" % (obj['Id'], obj['Item']['MediaSources'][0]['Id'], Filename) - self.LOG.warning("No video bitrate available %s" % self.Utils.StringMod(obj['Item']['Path'])) + self.LOG.warning("No video bitrate available %s" % self.EmbyServer.Utils.StringMod(obj['Item']['Path'])) elif MediaID == "movies": obj['Path'] = "http://127.0.0.1:57578/movies/%s/" % obj['LibraryId'] @@ -122,7 +121,7 @@ def get_path_filename(self, obj, MediaID): obj['Filename'] = "%s-%s-%s-stream-%s" % (obj['Id'], obj['MediaSourceID'], obj['Item']['MediaSources'][0]['MediaStreams'][0]['BitRate'], Filename) except: obj['Filename'] = "%s-%s-stream-%s" % (obj['Id'], obj['MediaSourceID'], Filename) - self.LOG.warning("No video bitrate available %s" % self.Utils.StringMod(obj['Item']['Path'])) + self.LOG.warning("No video bitrate available %s" % self.EmbyServer.Utils.StringMod(obj['Item']['Path'])) elif MediaID == "musicvideos": obj['Path'] = "http://127.0.0.1:57578/musicvideos/%s/" % obj['LibraryId'] @@ -130,7 +129,7 @@ def get_path_filename(self, obj, MediaID): obj['Filename'] = "%s-%s-%s-stream-%s" % (obj['Id'], obj['PresentationKey'], obj['Streams']['video'][0]['BitRate'], Filename) except: obj['Filename'] = "%s-%s-stream-%s" % (obj['Id'], obj['PresentationKey'], Filename) - self.LOG.warning("No video bitrate available %s" % self.Utils.StringMod(obj['Item']['Path'])) + self.LOG.warning("No video bitrate available %s" % self.EmbyServer.Utils.StringMod(obj['Item']['Path'])) elif MediaID == "audio": obj['Path'] = "http://127.0.0.1:57578/audio/%s/" % obj['Id'] obj['Filename'] = "%s-stream-%s" % (obj['Id'], Filename) @@ -145,7 +144,7 @@ def get_path_filename(self, obj, MediaID): for AdditionalItem in AdditionalParts['Items']: AdditionalItem = self.objects.MapMissingData(AdditionalItem, 'MediaSources') - Filename = self.Utils.PathToFilenameReplaceSpecialCharecters(AdditionalItem['Path']) + Filename = self.EmbyServer.Utils.PathToFilenameReplaceSpecialCharecters(AdditionalItem['Path']) try: obj['Filename'] = obj['Filename'] + " , " + obj['Path'] + "%s--%s-stream-%s" % (AdditionalItem['Id'], AdditionalItem['MediaSources'][0]['MediaStreams'][0]['BitRate'], Filename) @@ -195,12 +194,10 @@ def library_check(self, e_item, item, library): break - sync = self.Utils.get_sync() - if not library: library = {} - if view_id not in [x.replace('Mixed:', "") for x in sync['Whitelist'] + sync['Libraries']]: + if view_id not in [x.replace('Mixed:', "") for x in self.EmbyServer.Utils.SyncData['Whitelist'] + self.EmbyServer.Utils.SyncData['Libraries']]: self.LOG.info("Library %s is not synced. Skip update." % view_id) return False diff --git a/core/listitem.py b/core/listitem.py index a0e4efd59..445656c09 100644 --- a/core/listitem.py +++ b/core/listitem.py @@ -5,842 +5,354 @@ import helper.loghandler from . import obj_ops -class BaseListItem(object): - def __init__(self, obj_type, art_type, art_parent, listitem, item, Utils): - self.LOG = helper.loghandler.LOG('EMBY.code.listitem.BaseListItem') - self.li = listitem - self.item = item - self.Utils = Utils - self.objects = obj_ops.Objects(self.Utils) - self.api = helper.api.API(item, self.Utils, item['LI']['Server']) - self.obj = self._get_objects(obj_type) - self.obj['Artwork'] = self._get_artwork(art_type, art_parent) - self.format() - self.set() - - def __getitem__(self, key): - if key in self.obj: - return self.obj[key] - - return None - - def __setitem__(self, key, value): - self.obj[key] = value - - def _get_objects(self, key): - return self.objects.map(self.item, key) - - def _get_artwork(self, key, parent=False): - return self.api.get_all_artwork(self.objects.map(self.item, key), parent) - - #Format object values. Override - def format(self): - pass - - #Set the listitem values based on object. Override - def set(self): - pass - - #Return artwork mapping for object. Override if needed - @classmethod - def art(cls): - return { - 'poster': "Primary", - 'clearart': "Art", - 'clearlogo': "Logo", - 'discart': "Disc", - 'fanart_image': "Backdrop", - 'landscape': "Thumb", - 'thumb': "Primary", - 'fanart': "Backdrop" - } - - def set_art(self): - artwork = self['Artwork'] - art = self.art() - - for kodi, emby in list(art.items()): - if emby == 'Backdrop': - self._set_art(kodi, artwork[emby][0] if artwork[emby] else " ") - else: - self._set_art(kodi, artwork.get(emby, " ")) - - def _set_art(self, art, path): - self.LOG.debug(" [ art/%s ] %s" % (art, path)) - - if art in ('fanart_image', 'small_poster', 'tiny_poster', 'medium_landscape', 'medium_poster', 'small_fanartimage', 'medium_fanartimage', 'fanart_noindicators', 'tvshow.poster'): - self.li.setProperty(art, path) - else: - self.li.setArt({art: path}) - -class Playlist(BaseListItem): - def __init__(self, *args, **kwargs): - BaseListItem.__init__(self, 'BrowseFolder', 'Artwork', False, *args, **kwargs) - - def set(self): - self.li.setProperty('path', self['Artwork']['Primary']) - self.li.setProperty('IsFolder', 'true') -# self.li.setThumbnailImage(self['Artwork']['Primary']) -# self.li.setIconImage('DefaultFolder.png') - self.li.setArt({"thumb": self['Artwork']['Primary'], "icon" : 'DefaultFolder.png'}) - self.li.setProperty('IsPlayable', 'false') - self.li.setLabel(self['Title']) - self.li.setContentLookup(False) - -class Channel(BaseListItem): - def __init__(self, *args, **kwargs): - BaseListItem.__init__(self, 'BrowseChannel', 'Artwork', False, *args, **kwargs) - - @staticmethod - def art(): - return { - 'fanart_image': "Backdrop", - 'thumb': "Primary", - 'fanart': "Backdrop" - } - - def format(self): - self['Title'] = "%s - %s" % (self['Title'], self['ProgramName']) - self['Runtime'] = round(float((self['Runtime'] or 0) / 10000000.0), 6) - self['PlayCount'] = self.api.get_playcount(self['Played'], self['PlayCount']) or 0 - self['Overlay'] = 7 if self['Played'] else 6 - self['Artwork']['Primary'] = self['Artwork']['Primary'] or "special://home/addons/plugin.video.emby-next-gen/resources/icon.png" - self['Artwork']['Thumb'] = self['Artwork']['Thumb'] or "special://home/addons/plugin.video.emby-next-gen/resources/icon.png" - self['Artwork']['Backdrop'] = self['Artwork']['Backdrop'] or ["special://home/addons/plugin.video.emby-next-gen/resources/fanart.jpg"] - - def set(self): - metadata = { - 'title': self['Title'], - 'originaltitle': self['Title'], - 'playcount': self['PlayCount'], - 'overlay': self['Overlay'] - } -# self.li.setIconImage('DefaultVideo.png') -# self.li.setThumbnailImage(self['Artwork']['Primary']) - self.li.setArt({"thumb": self['Artwork']['Primary'], "icon" : 'DefaultFolder.png'}) -## self.set_art() - self.li.setProperty('totaltime', str(self['Runtime'])) - self.li.setProperty('IsPlayable', 'true') - self.li.setProperty('IsFolder', 'false') - self.li.setLabel(self['Title']) - self.li.setInfo('video', metadata) - self.li.setContentLookup(False) - -class Photo(BaseListItem): - def __init__(self, *args, **kwargs): - BaseListItem.__init__(self, 'BrowsePhoto', 'Artwork', False, *args, **kwargs) - - def format(self): - self['Overview'] = self.api.get_overview(self['Overview']) - - try: - self['FileDate'] = "%s.%s.%s" % tuple(reversed(self['FileDate'].split('T')[0].split('-'))) - except: - pass - - def set(self): - metadata = { - 'title': self['Title'], - 'picturepath': self['Artwork']['Primary'], - 'date': self['FileDate'], - 'exif:width': str(self.obj.get('Width', 0)), - 'exif:height': str(self.obj.get('Height', 0)), - 'size': self['Size'], - 'exif:cameramake': self['CameraMake'], - 'exif:cameramodel': self['CameraModel'], - 'exif:exposuretime': str(self['ExposureTime']), - 'exif:focallength': str(self['FocalLength']) - } - self.li.setProperty('path', self['Artwork']['Primary']) -# self.li.setThumbnailImage(self['Artwork']['Primary']) - -# if art in ('fanart_image', 'small_poster', 'tiny_poster', -# 'medium_landscape', 'medium_poster', 'small_fanartimage', -# 'medium_fanartimage', 'fanart_noindicators', 'discart', -# 'tvshow.poster'): - -#thumb string - image filename -#poster string - image filename -#banner string - image filename -#fanart string - image filename -#learart string - image filename -#clearlogo string - image filename -#landscape string - image filename -#icon string - image filename - -#listitem.setArt({"thumb":thumb, "fanart": fanart}) - -#Function: setAvailableFanart(images) -#image string (http://www.someurl.com/someimage.png) -#preview [opt] string (http://www.someurl.com/somepreviewimage.png) - -# self.li.setArt({"thumb": self['Artwork']['Primary']}) - self.li.setArt({"thumb": self['Artwork']['Primary'], "icon" : 'DefaultFolder.png'}) - self.li.setProperty('plot', self['Overview']) - self.li.setProperty('IsFolder', 'false') -# self.li.setIconImage('DefaultPicture.png') -# self.li.setProperty('IsPlayable', 'false') - self.li.setLabel(self['Title']) - self.li.setInfo('pictures', metadata) - self.li.setContentLookup(False) - -class Music(BaseListItem): - def __init__(self, *args, **kwargs): - BaseListItem.__init__(self, 'BrowseAudio', 'ArtworkMusic', True, *args, **kwargs) - - @classmethod - def art(cls): - return { - 'clearlogo': "Logo", - 'discart': "Disc", - 'fanart': "Backdrop", - 'fanart_image': "Backdrop", - 'thumb': "Primary" - } - - def format(self): - self['Runtime'] = round(float((self['Runtime'] or 0) / 10000000.0), 6) - self['PlayCount'] = self.api.get_playcount(self['Played'], self['PlayCount']) or 0 - self['Rating'] = self['Rating'] or 0 - - if self['FileDate'] or self['DatePlayed']: - self['DatePlayed'] = (self['DatePlayed'] or self['FileDate']).split('.')[0].replace('T', " ") - - self['FileDate'] = "%s.%s.%s" % tuple(reversed(self['FileDate'].split('T')[0].split('-'))) - - def set(self): - return -# metadata = { -# 'title': self['Title'], -# 'genre': self['Genre'], -# 'year': self['Year'], -# 'album': self['Album'], -# 'artist': self['Artists'], -# 'rating': self['Rating'], -# 'comment': self['Comment'], -# 'date': self['FileDate'], -# 'mediatype': "music" -# } -## self.set_art() - -class PhotoAlbum(Photo): - def __init__(self, *args, **kwargs): - Photo.__init__(self, *args, **kwargs) - - def set(self): - metadata = {'title': self['Title']} - self.li.setProperty('path', self['Artwork']['Primary']) -# self.li.setThumbnailImage(self['Artwork']['Primary']) - self.li.setArt({"thumb": self['Artwork']['Primary'], "icon" : 'DefaultFolder.png'}) - self.li.setProperty('IsFolder', 'true') -# self.li.setIconImage('DefaultFolder.png') -# self.li.setProperty('IsPlayable', 'false') - self.li.setLabel(self['Title']) - self.li.setInfo('pictures', metadata) - self.li.setContentLookup(False) - -class Video(BaseListItem): - def __init__(self, *args, **kwargs): - BaseListItem.__init__(self, 'BrowseVideo', 'ArtworkParent', True, *args, **kwargs) - - def format(self): - self['Genres'] = " / ".join(self['Genres'] or []) - self['Studios'] = [self.api.validate_studio(studio) for studio in (self['Studios'] or [])] - self['Studios'] = " / ".join(self['Studios']) - self['Mpaa'] = self.api.get_mpaa(self['Mpaa']) - self['People'] = self['People'] or [] - self['Countries'] = " / ".join(self['Countries'] or []) - self['Directors'] = " / ".join(self['Directors'] or []) - self['Writers'] = " / ".join(self['Writers'] or []) - self['Plot'] = self.api.get_overview(self['Plot']) - self['ShortPlot'] = self.api.get_overview(self['ShortPlot']) - self['DateAdded'] = self['DateAdded'].split('.')[0].replace('T', " ") - self['Rating'] = self['Rating'] or 0 - self['FileDate'] = "%s.%s.%s" % tuple(reversed(self['DateAdded'].split('T')[0].split('-'))) - self['Runtime'] = round(float((self['Runtime'] or 0) / 10000000.0), 6) - self['Resume'] = self.api.adjust_resume((self['Resume'] or 0) / 10000000.0, self.Utils) - self['PlayCount'] = self.api.get_playcount(self['Played'], self['PlayCount']) or 0 - self['Overlay'] = 7 if self['Played'] else 6 - self['Video'] = self.api.video_streams(self['Video'] or [], self['Container']) - self['Audio'] = self.api.audio_streams(self['Audio'] or []) - self['Streams'] = self.api.media_streams(self['Video'], self['Audio'], self['Subtitles']) - self['ChildCount'] = self['ChildCount'] or 0 - self['RecursiveCount'] = self['RecursiveCount'] or 0 - self['Unwatched'] = self['Unwatched'] or 0 - self['Artwork']['Backdrop'] = self['Artwork']['Backdrop'] or [] - self['Artwork']['Thumb'] = self['Artwork']['Thumb'] or "" - self['Artwork']['Primary'] = self['Artwork']['Primary'] or "special://home/addons/plugin.video.emby-next-gen/resources/icon.png" - - if self['Premiere']: - self['Premiere'] = self['Premiere'].split('T')[0] - - if self['DatePlayed']: - self['DatePlayed'] = self['DatePlayed'].split('.')[0].replace('T', " ") - - def set(self): -## self.set_art() -# self.li.setIconImage('DefaultVideo.png') -# self.li.setThumbnailImage(self['Artwork']['Primary']) - self.li.setArt({"thumb": self['Artwork']['Primary'], "icon" : 'DefaultFolder.png'}) - metadata = { - 'title': self['Title'], - 'originaltitle': self['Title'], - 'sorttitle': self['SortTitle'], - 'country': self['Countries'], - 'genre': self['Genres'], - 'year': self['Year'], - 'rating': self['Rating'], - 'playcount': self['PlayCount'], - 'overlay': self['Overlay'], - 'director': self['Directors'], - 'mpaa': self['Mpaa'], - 'plot': self['Plot'], - 'plotoutline': self['ShortPlot'], - 'studio': self['Studios'], - 'tagline': self['Tagline'], - 'writer': self['Writers'], - 'premiered': self['Premiere'], - 'votes': self['Votes'], - 'dateadded': self['DateAdded'], - 'aired': self['Year'], - 'date': self['Premiere'] or self['FileDate'], - 'mediatype': "video", - 'lastplayed': self['DatePlayed'], - 'duration': self['Runtime'] - } - - if self.item['LI']['DbId']: - metadata['dbid'] = self.item['LI']['DbId'] - - self.li.setCast(self.api.get_actors()) - self.set_playable() - self.li.setLabel(self['Title']) - self.li.setInfo('video', metadata) - self.li.setContentLookup(False) - - def set_playable(self): - self.li.setProperty('totaltime', str(self['Runtime'])) - self.li.setProperty('IsPlayable', 'true') - self.li.setProperty('IsFolder', 'false') - - if self['Resume'] and self['Runtime'] and self.item['LI']['Seektime'] != False: - self.li.setProperty('resumetime', str(self['Resume'])) - self.li.setProperty('StartPercent', str(((self['Resume']/self['Runtime']) * 100))) - else: - self.li.setProperty('resumetime', '0') - self.li.setProperty('StartPercent', '0') - - for track in self['Streams']['video']: - self.li.addStreamInfo('video', { - 'duration': self['Runtime'], - 'aspect': track['aspect'], - 'codec': track['codec'], - 'width': track['width'], - 'height': track['height'] - }) - - for track in self['Streams']['audio']: - self.li.addStreamInfo('audio', {'codec': track['codec'], 'channels': track['channels']}) - - for track in self['Streams']['subtitle']: - self.li.addStreamInfo('subtitle', {'language': track}) - -class Audio(Music): - def __init__(self, *args, **kwargs): - Music.__init__(self, *args, **kwargs) - - def set(self): - metadata = { - 'title': self['Title'], - 'genre': self['Genre'], - 'year': self['Year'], - 'album': self['Album'], - 'artist': self['Artists'], - 'rating': self['Rating'], - 'comment': self['Comment'], - 'date': self['FileDate'], - 'mediatype': "song", - 'tracknumber': self['Index'], - 'discnumber': self['Disc'], - 'duration': self['Runtime'], - 'playcount': self['PlayCount'], - 'lastplayed': self['DatePlayed'], - 'musicbrainztrackid': self['UniqueId'] - } -## self.set_art() - self.li.setProperty('IsPlayable', 'true') - self.li.setProperty('IsFolder', 'false') - self.li.setLabel(self['Title']) - self.li.setInfo('music', metadata) - self.li.setContentLookup(False) - -class Album(Music): - def __init__(self, *args, **kwargs): - Music.__init__(self, *args, **kwargs) - - def set(self): - metadata = { - 'title': self['Title'], - 'genre': self['Genre'], - 'year': self['Year'], - 'album': self['Album'], - 'artist': self['Artists'], - 'rating': self['Rating'], - 'comment': self['Comment'], - 'date': self['FileDate'], - 'mediatype': "album", - 'musicbrainzalbumid': self['UniqueId'] - } -## self.set_art() - self.li.setLabel(self['Title']) - self.li.setInfo('music', metadata) - self.li.setContentLookup(False) - -class Artist(Music): - def __init__(self, *args, **kwargs): - Music.__init__(self, *args, **kwargs) - - def set(self): - metadata = { - 'title': self['Title'], - 'genre': self['Genre'], - 'year': self['Year'], - 'album': self['Album'], - 'artist': self['Artists'], - 'rating': self['Rating'], - 'comment': self['Comment'], - 'date': self['FileDate'], - 'mediatype': "artist", - 'musicbrainzartistid': self['UniqueId'] - } -## self.set_art() - self.li.setLabel(self['Title']) - self.li.setInfo('music', metadata) - self.li.setContentLookup(False) - -class Episode(Video): - def __init__(self, *args, **kwargs): - Video.__init__(self, *args, **kwargs) - - @classmethod - def art(cls): - return { - 'poster': "Series.Primary", - 'tvshow.poster': "Series.Primary", - 'clearart': "Art", - 'tvshow.clearart': "Art", - 'clearlogo': "Logo", - 'tvshow.clearlogo': "Logo", - 'discart': "Disc", - 'fanart_image': "Backdrop", - 'landscape': "Thumb", - 'tvshow.landscape': "Thumb", - 'thumb': "Primary", - 'fanart': "Backdrop" - } - - def set(self): -## self.set_art() -# self.li.setIconImage('DefaultVideo.png') -# self.li.setThumbnailImage(self['Artwork']['Primary']) - self.li.setArt({"thumb": self['Artwork']['Primary'], "icon" : 'DefaultFolder.png'}) - metadata = { - 'title': self['Title'], - 'originaltitle': self['OriginalTitle'], - 'sorttitle': self['SortTitle'], - 'country': self['Countries'], - 'genre': self['Genres'], - 'year': self['Year'], - 'rating': self['Rating'], - 'playcount': self['PlayCount'], - 'overlay': self['Overlay'], - 'director': self['Directors'], - 'mpaa': self['Mpaa'], - 'plot': self['Plot'], - 'plotoutline': self['ShortPlot'], - 'studio': self['Studios'], - 'tagline': self['Tagline'], - 'writer': self['Writers'], - 'premiered': self['Premiere'], - 'votes': self['Votes'], - 'dateadded': self['DateAdded'], - 'date': self['Premiere'] or self['FileDate'], - 'mediatype': "episode", - 'tvshowtitle': self['SeriesName'], - 'season': self['Season'] or 0, - 'sortseason': self['Season'] or 0, - 'episode': self['Index'] or 0, - 'sortepisode': self['Index'] or 0, - 'lastplayed': self['DatePlayed'], - 'duration': self['Runtime'], - 'aired': self['Premiere'] - } - - if self.item['LI']['DbId']: - metadata['dbid'] = self.item['LI']['DbId'] - - self.li.setCast(self.api.get_actors()) - self.set_playable() - self.li.setLabel(self['Title']) - self.li.setInfo('video', metadata) - self.li.setContentLookup(False) - -class Season(Video): - def __init__(self, *args, **kwargs): - Video.__init__(self, *args, **kwargs) - - def set(self): -## self.set_art() -# self.li.setIconImage('DefaultVideo.png') -# self.li.setThumbnailImage(self['Artwork']['Primary']) - self.li.setArt({"thumb": self['Artwork']['Primary'], "icon" : 'DefaultFolder.png'}) - metadata = { - 'title': self['Title'], - 'originaltitle': self['Title'], - 'sorttitle': self['SortTitle'], - 'country': self['Countries'], - 'genre': self['Genres'], - 'year': self['Year'], - 'rating': self['Rating'], - 'playcount': self['PlayCount'], - 'overlay': self['Overlay'], - 'director': self['Directors'], - 'mpaa': self['Mpaa'], - 'plot': self['Plot'], - 'plotoutline': self['ShortPlot'], - 'studio': self['Studios'], - 'tagline': self['Tagline'], - 'writer': self['Writers'], - 'premiered': self['Premiere'], - 'votes': self['Votes'], - 'dateadded': self['DateAdded'], - 'aired': self['Year'], - 'date': self['Premiere'] or self['FileDate'], - 'mediatype': "season", - 'tvshowtitle': self['SeriesName'], - 'season': self['Index'] or 0, - 'sortseason': self['Index'] or 0 - } - - if self.item['LI']['DbId']: - metadata['dbid'] = self.item['LI']['DbId'] - - self.li.setCast(self.api.get_actors()) - self.li.setProperty('NumEpisodes', str(self['RecursiveCount'])) - self.li.setProperty('WatchedEpisodes', str(self['RecursiveCount'] - self['Unwatched'])) - self.li.setProperty('UnWatchedEpisodes', str(self['Unwatched'])) - self.li.setProperty('IsFolder', 'true') - self.li.setLabel(self['Title']) - self.li.setInfo('video', metadata) - self.li.setContentLookup(False) - -class Series(Video): - def __init__(self, *args, **kwargs): - Video.__init__(self, *args, **kwargs) - - def format(self): - super(Series, self).format() - - if self['Status'] != 'Ended': - self['Status'] = None - - def set(self): -## self.set_art() -# self.li.setIconImage('DefaultVideo.png') -# self.li.setThumbnailImage(self['Artwork']['Primary']) - self.li.setArt({"thumb": self['Artwork']['Primary'], "icon" : 'DefaultFolder.png'}) - metadata = { - 'title': self['Title'], - 'originaltitle': self['OriginalTitle'], - 'sorttitle': self['SortTitle'], - 'country': self['Countries'], - 'genre': self['Genres'], - 'year': self['Year'], - 'rating': self['Rating'], - 'playcount': self['PlayCount'], - 'overlay': self['Overlay'], - 'director': self['Directors'], - 'mpaa': self['Mpaa'], - 'plot': self['Plot'], - 'plotoutline': self['ShortPlot'], - 'studio': self['Studios'], - 'tagline': self['Tagline'], - 'writer': self['Writers'], - 'premiered': self['Premiere'], - 'votes': self['Votes'], - 'dateadded': self['DateAdded'], - 'aired': self['Year'], - 'date': self['Premiere'] or self['FileDate'], - 'mediatype': "tvshow", - 'tvshowtitle': self['Title'], - 'status': self['Status'] - } - - if self.item['LI']['DbId']: - metadata['dbid'] = self.item['LI']['DbId'] - - self.li.setCast(self.api.get_actors()) - self.li.setProperty('TotalSeasons', str(self['ChildCount'])) - self.li.setProperty('TotalEpisodes', str(self['RecursiveCount'])) - self.li.setProperty('WatchedEpisodes', str(self['RecursiveCount'] - self['Unwatched'])) - self.li.setProperty('UnWatchedEpisodes', str(self['Unwatched'])) - self.li.setProperty('IsFolder', 'true') - self.li.setLabel(self['Title']) - self.li.setInfo('video', metadata) - self.li.setContentLookup(False) - -class Movie(Video): - def __init__(self, *args, **kwargs): - Video.__init__(self, *args, **kwargs) - - def set(self): -## self.set_art() -# self.li.setIconImage('DefaultVideo.png') -# self.li.setThumbnailImage(self['Artwork']['Primary']) - self.li.setArt({"thumb": self['Artwork']['Primary'], "icon" : 'DefaultFolder.png'}) - metadata = { - 'title': self['Title'], - 'originaltitle': self['OriginalTitle'], - 'sorttitle': self['SortTitle'], - 'country': self['Countries'], - 'genre': self['Genres'], - 'year': self['Year'], - 'rating': self['Rating'], - 'playcount': self['PlayCount'], - 'overlay': self['Overlay'], - 'director': self['Directors'], - 'mpaa': self['Mpaa'], - 'plot': self['Plot'], - 'plotoutline': self['ShortPlot'], - 'studio': self['Studios'], - 'tagline': self['Tagline'], - 'writer': self['Writers'], - 'premiered': self['Premiere'], - 'votes': self['Votes'], - 'dateadded': self['DateAdded'], - 'aired': self['Year'], - 'date': self['Premiere'] or self['FileDate'], - 'mediatype': "movie", - 'imdbnumber': self['UniqueId'], - 'lastplayed': self['DatePlayed'], - 'duration': self['Runtime'], - 'userrating': self['CriticRating'] - } - - if self.item['LI']['DbId']: - metadata['dbid'] = self.item['LI']['DbId'] - - self.li.setCast(self.api.get_actors()) - self.set_playable() - self.li.setLabel(self['Title']) - self.li.setInfo('video', metadata) - self.li.setContentLookup(False) - -class BoxSet(Video): - def __init__(self, *args, **kwargs): - Video.__init__(self, *args, **kwargs) - - def set(self): -## self.set_art() -# self.li.setIconImage('DefaultVideo.png') -# self.li.setThumbnailImage(self['Artwork']['Primary']) - self.li.setArt({"thumb": self['Artwork']['Primary'], "icon" : 'DefaultFolder.png'}) - metadata = { - 'title': self['Title'], - 'originaltitle': self['Title'], - 'sorttitle': self['SortTitle'], - 'country': self['Countries'], - 'genre': self['Genres'], - 'year': self['Year'], - 'rating': self['Rating'], - 'playcount': self['PlayCount'], - 'overlay': self['Overlay'], - 'director': self['Directors'], - 'mpaa': self['Mpaa'], - 'plot': self['Plot'], - 'plotoutline': self['ShortPlot'], - 'studio': self['Studios'], - 'tagline': self['Tagline'], - 'writer': self['Writers'], - 'premiered': self['Premiere'], - 'votes': self['Votes'], - 'dateadded': self['DateAdded'], - 'aired': self['Year'], - 'date': self['Premiere'] or self['FileDate'], - 'mediatype': "set" - } - - if self.item['LI']['DbId']: - metadata['dbid'] = self.item['LI']['DbId'] - - self.li.setCast(self.api.get_actors()) - self.li.setProperty('IsFolder', 'true') - self.li.setLabel(self['Title']) - self.li.setInfo('video', metadata) - self.li.setContentLookup(False) - -class MusicVideo(Video): - def __init__(self, *args, **kwargs): - Video.__init__(self, *args, **kwargs) - - def set(self): -## self.set_art() -# self.li.setIconImage('DefaultVideo.png') -# self.li.setThumbnailImage(self['Artwork']['Primary']) - self.li.setArt({"thumb": self['Artwork']['Primary'], "icon" : 'DefaultFolder.png'}) - metadata = { - 'title': self['Title'], - 'originaltitle': self['Title'], - 'sorttitle': self['SortTitle'], - 'country': self['Countries'], - 'genre': self['Genres'], - 'year': self['Year'], - 'rating': self['Rating'], - 'playcount': self['PlayCount'], - 'overlay': self['Overlay'], - 'director': self['Directors'], - 'mpaa': self['Mpaa'], - 'plot': self['Plot'], - 'plotoutline': self['ShortPlot'], - 'studio': self['Studios'], - 'tagline': self['Tagline'], - 'writer': self['Writers'], - 'premiered': self['Premiere'], - 'votes': self['Votes'], - 'dateadded': self['DateAdded'], - 'aired': self['Year'], - 'date': self['Premiere'] or self['FileDate'], - 'mediatype': "musicvideo", - 'album': self['Album'], - 'artist': self['Artists'] or [], - 'lastplayed': self['DatePlayed'], - 'duration': self['Runtime'] - } - - if self.item['LI']['DbId']: - metadata['dbid'] = self.item['LI']['DbId'] - - self.li.setCast(self.api.get_actors()) - self.set_playable() - self.li.setLabel(self['Title']) - self.li.setInfo('video', metadata) - self.li.setContentLookup(False) - -class Intro(Video): - def __init__(self, *args, **kwargs): - Video.__init__(self, *args, **kwargs) - - def format(self): - self['Artwork']['Primary'] = self['Artwork']['Primary'] or self['Artwork']['Thumb'] or (self['Artwork']['Backdrop'][0] if len(self['Artwork']['Backdrop']) else "special://home/addons/plugin.video.emby-next-gen/resources/fanart.jpg") - self['Artwork']['Primary'] += "&KodiCinemaMode=true" - self['Artwork']['Backdrop'] = [self['Artwork']['Primary']] - super(Intro, self).format() - - def set(self): -## self.set_art() - self.li.setArt({'poster': ""}) # Clear the poster value for intros / trailers to prevent issues in skins -# self.li.setIconImage('DefaultVideo.png') -# self.li.setThumbnailImage(self['Artwork']['Primary']) - self.li.setArt({"thumb": self['Artwork']['Primary'], "icon" : 'DefaultFolder.png'}) - metadata = { - 'title': self['Title'], - 'originaltitle': self['Title'], - 'sorttitle': self['SortTitle'], - 'country': self['Countries'], - 'genre': self['Genres'], - 'year': self['Year'], - 'rating': self['Rating'], - 'playcount': self['PlayCount'], - 'overlay': self['Overlay'], - 'director': self['Directors'], - 'mpaa': self['Mpaa'], - 'plot': self['Plot'], - 'plotoutline': self['ShortPlot'], - 'studio': self['Studios'], - 'tagline': self['Tagline'], - 'writer': self['Writers'], - 'premiered': self['Premiere'], - 'votes': self['Votes'], - 'dateadded': self['DateAdded'], - 'aired': self['Year'], - 'date': self['Premiere'] or self['FileDate'], - 'mediatype': "video", - 'lastplayed': self['DatePlayed'], - 'duration': self['Runtime'] - } - self.li.setCast(self.api.get_actors()) - self.set_playable() - self.li.setLabel(self['Title']) - self.li.setInfo('video', metadata) - self.li.setContentLookup(False) - -class Trailer(Intro): - def __init__(self, *args, **kwargs): - Intro.__init__(self, *args, **kwargs) - - def format(self): - self['Artwork']['Primary'] = self['Artwork']['Primary'] or self['Artwork']['Thumb'] or (self['Artwork']['Backdrop'][0] if len(self['Artwork']['Backdrop']) else "special://home/addons/plugin.video.emby-next-gen/resources/fanart.jpg") - self['Artwork']['Primary'] += "&KodiTrailer=true" - self['Artwork']['Backdrop'] = [self['Artwork']['Primary']] - Video.format(self) - -MUSIC = { - 'Artist': Artist, - 'MusicArtist': Artist, - 'MusicAlbum': Album, - 'Audio': Audio, - 'Music': Music -} -PHOTO = { - 'Photo': Photo, - 'PhotoAlbum': PhotoAlbum -} -VIDEO = { - 'Episode': Episode, - 'Season': Season, - 'Series': Series, - 'Movie': Movie, - 'MusicVideo': MusicVideo, - 'BoxSet': BoxSet, - 'Trailer': Trailer, - 'AudioBook': Video, - 'Video': Video, - 'Intro': Intro -} -BASIC = { - 'Playlist': Playlist, - 'TvChannel': Channel -} - -#Translate an emby item into a Kodi listitem. -#Returns the listitem class ListItem(): - def __init__(self, server_addr, Utils): - self.server = server_addr - self.Utils = Utils - - def _detect_type(self, item): - item_type = item['Type'] + def __init__(self, ssl, Utils): + self.objects = obj_ops.Objects(Utils) + self.API = helper.api.API(Utils, ssl) - for typ in (VIDEO, MUSIC, PHOTO, BASIC): - if item_type in typ: - return typ[item_type] - - return VIDEO['Video'] - - def set(self, item, listitem, db_id, intro, seektime, *args, **kwargs): + def set(self, item, listitem, db_id, seektime): listitem = listitem or xbmcgui.ListItem() - item['LI'] = { - 'DbId': db_id, - 'Seektime': seektime, - 'Server': self.server - } - - if intro: - func = VIDEO['Trailer'] if item['Type'] == 'Trailer' else VIDEO['Intro'] - else: - func = self._detect_type(item) - - func(listitem, item, self.Utils, *args, **kwargs) - item.pop('LI') + Properties = {} + ArtworkData = {} + + if item['Type'] in ("Movie", "MusicVideo", 'Episode', 'Season', 'Series', 'Video', 'BoxSet', 'AudioBook', 'Folder', 'Trailer'): + obj = self.objects.map(item, 'BrowseVideo') + obj['Artwork'] = self.API.get_all_artwork(self.objects.map(item, 'ArtworkParent'), True) + obj['Genres'] = " / ".join(obj['Genres'] or []) + obj['Studios'] = [self.API.validate_studio(studio) for studio in (obj['Studios'] or [])] + obj['Studios'] = " / ".join(obj['Studios']) + obj['Mpaa'] = self.API.get_mpaa(obj['Mpaa'], item) + obj['People'] = obj['People'] or [] + obj['Countries'] = " / ".join(obj['Countries'] or []) + obj['Directors'] = " / ".join(obj['Directors'] or []) + obj['Writers'] = " / ".join(obj['Writers'] or []) + obj['Plot'] = self.API.get_overview(obj['Plot'], item) + obj['ShortPlot'] = self.API.get_overview(obj['ShortPlot'], item) + obj['DateAdded'] = obj['DateAdded'].split('.')[0].replace('T', " ") + obj['Rating'] = obj['Rating'] or 0 + obj['FileDate'] = "%s.%s.%s" % tuple(reversed(obj['DateAdded'].split('T')[0].split('-'))) + obj['Runtime'] = round(float((obj['Runtime'] or 0) / 10000000.0), 6) + obj['Resume'] = self.API.adjust_resume((obj['Resume'] or 0) / 10000000.0) + obj['PlayCount'] = self.API.get_playcount(obj['Played'], obj['PlayCount']) or 0 + obj['Overlay'] = 7 if obj['Played'] else 6 + obj['Video'] = self.API.video_streams(obj['Video'] or [], obj['Container'], item) + obj['Audio'] = self.API.audio_streams(obj['Audio'] or []) + obj['Streams'] = self.API.media_streams(obj['Video'], obj['Audio'], obj['Subtitles']) + obj['ChildCount'] = obj['ChildCount'] or 0 + obj['RecursiveCount'] = obj['RecursiveCount'] or 0 + obj['Unwatched'] = obj['Unwatched'] or 0 + obj['Artwork']['Backdrop'] = obj['Artwork']['Backdrop'] or [] + obj['Artwork']['Thumb'] = obj['Artwork']['Thumb'] or "" + obj['Artwork']['Primary'] = obj['Artwork']['Primary'] or "special://home/addons/plugin.video.emby-next-gen/resources/icon.png" + + if obj['Premiere']: + obj['Premiere'] = obj['Premiere'].split('T')[0] + + if obj['DatePlayed']: + obj['DatePlayed'] = obj['DatePlayed'].split('.')[0].replace('T', " ") + + if obj['Status'] != 'Ended': + obj['Status'] = None + + Folder = False + Properties['totaltime'] = str(obj['Runtime']) + art = { + 'clearart': "Art", + 'clearlogo': "Logo", + 'discart': "Disc", + 'fanart_image': "Backdrop", + 'landscape': "Thumb", + 'thumb': "Primary", + 'fanart': "Backdrop" + } + metadata = { + 'title': obj['Title'], + 'originaltitle': obj['OriginalTitle'], + 'sorttitle': obj['SortTitle'], + 'country': obj['Countries'], + 'genre': obj['Genres'], + 'year': obj['Year'], + 'rating': obj['Rating'], + 'playcount': obj['PlayCount'], + 'overlay': obj['Overlay'], + 'director': obj['Directors'], + 'mpaa': obj['Mpaa'], + 'plot': obj['Plot'], + 'plotoutline': obj['ShortPlot'], + 'studio': obj['Studios'], + 'tagline': obj['Tagline'], + 'writer': obj['Writers'], + 'premiered': obj['Premiere'], + 'votes': obj['Votes'], + 'dateadded': obj['DateAdded'], + 'date': obj['Premiere'] or obj['FileDate'], + 'lastplayed': obj['DatePlayed'], + 'duration': obj['Runtime'], + 'aired': obj['Year'] + } + + if item['Type'] == 'Movie': + metadata['imdbnumber'] = obj['UniqueId'] + metadata['userrating'] = obj['CriticRating'] + metadata['mediatype'] = "movie" + Properties['IsFolder'] = 'false' + Properties['IsPlayable'] = 'true' + art['poster'] = "Primary" + elif item['Type'] == 'MusicVideo': + metadata['mediatype'] = "musicvideo" + metadata['album'] = obj['Album'] + metadata['artist'] = obj['Artists'] or [] + Properties['IsFolder'] = 'false' + Properties['IsPlayable'] = 'true' + art['poster'] = "Primary" + elif item['Type'] == 'Episode': + metadata['mediatype'] = "episode" + metadata['tvshowtitle'] = obj['SeriesName'] + metadata['season'] = obj['Season'] or 0 + metadata['sortseason'] = obj['Season'] or 0 + metadata['episode'] = obj['Index'] or 0 + metadata['sortepisode'] = obj['Index'] or 0 + Properties['IsFolder'] = 'false' + Properties['IsPlayable'] = 'true' + art['poster'] = "Series.Primary" + art['tvshow.poster'] = "Series.Primary" + art['tvshow.clearart'] = "Art" + art['tvshow.clearlogo'] = "Logo" + elif item['Type'] == 'Season': + metadata['mediatype'] = "season" + metadata['tvshowtitle'] = obj['SeriesName'] + metadata['season'] = obj['Index'] or 0 + metadata['sortseason'] = obj['Index'] or 0 + Properties['NumEpisodes'] = str(obj['RecursiveCount']) + Properties['WatchedEpisodes'] = str(obj['RecursiveCount'] - obj['Unwatched']) + Properties['UnWatchedEpisodes'] = str(obj['Unwatched']) + Properties['IsFolder'] = 'true' + Properties['IsPlayable'] = 'true' + art['poster'] = "Primary" + elif item['Type'] == 'Series': + metadata['mediatype'] = "tvshow" + metadata['tvshowtitle'] = obj['Title'] + metadata['status'] = obj['Status'] + Properties['TotalSeasons'] = str(obj['ChildCount']) + Properties['TotalEpisodes'] = str(obj['RecursiveCount']) + Properties['WatchedEpisodes'] = str(obj['RecursiveCount'] - obj['Unwatched']) + Properties['UnWatchedEpisodes'] = str(obj['Unwatched']) + Properties['IsFolder'] = 'true' + Properties['IsPlayable'] = 'true' + Folder = True + art['poster'] = "Primary" + elif item['Type'] == 'Video': + metadata['mediatype'] = "video" + Properties['IsFolder'] = 'false' + Properties['IsPlayable'] = 'true' + art['poster'] = "Primary" + elif item['Type'] == 'Boxset': + metadata['mediatype'] = "set" + Properties['IsFolder'] = 'false' + Properties['IsPlayable'] = 'true' + art['poster'] = "Primary" + elif item['Type'] == 'Trailer': + metadata['mediatype'] = "video" + Properties['IsFolder'] = 'false' + Properties['IsPlayable'] = 'true' + art['poster'] = "Primary" + elif item['Type'] == 'Folder': + Properties['IsFolder'] = 'true' + Properties['IsPlayable'] = 'true' + Folder = True + art['poster'] = "Primary" + + if db_id: + metadata['dbid'] = db_id + + if not Folder: + if obj['Resume'] and obj['Runtime'] and seektime != False: + Properties['resumetime'] = str(obj['Resume']) + Properties['StartPercent'] = str(((obj['Resume'] / obj['Runtime']) * 100)) + else: + Properties['resumetime'] = '0' + Properties['StartPercent'] = '0' + + for track in obj['Streams']['video']: + listitem.addStreamInfo('video', { + 'duration': obj['Runtime'], + 'aspect': track['aspect'], + 'codec': track['codec'], + 'width': track['width'], + 'height': track['height'] + }) + + for track in obj['Streams']['audio']: + listitem.addStreamInfo('audio', {'codec': track['codec'], 'channels': track['channels']}) + + for track in obj['Streams']['subtitle']: + listitem.addStreamInfo('subtitle', {'language': track}) + + for kodi, emby in list(art.items()): + if emby == 'Backdrop': + ArtworkData[kodi] = obj['Artwork'][emby][0] if obj['Artwork'][emby] else "" + else: + ArtworkData[kodi] = obj['Artwork'].get(emby, " ") + + listitem.setInfo('video', metadata) + elif item['Type'] in ("Music", "Audio", "MusicAlbum", "MusicArtist", "Artist"): + obj = self.objects.map(item, 'BrowseAudio') + obj['Artwork'] = self.API.get_all_artwork(self.objects.map(item, 'ArtworkMusic'), True) + obj['Runtime'] = round(float((obj['Runtime'] or 0) / 10000000.0), 6) + obj['PlayCount'] = self.API.get_playcount(obj['Played'], obj['PlayCount']) or 0 + obj['Rating'] = obj['Rating'] or 0 + obj['FileDate'] = "%s.%s.%s" % tuple(reversed(obj['DateAdded'].split('T')[0].split('-'))) + art = { + 'clearart': "Art", + 'clearlogo': "Logo", + 'discart': "Disc", + 'fanart_image': "Backdrop", + 'landscape': "Thumb", + 'thumb': "Primary", + 'fanart': "Backdrop" + } + metadata = { + 'title': obj['Title'], + 'genre': obj['Genre'], + 'year': obj['Year'], + 'album': obj['Album'], + 'artist': obj['Artists'], + 'rating': obj['Rating'], + 'comment': obj['Comment'], + 'date': obj['FileDate'], + } + + if item['Type'] == 'Music': + metadata['mediatype'] = "music" + elif item['Type'] == 'Audio': + metadata['mediatype'] = "song" + metadata['tracknumber'] = obj['Index'] + metadata['discnumber'] = obj['Disc'] + metadata['duration'] = obj['Runtime'] + metadata['playcount'] = obj['PlayCount'] + metadata['lastplayed'] = obj['DatePlayed'] + metadata['musicbrainztrackid'] = obj['UniqueId'] + Properties['IsPlayable'] = 'true' + Properties['IsFolder'] = 'false' + elif item['Type'] == 'MusicAlbum': + metadata['mediatype'] = "album" + metadata['musicbrainzalbumid'] = obj['UniqueId'] + elif item['Type'] in ("MusicArtist", "Artist"): + metadata['mediatype'] = "artist" + metadata['musicbrainzartistid'] = obj['UniqueId'] + + for kodi, emby in list(art.items()): + if emby == 'Backdrop': + ArtworkData[kodi] = obj['Artwork'][emby][0] if obj['Artwork'][emby] else "" + else: + ArtworkData[kodi] = obj['Artwork'].get(emby, " ") + + listitem.setInfo('music', metadata) + elif item['Type'] in ("Photo", "PhotoAlbum"): + obj = self.objects.map(item, 'BrowsePhoto') + obj['Artwork'] = self.API.get_all_artwork(self.objects.map(item, 'Artwork'), False) + obj['Overview'] = self.API.get_overview(obj['Overview'], item) + obj['FileDate'] = "%s.%s.%s" % tuple(reversed(obj['DateAdded'].split('T')[0].split('-'))) + art = { + 'clearart': "Art", + 'clearlogo': "Logo", + 'discart': "Disc", + 'fanart_image': "Backdrop", + 'landscape': "Thumb", + 'thumb': "Primary", + 'fanart': "Backdrop" + } + metadata = { + 'title': obj['Title'], + 'picturepath': obj['Artwork']['Primary'], + 'date': obj['FileDate'], + 'exif:width': str(obj.get('Width', 0)), + 'exif:height': str(obj.get('Height', 0)), + 'size': obj['Size'], + 'exif:cameramake': obj['CameraMake'], + 'exif:cameramodel': obj['CameraModel'], + 'exif:exposuretime': str(obj['ExposureTime']), + 'exif:focallength': str(obj['FocalLength']) + } + + if item['Type'] == 'Photo': + Properties['IsFolder'] = 'false' + else: + Properties['IsFolder'] = 'true' + + Properties['path'] = obj['Artwork']['Primary'] + Properties['plot'] = obj['Overview'] + Properties['IsPlayable'] = 'false' + + for kodi, emby in list(art.items()): + if emby == 'Backdrop': + ArtworkData[kodi] = obj['Artwork'][emby][0] if obj['Artwork'][emby] else "" + else: + ArtworkData[kodi] = obj['Artwork'].get(emby, " ") + + listitem.setInfo('pictures', metadata) + elif item['Type'] == 'Playlist': + obj = self.objects.map(item, 'BrowseFolder') + obj['Artwork'] = self.API.get_all_artwork(self.objects.map(item, 'Artwork'), False) + Properties['path'] = obj['Artwork']['Primary'] + Properties['IsFolder'] = 'true' + Properties['IsPlayable'] = 'false' + art = { + 'clearart': "Art", + 'clearlogo': "Logo", + 'discart': "Disc", + 'fanart_image': "Backdrop", + 'landscape': "Thumb", + 'thumb': "Primary", + 'fanart': "Backdrop" + } + + for kodi, emby in list(art.items()): + if emby == 'Backdrop': + ArtworkData[kodi] = obj['Artwork'][emby][0] if obj['Artwork'][emby] else "" + else: + ArtworkData[kodi] = obj['Artwork'].get(emby, " ") + elif item['Type'] == 'TvChannel': + obj = self.objects.map(item, 'BrowseChannel') + obj['Artwork'] = self.API.get_all_artwork(self.objects.map(item, 'Artwork'), False) + obj['Title'] = "%s - %s" % (obj['Title'], obj['ProgramName']) + obj['Runtime'] = round(float((obj['Runtime'] or 0) / 10000000.0), 6) + obj['PlayCount'] = self.API.get_playcount(obj['Played'], obj['PlayCount']) or 0 + obj['Overlay'] = 7 if obj['Played'] else 6 + obj['Artwork']['Primary'] = obj['Artwork']['Primary'] or "special://home/addons/plugin.video.emby-next-gen/resources/icon.png" + obj['Artwork']['Thumb'] = obj['Artwork']['Thumb'] or "special://home/addons/plugin.video.emby-next-gen/resources/icon.png" + obj['Artwork']['Backdrop'] = obj['Artwork']['Backdrop'] or ["special://home/addons/plugin.video.emby-next-gen/resources/fanart.jpg"] + metadata = { + 'title': obj['Title'], + 'originaltitle': obj['Title'], + 'playcount': obj['PlayCount'], + 'overlay': obj['Overlay'] + } + art = { + 'clearart': "Art", + 'clearlogo': "Logo", + 'discart': "Disc", + 'fanart_image': "Backdrop", + 'landscape': "Thumb", + 'thumb': "Primary", + 'fanart': "Backdrop" + } + Properties['totaltime'] = str(obj['Runtime']) + Properties['IsFolder'] = 'false' + Properties['IsPlayable'] = 'true' + + for kodi, emby in list(art.items()): + if emby == 'Backdrop': + ArtworkData[kodi] = obj['Artwork'][emby][0] if obj['Artwork'][emby] else "" + else: + ArtworkData[kodi] = obj['Artwork'].get(emby, " ") + + listitem.setInfo('video', metadata) + + if Properties: + listitem.setProperties(Properties) + + listitem.setArt(ArtworkData) + listitem.setLabel(obj['Title']) + listitem.setContentLookup(False) return listitem diff --git a/core/movies.py b/core/movies.py index 953b3ace6..c8848333c 100644 --- a/core/movies.py +++ b/core/movies.py @@ -10,21 +10,19 @@ from . import common class Movies(): - def __init__(self, EmbyServer, embydb, videodb, direct_path, Utils, Downloader): + def __init__(self, EmbyServer, embydb, videodb): self.LOG = helper.loghandler.LOG('EMBY.core.movies.Movies') - self.Utils = Utils self.EmbyServer = EmbyServer self.emby = embydb self.video = videodb - self.direct_path = direct_path self.emby_db = database.emby_db.EmbyDatabase(embydb.cursor) - self.objects = obj_ops.Objects(self.Utils) + self.objects = obj_ops.Objects(self.EmbyServer.Utils) self.item_ids = [] - self.Downloader = Downloader - self.Common = common.Common(self.emby_db, self.objects, self.Utils, self.direct_path, self.EmbyServer) - self.KodiDBIO = kodi.Kodi(videodb.cursor, Utils) + self.Common = common.Common(self.emby_db, self.objects, self.EmbyServer) + self.KodiDBIO = kodi.Kodi(videodb.cursor, self.EmbyServer.Utils) self.MoviesDBIO = MoviesDBIO(videodb.cursor) - self.ArtworkDBIO = artwork.Artwork(videodb.cursor, self.Utils) + self.ArtworkDBIO = artwork.Artwork(videodb.cursor, self.EmbyServer.Utils) + self.APIHelper = helper.api.API(self.EmbyServer.Utils, self.EmbyServer.Data['auth.ssl']) #If item does not exist, entry will be added. #If item exists, entry will be updated @@ -35,7 +33,6 @@ def movie(self, item, library): if not library: return False - API = helper.api.API(item, self.Utils, self.EmbyServer.auth.get_serveraddress()) obj = self.objects.map(item, 'Movie') obj['Item'] = item obj['Library'] = library @@ -46,14 +43,14 @@ def movie(self, item, library): if str(StackedID) != obj['Id']: self.LOG.info("Skipping stacked movie %s [%s/%s]" % (obj['Title'], StackedID, obj['Id'])) - Movies(self.EmbyServer, self.emby, self.video, self.direct_path, self.Utils, self.Downloader).remove(StackedID) + Movies(self.EmbyServer, self.emby, self.video).remove(StackedID) if e_item: obj['MovieId'] = e_item[0] obj['FileId'] = e_item[1] obj['PathId'] = e_item[2] - if self.MoviesDBIO.get(*self.Utils.values(obj, queries_videos.get_movie_obj)) is None: + if self.MoviesDBIO.get(*self.EmbyServer.Utils.values(obj, queries_videos.get_movie_obj)) is None: update = False self.LOG.info("MovieId %s missing from kodi. repairing the entry." % obj['MovieId']) else: @@ -69,35 +66,35 @@ def movie(self, item, library): obj['Path'] = obj['Item']['MediaSources'][0]['Path'] #don't use 3d movies as default - if "3d" in self.Utils.StringMod(obj['Item']['MediaSources'][0]['Path']): + if "3d" in self.EmbyServer.Utils.StringMod(obj['Item']['MediaSources'][0]['Path']): for DataSource in obj['Item']['MediaSources']: - if not "3d" in self.Utils.StringMod(DataSource['Path']): + if not "3d" in self.EmbyServer.Utils.StringMod(DataSource['Path']): DataSource = self.objects.MapMissingData(DataSource, 'MediaSources') obj['Path'] = DataSource['Path'] obj['MediaSourceID'] = DataSource['Id'] obj['Runtime'] = DataSource['RunTimeTicks'] break - obj['Path'] = API.get_file_path(obj['Path']) + obj['Path'] = self.APIHelper.get_file_path(obj['Path'], item) obj['Genres'] = obj['Genres'] or [] - obj['Studios'] = [API.validate_studio(studio) for studio in (obj['Studios'] or [])] + obj['Studios'] = [self.APIHelper.validate_studio(studio) for studio in (obj['Studios'] or [])] obj['People'] = obj['People'] or [] obj['Genre'] = " / ".join(obj['Genres']) obj['Writers'] = " / ".join(obj['Writers'] or []) obj['Directors'] = " / ".join(obj['Directors'] or []) - obj['Plot'] = API.get_overview(obj['Plot']) - obj['Mpaa'] = API.get_mpaa(obj['Mpaa']) - obj['Resume'] = API.adjust_resume((obj['Resume'] or 0) / 10000000.0, self.Utils) + obj['Plot'] = self.APIHelper.get_overview(obj['Plot'], item) + obj['Mpaa'] = self.APIHelper.get_mpaa(obj['Mpaa'], item) + obj['Resume'] = self.APIHelper.adjust_resume((obj['Resume'] or 0) / 10000000.0) obj['Runtime'] = round(float((obj['Runtime'] or 0) / 10000000.0), 6) - obj['People'] = API.get_people_artwork(obj['People']) - obj['DateAdded'] = self.Utils.convert_to_local(obj['DateAdded']).split('.')[0].replace('T', " ") - obj['Premiered'] = self.Utils.convert_to_local(obj['Year']) if not obj['Premiered'] else self.Utils.convert_to_local(obj['Premiered']).replace(" ", "T").split('T')[0] - obj['DatePlayed'] = None if not obj['DatePlayed'] else self.Utils.convert_to_local(obj['DatePlayed']).split('.')[0].replace('T', " ") - obj['PlayCount'] = API.get_playcount(obj['Played'], obj['PlayCount']) - obj['Artwork'] = API.get_all_artwork(self.objects.map(item, 'Artwork')) - obj['Video'] = API.video_streams(obj['Video'] or [], obj['Container']) - obj['Audio'] = API.audio_streams(obj['Audio'] or []) - obj['Streams'] = API.media_streams(obj['Video'], obj['Audio'], obj['Subtitles']) + obj['People'] = self.APIHelper.get_people_artwork(obj['People']) + obj['DateAdded'] = self.EmbyServer.Utils.convert_to_local(obj['DateAdded']).split('.')[0].replace('T', " ") + obj['Premiered'] = self.EmbyServer.Utils.convert_to_local(obj['Year']) if not obj['Premiered'] else self.EmbyServer.Utils.convert_to_local(obj['Premiered']).replace(" ", "T").split('T')[0] + obj['DatePlayed'] = None if not obj['DatePlayed'] else self.EmbyServer.Utils.convert_to_local(obj['DatePlayed']).split('.')[0].replace('T', " ") + obj['PlayCount'] = self.APIHelper.get_playcount(obj['Played'], obj['PlayCount']) + obj['Artwork'] = self.APIHelper.get_all_artwork(self.objects.map(item, 'Artwork')) + obj['Video'] = self.APIHelper.video_streams(obj['Video'] or [], obj['Container'], item) + obj['Audio'] = self.APIHelper.audio_streams(obj['Audio'] or []) + obj['Streams'] = self.APIHelper.media_streams(obj['Video'], obj['Audio'], obj['Subtitles']) PathValid, obj = self.Common.get_path_filename(obj, "movies") if not PathValid: @@ -106,7 +103,7 @@ def movie(self, item, library): self.trailer(obj) if obj['Countries']: - self.MoviesDBIO.add_countries(*self.Utils.values(obj, queries_videos.update_country_obj)) + self.MoviesDBIO.add_countries(*self.EmbyServer.Utils.values(obj, queries_videos.update_country_obj)) tags = [] tags.extend(obj['TagItems'] or obj['Tags'] or []) @@ -122,19 +119,19 @@ def movie(self, item, library): else: self.movie_add(obj) - self.KodiDBIO.update_path(*self.Utils.values(obj, queries_videos.update_path_movie_obj)) - self.KodiDBIO.update_file(*self.Utils.values(obj, queries_videos.update_file_obj)) - self.KodiDBIO.add_tags(*self.Utils.values(obj, queries_videos.add_tags_movie_obj)) - self.KodiDBIO.add_genres(*self.Utils.values(obj, queries_videos.add_genres_movie_obj)) - self.KodiDBIO.add_studios(*self.Utils.values(obj, queries_videos.add_studios_movie_obj)) - self.KodiDBIO.add_playstate(*self.Utils.values(obj, queries_videos.add_bookmark_obj)) - self.KodiDBIO.add_people(*self.Utils.values(obj, queries_videos.add_people_movie_obj)) - self.KodiDBIO.add_streams(*self.Utils.values(obj, queries_videos.add_streams_obj)) + self.KodiDBIO.update_path(*self.EmbyServer.Utils.values(obj, queries_videos.update_path_movie_obj)) + self.KodiDBIO.update_file(*self.EmbyServer.Utils.values(obj, queries_videos.update_file_obj)) + self.KodiDBIO.add_tags(*self.EmbyServer.Utils.values(obj, queries_videos.add_tags_movie_obj)) + self.KodiDBIO.add_genres(*self.EmbyServer.Utils.values(obj, queries_videos.add_genres_movie_obj)) + self.KodiDBIO.add_studios(*self.EmbyServer.Utils.values(obj, queries_videos.add_studios_movie_obj)) + self.KodiDBIO.add_playstate(*self.EmbyServer.Utils.values(obj, queries_videos.add_bookmark_obj)) + self.KodiDBIO.add_people(*self.EmbyServer.Utils.values(obj, queries_videos.add_people_movie_obj)) + self.KodiDBIO.add_streams(*self.EmbyServer.Utils.values(obj, queries_videos.add_streams_obj)) self.ArtworkDBIO.add(obj['Artwork'], obj['MovieId'], "movie") self.item_ids.append(obj['Id']) if "StackTimes" in obj: - self.KodiDBIO.add_stacktimes(*self.Utils.values(obj, queries_videos.add_stacktimes_obj)) + self.KodiDBIO.add_stacktimes(*self.EmbyServer.Utils.values(obj, queries_videos.add_stacktimes_obj)) return not update @@ -143,13 +140,13 @@ def movie_add(self, obj): obj = self.Common.Streamdata_add(obj, False) obj['RatingType'] = "default" obj['RatingId'] = self.KodiDBIO.create_entry_rating() - self.KodiDBIO.add_ratings(*self.Utils.values(obj, queries_videos.add_rating_movie_obj)) + self.KodiDBIO.add_ratings(*self.EmbyServer.Utils.values(obj, queries_videos.add_rating_movie_obj)) if obj['CriticRating'] is not None: - self.KodiDBIO.add_ratings(*self.Utils.values(dict(obj, RatingId=self.KodiDBIO.create_entry_rating(), RatingType="tomatometerallcritics", Rating=float(obj['CriticRating']/10.0)), queries_videos.add_rating_movie_obj)) + self.KodiDBIO.add_ratings(*self.EmbyServer.Utils.values(dict(obj, RatingId=self.KodiDBIO.create_entry_rating(), RatingType="tomatometerallcritics", Rating=float(obj['CriticRating']/10.0)), queries_videos.add_rating_movie_obj)) obj['Unique'] = self.MoviesDBIO.create_entry_unique_id() - self.MoviesDBIO.add_unique_id(*self.Utils.values(obj, queries_videos.add_unique_id_movie_obj)) + self.MoviesDBIO.add_unique_id(*self.EmbyServer.Utils.values(obj, queries_videos.add_unique_id_movie_obj)) for provider in obj['UniqueIds'] or {}: unique_id = obj['UniqueIds'][provider] @@ -157,29 +154,29 @@ def movie_add(self, obj): if provider != 'imdb': temp_obj = dict(obj, ProviderName=provider, UniqueId=unique_id, Unique=self.MoviesDBIO.create_entry_unique_id()) - self.MoviesDBIO.add_unique_id(*self.Utils.values(temp_obj, queries_videos.add_unique_id_movie_obj)) + self.MoviesDBIO.add_unique_id(*self.EmbyServer.Utils.values(temp_obj, queries_videos.add_unique_id_movie_obj)) - obj['PathId'] = self.KodiDBIO.add_path(*self.Utils.values(obj, queries_videos.add_path_obj)) - obj['FileId'] = self.KodiDBIO.add_file(*self.Utils.values(obj, queries_videos.add_file_obj)) - self.MoviesDBIO.add(*self.Utils.values(obj, queries_videos.add_movie_obj)) - self.emby_db.add_reference(*self.Utils.values(obj, database.queries.add_reference_movie_obj)) + obj['PathId'] = self.KodiDBIO.add_path(*self.EmbyServer.Utils.values(obj, queries_videos.add_path_obj)) + obj['FileId'] = self.KodiDBIO.add_file(*self.EmbyServer.Utils.values(obj, queries_videos.add_file_obj)) + self.MoviesDBIO.add(*self.EmbyServer.Utils.values(obj, queries_videos.add_movie_obj)) + self.emby_db.add_reference(*self.EmbyServer.Utils.values(obj, database.queries.add_reference_movie_obj)) self.LOG.info("ADD movie [%s/%s/%s] %s: %s" % (obj['PathId'], obj['FileId'], obj['MovieId'], obj['Id'], obj['Title'])) #Update object to kodi def movie_update(self, obj): obj = self.Common.Streamdata_add(obj, True) obj['RatingType'] = "default" - obj['RatingId'] = self.KodiDBIO.get_rating_id(*self.Utils.values(obj, queries_videos.get_rating_movie_obj)) - self.KodiDBIO.update_ratings(*self.Utils.values(obj, queries_videos.update_rating_movie_obj)) + obj['RatingId'] = self.KodiDBIO.get_rating_id(*self.EmbyServer.Utils.values(obj, queries_videos.get_rating_movie_obj)) + self.KodiDBIO.update_ratings(*self.EmbyServer.Utils.values(obj, queries_videos.update_rating_movie_obj)) if obj['CriticRating'] is not None: temp_obj = dict(obj, RatingType="tomatometerallcritics", Rating=float(obj['CriticRating']/10.0)) - temp_obj['RatingId'] = self.KodiDBIO.get_rating_id(*self.Utils.values(temp_obj, queries_videos.get_rating_movie_obj)) - self.KodiDBIO.update_ratings(*self.Utils.values(temp_obj, queries_videos.update_rating_movie_obj)) + temp_obj['RatingId'] = self.KodiDBIO.get_rating_id(*self.EmbyServer.Utils.values(temp_obj, queries_videos.get_rating_movie_obj)) + self.KodiDBIO.update_ratings(*self.EmbyServer.Utils.values(temp_obj, queries_videos.update_rating_movie_obj)) - self.KodiDBIO.remove_unique_ids(*self.Utils.values(obj, queries_videos.delete_unique_ids_movie_obj)) + self.KodiDBIO.remove_unique_ids(*self.EmbyServer.Utils.values(obj, queries_videos.delete_unique_ids_movie_obj)) obj['Unique'] = self.MoviesDBIO.create_entry_unique_id() - self.MoviesDBIO.add_unique_id(*self.Utils.values(obj, queries_videos.add_unique_id_movie_obj)) + self.MoviesDBIO.add_unique_id(*self.EmbyServer.Utils.values(obj, queries_videos.add_unique_id_movie_obj)) for provider in obj['UniqueIds'] or {}: unique_id = obj['UniqueIds'][provider] @@ -187,21 +184,20 @@ def movie_update(self, obj): if provider != 'imdb': temp_obj = dict(obj, ProviderName=provider, UniqueId=unique_id, Unique=self.MoviesDBIO.create_entry_unique_id()) - self.MoviesDBIO.add_unique_id(*self.Utils.values(temp_obj, queries_videos.add_unique_id_movie_obj)) + self.MoviesDBIO.add_unique_id(*self.EmbyServer.Utils.values(temp_obj, queries_videos.add_unique_id_movie_obj)) - self.MoviesDBIO.update(*self.Utils.values(obj, queries_videos.update_movie_obj)) - self.emby_db.update_reference(*self.Utils.values(obj, database.queries.update_reference_obj)) + self.MoviesDBIO.update(*self.EmbyServer.Utils.values(obj, queries_videos.update_movie_obj)) + self.emby_db.update_reference(*self.EmbyServer.Utils.values(obj, database.queries.update_reference_obj)) self.LOG.info("UPDATE movie [%s/%s/%s] %s: %s" % (obj['PathId'], obj['FileId'], obj['MovieId'], obj['Id'], obj['Title'])) def trailer(self, obj): try: if obj['LocalTrailer']: trailer = self.EmbyServer.API.get_local_trailers(obj['Id']) - API = helper.api.API(trailer, self.Utils, self.EmbyServer.auth.get_serveraddress()) - if self.direct_path: - obj['Trailer'] = API.get_file_path(trailer[0]['Path']) - obj['Trailer'] = self.Utils.StringDecode(obj['Trailer']) + if self.EmbyServer.Utils.direct_path: + obj['Trailer'] = self.APIHelper.get_file_path(trailer[0]['Path'], trailer) + obj['Trailer'] = self.EmbyServer.Utils.StringDecode(obj['Trailer']) else: obj['Trailer'] = "plugin://plugin.video.emby-next-gen/trailer?id=%s&mode=play" % trailer[0]['Id'] elif obj['Trailer']: @@ -216,50 +212,49 @@ def trailer(self, obj): #Process removals from boxset. def boxset(self, item): e_item = self.emby_db.get_item_by_id(item['Id']) - API = helper.api.API(item, self.Utils, self.EmbyServer.auth.get_serveraddress()) obj = self.objects.map(item, 'Boxset') - obj['Overview'] = API.get_overview(obj['Overview']) + obj['Overview'] = self.APIHelper.get_overview(obj['Overview'], item) obj['Checksum'] = obj['Etag'] if e_item: obj['SetId'] = e_item[0] - self.MoviesDBIO.update_boxset(*self.Utils.values(obj, queries_videos.update_set_obj)) + self.MoviesDBIO.update_boxset(*self.EmbyServer.Utils.values(obj, queries_videos.update_set_obj)) else: self.LOG.debug("SetId %s not found" % obj['Id']) - obj['SetId'] = self.MoviesDBIO.add_boxset(*self.Utils.values(obj, queries_videos.add_set_obj)) + obj['SetId'] = self.MoviesDBIO.add_boxset(*self.EmbyServer.Utils.values(obj, queries_videos.add_set_obj)) self.boxset_current(obj) - obj['Artwork'] = API.get_all_artwork(self.objects.map(item, 'Artwork')) + obj['Artwork'] = self.APIHelper.get_all_artwork(self.objects.map(item, 'Artwork')) for movie in obj['Current']: temp_obj = dict(obj) temp_obj['Movie'] = movie temp_obj['MovieId'] = obj['Current'][temp_obj['Movie']] - self.MoviesDBIO.remove_from_boxset(*self.Utils.values(temp_obj, queries_videos.delete_movie_set_obj)) - self.emby_db.update_parent_id(*self.Utils.values(temp_obj, database.queries.delete_parent_boxset_obj)) + self.MoviesDBIO.remove_from_boxset(*self.EmbyServer.Utils.values(temp_obj, queries_videos.delete_movie_set_obj)) + self.emby_db.update_parent_id(*self.EmbyServer.Utils.values(temp_obj, database.queries.delete_parent_boxset_obj)) self.LOG.info("DELETE from boxset [%s] %s: %s" % (temp_obj['SetId'], temp_obj['Title'], temp_obj['MovieId'])) self.ArtworkDBIO.add(obj['Artwork'], obj['SetId'], "set") - self.emby_db.add_reference(*self.Utils.values(obj, database.queries.add_reference_boxset_obj)) + self.emby_db.add_reference(*self.EmbyServer.Utils.values(obj, database.queries.add_reference_boxset_obj)) self.LOG.info("UPDATE boxset [%s] %s" % (obj['SetId'], obj['Title'])) return True #Add or removes movies based on the current movies found in the boxset def boxset_current(self, obj): try: - current = self.emby_db.get_item_id_by_parent_id(*self.Utils.values(obj, database.queries.get_item_id_by_parent_boxset_obj)) + current = self.emby_db.get_item_id_by_parent_id(*self.EmbyServer.Utils.values(obj, database.queries.get_item_id_by_parent_boxset_obj)) movies = dict(current) except ValueError: movies = {} obj['Current'] = movies - for all_movies in self.Downloader.get_movies_by_boxset(obj['Id']): + for all_movies in self.EmbyServer.API.get_movies_by_boxset(obj['Id']): for movie in all_movies['Items']: temp_obj = dict(obj) temp_obj['Title'] = movie['Name'] temp_obj['Id'] = movie['Id'] - Data = self.emby_db.get_item_by_id(*self.Utils.values(temp_obj, database.queries.get_item_obj)) + Data = self.emby_db.get_item_by_id(*self.EmbyServer.Utils.values(temp_obj, database.queries.get_item_obj)) if Data: temp_obj['MovieId'] = Data[0] @@ -268,8 +263,8 @@ def boxset_current(self, obj): continue if temp_obj['Id'] not in obj['Current']: - self.MoviesDBIO.set_boxset(*self.Utils.values(temp_obj, queries_videos.update_movie_set_obj)) - self.emby_db.update_parent_id(*self.Utils.values(temp_obj, database.queries.update_parent_movie_obj)) + self.MoviesDBIO.set_boxset(*self.EmbyServer.Utils.values(temp_obj, queries_videos.update_movie_set_obj)) + self.emby_db.update_parent_id(*self.EmbyServer.Utils.values(temp_obj, database.queries.update_parent_movie_obj)) self.LOG.info("ADD to boxset [%s/%s] %s: %s to boxset" % (temp_obj['SetId'], temp_obj['MovieId'], temp_obj['Title'], temp_obj['Id'])) else: obj['Current'].pop(temp_obj['Id']) @@ -284,7 +279,6 @@ def boxsets_reset(self): #Poster with progress bar def userdata(self, item): e_item = self.emby_db.get_item_by_id(item['Id']) - API = helper.api.API(item, self.Utils, self.EmbyServer.auth.get_serveraddress()) obj = self.objects.map(item, 'MovieUserData') obj['Item'] = item @@ -295,21 +289,21 @@ def userdata(self, item): return obj = self.Common.Streamdata_add(obj, True) - obj['Resume'] = API.adjust_resume((obj['Resume'] or 0) / 10000000.0, self.Utils) + obj['Resume'] = self.APIHelper.adjust_resume((obj['Resume'] or 0) / 10000000.0) obj['Runtime'] = round(float((obj['Runtime'] or 0) / 10000000.0), 6) - obj['PlayCount'] = API.get_playcount(obj['Played'], obj['PlayCount']) + obj['PlayCount'] = self.APIHelper.get_playcount(obj['Played'], obj['PlayCount']) if obj['DatePlayed']: - obj['DatePlayed'] = self.Utils.convert_to_local(obj['DatePlayed']).split('.')[0].replace('T', " ") + obj['DatePlayed'] = self.EmbyServer.Utils.convert_to_local(obj['DatePlayed']).split('.')[0].replace('T', " ") if obj['Favorite']: - self.KodiDBIO.get_tag(*self.Utils.values(obj, queries_videos.get_tag_movie_obj)) + self.KodiDBIO.get_tag(*self.EmbyServer.Utils.values(obj, queries_videos.get_tag_movie_obj)) else: - self.KodiDBIO.remove_tag(*self.Utils.values(obj, queries_videos.delete_tag_movie_obj)) + self.KodiDBIO.remove_tag(*self.EmbyServer.Utils.values(obj, queries_videos.delete_tag_movie_obj)) self.LOG.debug("New resume point %s: %s" % (obj['Id'], obj['Resume'])) - self.KodiDBIO.add_playstate(*self.Utils.values(obj, queries_videos.add_bookmark_obj)) - self.emby_db.update_reference(*self.Utils.values(obj, database.queries.update_reference_obj)) + self.KodiDBIO.add_playstate(*self.EmbyServer.Utils.values(obj, queries_videos.add_bookmark_obj)) + self.emby_db.update_reference(*self.EmbyServer.Utils.values(obj, database.queries.update_reference_obj)) self.LOG.info("USERDATA movie [%s/%s] %s: %s" % (obj['FileId'], obj['MovieId'], obj['Id'], obj['Title'])) #Remove movieid, fileid, emby reference. @@ -328,16 +322,16 @@ def remove(self, item_id): self.ArtworkDBIO.delete(obj['KodiId'], obj['Media']) if obj['Media'] == 'movie': - self.MoviesDBIO.delete(*self.Utils.values(obj, queries_videos.delete_movie_obj)) + self.MoviesDBIO.delete(*self.EmbyServer.Utils.values(obj, queries_videos.delete_movie_obj)) elif obj['Media'] == 'set': - for movie in self.emby_db.get_item_by_parent_id(*self.Utils.values(obj, database.queries.get_item_by_parent_movie_obj)): + for movie in self.emby_db.get_item_by_parent_id(*self.EmbyServer.Utils.values(obj, database.queries.get_item_by_parent_movie_obj)): temp_obj = dict(obj) temp_obj['MovieId'] = movie[1] temp_obj['Movie'] = movie[0] - self.MoviesDBIO.remove_from_boxset(*self.Utils.values(temp_obj, queries_videos.delete_movie_set_obj)) - self.emby_db.update_parent_id(*self.Utils.values(temp_obj, database.queries.delete_parent_boxset_obj)) + self.MoviesDBIO.remove_from_boxset(*self.EmbyServer.Utils.values(temp_obj, queries_videos.delete_movie_set_obj)) + self.emby_db.update_parent_id(*self.EmbyServer.Utils.values(temp_obj, database.queries.delete_parent_boxset_obj)) - self.MoviesDBIO.delete_boxset(*self.Utils.values(obj, queries_videos.delete_set_obj)) + self.MoviesDBIO.delete_boxset(*self.EmbyServer.Utils.values(obj, queries_videos.delete_set_obj)) self.emby_db.remove_item(item_id) self.LOG.info("DELETE %s [%s/%s] %s" % (obj['Media'], obj['FileId'], obj['KodiId'], obj['Id'])) diff --git a/core/music.py b/core/music.py index 60adabd50..dc287a46c 100644 --- a/core/music.py +++ b/core/music.py @@ -12,23 +12,22 @@ from . import common class Music(): - def __init__(self, EmbyServer, embydb, musicdb, direct_path, Utils): + def __init__(self, EmbyServer, embydb, musicdb): self.LOG = helper.loghandler.LOG('EMBY.core.music.Music') - self.Utils = Utils self.EmbyServer = EmbyServer self.emby = embydb self.music = musicdb self.emby_db = database.emby_db.EmbyDatabase(self.emby.cursor) - self.objects = obj_ops.Objects(self.Utils) + self.objects = obj_ops.Objects(self.EmbyServer.Utils) self.item_ids = [] - self.DBVersion = int(self.Utils.window('kodidbversion.music')) - self.Common = common.Common(self.emby_db, self.objects, self.Utils, direct_path, self.EmbyServer) - self.MusicDBIO = MusicDBIO(self.music.cursor, self.DBVersion) - self.ArtworkDBIO = artwork.Artwork(musicdb.cursor, self.Utils) + self.Common = common.Common(self.emby_db, self.objects, self.EmbyServer) + self.MusicDBIO = MusicDBIO(self.music.cursor, self.EmbyServer.Utils.DatabaseFiles['music-version']) + self.ArtworkDBIO = artwork.Artwork(musicdb.cursor, self.EmbyServer.Utils) + self.APIHelper = helper.api.API(self.EmbyServer.Utils, self.EmbyServer.Data['auth.ssl']) - if not self.Utils.settings('MusicRescan.bool'): + if not self.EmbyServer.Utils.settings('MusicRescan.bool'): self.MusicDBIO.disable_rescan() - self.Utils.settings('MusicRescan.bool', True) + self.EmbyServer.Utils.settings('MusicRescan.bool', True) #If item does not exist, entry will be added. #If item exists, entry will be updated @@ -39,14 +38,13 @@ def artist(self, item, library): if not library: return False - API = helper.api.API(item, self.Utils, self.EmbyServer.auth.get_serveraddress()) obj = self.objects.map(item, 'Artist') update = True if e_item: obj['ArtistId'] = e_item[0] - if self.MusicDBIO.validate_artist(*self.Utils.values(obj, queries_music.get_artist_by_id_obj)) is None: + if self.MusicDBIO.validate_artist(*self.EmbyServer.Utils.values(obj, queries_music.get_artist_by_id_obj)) is None: update = False self.LOG.info("ArtistId %s missing from kodi. repairing the entry." % obj['ArtistId']) else: @@ -59,8 +57,8 @@ def artist(self, item, library): obj['LastScraped'] = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') obj['ArtistType'] = "MusicArtist" obj['Genre'] = " / ".join(obj['Genres'] or []) - obj['Bio'] = API.get_overview(obj['Bio']) - obj['Artwork'] = API.get_all_artwork(self.objects.map(item, 'ArtworkMusic'), True) + obj['Bio'] = self.APIHelper.get_overview(obj['Bio'], item) + obj['Artwork'] = self.APIHelper.get_all_artwork(self.objects.map(item, 'ArtworkMusic'), True) obj['Thumb'] = obj['Artwork']['Primary'] obj['Backdrops'] = obj['Artwork']['Backdrop'] or "" @@ -71,14 +69,14 @@ def artist(self, item, library): obj['Backdrops'] = "%s" % obj['Backdrops'][0] if obj['DateAdded']: - obj['DateAdded'] = self.Utils.convert_to_local(obj['DateAdded']).split('.')[0].replace('T', " ") + obj['DateAdded'] = self.EmbyServer.Utils.convert_to_local(obj['DateAdded']).split('.')[0].replace('T', " ") if update: self.artist_update(obj) else: self.artist_add(obj) - if self.DBVersion >= 82: + if self.EmbyServer.Utils.DatabaseFiles['music-version'] >= 82: self.MusicDBIO.update(obj['Genre'], obj['Bio'], obj['Thumb'], obj['LastScraped'], obj['SortName'], obj['DateAdded'], obj['ArtistId']) else: self.MusicDBIO.update(obj['Genre'], obj['Bio'], obj['Thumb'], obj['Backdrops'], obj['LastScraped'], obj['SortName'], obj['ArtistId']) @@ -91,13 +89,13 @@ def artist(self, item, library): #safety checks: It looks like Emby supports the same artist multiple times. #Kodi doesn't allow that. In case that happens we just merge the artist entries def artist_add(self, obj): - obj['ArtistId'] = self.MusicDBIO.get(*self.Utils.values(obj, queries_music.get_artist_obj)) - self.emby_db.add_reference(*self.Utils.values(obj, database.queries.add_reference_artist_obj)) + obj['ArtistId'] = self.MusicDBIO.get(*self.EmbyServer.Utils.values(obj, queries_music.get_artist_obj)) + self.emby_db.add_reference(*self.EmbyServer.Utils.values(obj, database.queries.add_reference_artist_obj)) self.LOG.info("ADD artist [%s] %s: %s" % (obj['ArtistId'], obj['Name'], obj['Id'])) #Update object to kodi def artist_update(self, obj): - self.emby_db.update_reference(*self.Utils.values(obj, database.queries.update_reference_obj)) + self.emby_db.update_reference(*self.EmbyServer.Utils.values(obj, database.queries.update_reference_obj)) self.LOG.info("UPDATE artist [%s] %s: %s" % (obj['ArtistId'], obj['Name'], obj['Id'])) #Update object to kodi @@ -108,14 +106,13 @@ def album(self, item, library): if not library: return False - API = helper.api.API(item, self.Utils, self.EmbyServer.auth.get_serveraddress()) obj = self.objects.map(item, 'Album') update = True if e_item: obj['AlbumId'] = e_item[0] - if self.MusicDBIO.validate_album(*self.Utils.values(obj, queries_music.get_album_by_id_obj)) is None: + if self.MusicDBIO.validate_album(*self.EmbyServer.Utils.values(obj, queries_music.get_album_by_id_obj)) is None: update = False else: update = False @@ -128,14 +125,14 @@ def album(self, item, library): obj['LastScraped'] = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') obj['Genres'] = obj['Genres'] or [] obj['Genre'] = " / ".join(obj['Genres']) - obj['Bio'] = API.get_overview(obj['Bio']) + obj['Bio'] = self.APIHelper.get_overview(obj['Bio'], item) obj['Artists'] = " / ".join(obj['Artists'] or []) - obj['Artwork'] = API.get_all_artwork(self.objects.map(item, 'ArtworkMusic'), True) + obj['Artwork'] = self.APIHelper.get_all_artwork(self.objects.map(item, 'ArtworkMusic'), True) obj['Thumb'] = obj['Artwork']['Primary'] obj['UniqueId'] = obj['UniqueId'] or None if obj['DateAdded']: - obj['DateAdded'] = self.Utils.convert_to_local(obj['DateAdded']).split('.')[0].replace('T', " ") + obj['DateAdded'] = self.EmbyServer.Utils.convert_to_local(obj['DateAdded']).split('.')[0].replace('T', " ") if obj['Thumb']: obj['Thumb'] = "%s" % obj['Thumb'] @@ -153,22 +150,22 @@ def album(self, item, library): #Add object to kodi def album_add(self, obj): - if self.DBVersion >= 82: - obj['AlbumId'] = self.MusicDBIO.get_album(*self.Utils.values(obj, queries_music.get_album_obj82)) + if self.EmbyServer.Utils.DatabaseFiles['music-version'] >= 82: + obj['AlbumId'] = self.MusicDBIO.get_album(*self.EmbyServer.Utils.values(obj, queries_music.get_album_obj82)) else: - obj['AlbumId'] = self.MusicDBIO.get_album(*self.Utils.values(obj, queries_music.get_album_obj)) + obj['AlbumId'] = self.MusicDBIO.get_album(*self.EmbyServer.Utils.values(obj, queries_music.get_album_obj)) - self.emby_db.add_reference(*self.Utils.values(obj, database.queries.add_reference_album_obj)) + self.emby_db.add_reference(*self.EmbyServer.Utils.values(obj, database.queries.add_reference_album_obj)) self.LOG.info("ADD album [%s] %s: %s" % (obj['AlbumId'], obj['Title'], obj['Id'])) #Update object to kodi def album_update(self, obj): - self.emby_db.update_reference(*self.Utils.values(obj, database.queries.update_reference_obj)) + self.emby_db.update_reference(*self.EmbyServer.Utils.values(obj, database.queries.update_reference_obj)) - if self.DBVersion >= 82: - self.MusicDBIO.update_album(*self.Utils.values(obj, queries_music.update_album_obj82)) + if self.EmbyServer.Utils.DatabaseFiles['music-version'] >= 82: + self.MusicDBIO.update_album(*self.EmbyServer.Utils.values(obj, queries_music.update_album_obj82)) else: - self.MusicDBIO.update_album(*self.Utils.values(obj, queries_music.update_album_obj)) + self.MusicDBIO.update_album(*self.EmbyServer.Utils.values(obj, queries_music.update_album_obj)) self.LOG.info("UPDATE album [%s] %s: %s" % (obj['AlbumId'], obj['Title'], obj['Id'])) @@ -178,15 +175,15 @@ def artist_discography(self, obj): temp_obj = dict(obj) temp_obj['Id'] = artist['Id'] temp_obj['AlbumId'] = obj['Id'] - Data = self.emby_db.get_item_by_id(*self.Utils.values(temp_obj, database.queries.get_item_obj)) + Data = self.emby_db.get_item_by_id(*self.EmbyServer.Utils.values(temp_obj, database.queries.get_item_obj)) if Data: temp_obj['ArtistId'] = Data[0] else: continue - self.MusicDBIO.add_discography(*self.Utils.values(temp_obj, queries_music.update_discography_obj)) - self.emby_db.update_parent_id(*self.Utils.values(temp_obj, database.queries.update_parent_album_obj)) + self.MusicDBIO.add_discography(*self.EmbyServer.Utils.values(temp_obj, queries_music.update_discography_obj)) + self.emby_db.update_parent_id(*self.EmbyServer.Utils.values(temp_obj, database.queries.update_parent_album_obj)) #Assign main artists to album. #Artist does not exist in emby database, create the reference @@ -195,16 +192,16 @@ def artist_link(self, obj): temp_obj = dict(obj) temp_obj['Name'] = artist['Name'] temp_obj['Id'] = artist['Id'] - Data = self.emby_db.get_item_by_id(*self.Utils.values(temp_obj, database.queries.get_item_obj)) + Data = self.emby_db.get_item_by_id(*self.EmbyServer.Utils.values(temp_obj, database.queries.get_item_obj)) if Data: temp_obj['ArtistId'] = Data[0] else: self.artist(self.EmbyServer.API.get_item(temp_obj['Id']), library=None) - temp_obj['ArtistId'] = self.emby_db.get_item_by_id(*self.Utils.values(temp_obj, database.queries.get_item_obj))[0] + temp_obj['ArtistId'] = self.emby_db.get_item_by_id(*self.EmbyServer.Utils.values(temp_obj, database.queries.get_item_obj))[0] - self.MusicDBIO.update_artist_name(*self.Utils.values(temp_obj, queries_music.update_artist_name_obj)) - self.MusicDBIO.link(*self.Utils.values(temp_obj, queries_music.update_link_obj)) + self.MusicDBIO.update_artist_name(*self.EmbyServer.Utils.values(temp_obj, queries_music.update_artist_name_obj)) + self.MusicDBIO.link(*self.EmbyServer.Utils.values(temp_obj, queries_music.update_link_obj)) self.item_ids.append(temp_obj['Id']) #Update object to kodi @@ -215,7 +212,6 @@ def song(self, item, library): if not library: return False - API = helper.api.API(item, self.Utils, self.EmbyServer.auth.get_serveraddress()) obj = self.objects.map(item, 'Song') update = True @@ -224,7 +220,7 @@ def song(self, item, library): obj['PathId'] = e_item[2] obj['AlbumId'] = e_item[3] - if self.MusicDBIO.validate_song(*self.Utils.values(obj, queries_music.get_song_by_id_obj)) is None: + if self.MusicDBIO.validate_song(*self.EmbyServer.Utils.values(obj, queries_music.get_song_by_id_obj)) is None: update = False else: update = False @@ -233,7 +229,7 @@ def song(self, item, library): obj['LibraryId'] = library['Id'] obj['LibraryName'] = library['Name'] - obj['Path'] = API.get_file_path(obj['Path']) + obj['Path'] = self.APIHelper.get_file_path(obj['Path'], item) PathValid, obj = self.Common.get_path_filename(obj, "audio") if not PathValid: @@ -241,7 +237,7 @@ def song(self, item, library): obj['Rating'] = 0 obj['Genres'] = obj['Genres'] or [] - obj['PlayCount'] = API.get_playcount(obj['Played'], obj['PlayCount']) + obj['PlayCount'] = self.APIHelper.get_playcount(obj['Played'], obj['PlayCount']) obj['Runtime'] = (obj['Runtime'] or 0) / 10000000.0 obj['Genre'] = " / ".join(obj['Genres']) obj['Artists'] = " / ".join(obj['Artists'] or []) @@ -249,17 +245,17 @@ def song(self, item, library): obj['Index'] = obj['Index'] or None obj['Disc'] = obj['Disc'] or 1 obj['EmbedCover'] = False - obj['Comment'] = API.get_overview(obj['Comment']) - obj['Artwork'] = API.get_all_artwork(self.objects.map(item, 'ArtworkMusic'), True) + obj['Comment'] = self.APIHelper.get_overview(obj['Comment'], item) + obj['Artwork'] = self.APIHelper.get_all_artwork(self.objects.map(item, 'ArtworkMusic'), True) obj['Thumb'] = obj['Artwork']['Primary'] obj['UniqueId'] = obj['UniqueId'] or None obj['Album'] = obj['Album'] or "Single" if obj['DateAdded']: - obj['DateAdded'] = self.Utils.convert_to_local(obj['DateAdded']).split('.')[0].replace('T', " ") + obj['DateAdded'] = self.EmbyServer.Utils.convert_to_local(obj['DateAdded']).split('.')[0].replace('T', " ") if obj['DatePlayed']: - obj['DatePlayed'] = self.Utils.convert_to_local(obj['DatePlayed']).split('.')[0].replace('T', " ") + obj['DatePlayed'] = self.EmbyServer.Utils.convert_to_local(obj['DatePlayed']).split('.')[0].replace('T', " ") if obj['Disc'] != 1 and obj['Index']: obj['Index'] = obj['Disc'] * 2 ** 16 + obj['Index'] @@ -272,12 +268,12 @@ def song(self, item, library): else: self.song_add(obj) - self.MusicDBIO.add_role(*self.Utils.values(obj, queries_music.update_role_obj)) # defaultt role + self.MusicDBIO.add_role(*self.EmbyServer.Utils.values(obj, queries_music.update_role_obj)) # defaultt role self.song_artist_link(obj) self.song_artist_discography(obj) obj['strAlbumArtists'] = " / ".join(obj['AlbumArtists']) - self.MusicDBIO.get_album_artist(*self.Utils.values(obj, queries_music.get_album_artist_obj)) - self.MusicDBIO.add_genres(*self.Utils.values(obj, queries_music.update_genre_song_obj)) + self.MusicDBIO.get_album_artist(*self.EmbyServer.Utils.values(obj, queries_music.get_album_artist_obj)) + self.MusicDBIO.add_genres(*self.EmbyServer.Utils.values(obj, queries_music.update_genre_song_obj)) self.ArtworkDBIO.add(obj['Artwork'], obj['SongId'], "song") self.item_ids.append(obj['Id']) @@ -294,7 +290,7 @@ def song_add(self, obj): obj['PathId'] = self.MusicDBIO.add_path(obj['Path']) if obj['SongAlbumId']: - result = self.emby_db.get_item_by_id(*self.Utils.values(obj, database.queries.get_item_song_obj)) + result = self.emby_db.get_item_by_id(*self.EmbyServer.Utils.values(obj, database.queries.get_item_song_obj)) if result: obj['AlbumId'] = result[0] @@ -306,30 +302,30 @@ def song_add(self, obj): BackupTitle = obj['Title'] obj['Title'] = "--NO INFO--" - if self.DBVersion >= 82: - obj['AlbumId'] = self.MusicDBIO.get_album(*self.Utils.values(obj, queries_music.get_single_obj82)) + if self.EmbyServer.Utils.DatabaseFiles['music-version'] >= 82: + obj['AlbumId'] = self.MusicDBIO.get_album(*self.EmbyServer.Utils.values(obj, queries_music.get_single_obj82)) else: - obj['AlbumId'] = self.MusicDBIO.get_album(*self.Utils.values(obj, queries_music.get_single_obj)) + obj['AlbumId'] = self.MusicDBIO.get_album(*self.EmbyServer.Utils.values(obj, queries_music.get_single_obj)) obj['Title'] = BackupTitle - if not self.MusicDBIO.add_song(*self.Utils.values(obj, queries_music.add_song_obj)): + if not self.MusicDBIO.add_song(*self.EmbyServer.Utils.values(obj, queries_music.add_song_obj)): obj['Index'] = None #Duplicate track number for same album - self.MusicDBIO.add_song(*self.Utils.values(obj, queries_music.add_song_obj)) + self.MusicDBIO.add_song(*self.EmbyServer.Utils.values(obj, queries_music.add_song_obj)) - self.emby_db.add_reference(*self.Utils.values(obj, database.queries.add_reference_song_obj)) + self.emby_db.add_reference(*self.EmbyServer.Utils.values(obj, database.queries.add_reference_song_obj)) self.LOG.info("ADD song [%s/%s/%s] %s: %s" % (obj['PathId'], obj['AlbumId'], obj['SongId'], obj['Id'], obj['Title'])) return True # obj #Update object to kodi def song_update(self, obj): - self.MusicDBIO.update_path(*self.Utils.values(obj, queries_music.update_path_obj)) + self.MusicDBIO.update_path(*self.EmbyServer.Utils.values(obj, queries_music.update_path_obj)) - if not self.MusicDBIO.update_song(*self.Utils.values(obj, queries_music.update_song_obj)): + if not self.MusicDBIO.update_song(*self.EmbyServer.Utils.values(obj, queries_music.update_song_obj)): obj['Index'] = None #Duplicate track number for same album - self.MusicDBIO.update_song(*self.Utils.values(obj, queries_music.update_song_obj)) + self.MusicDBIO.update_song(*self.EmbyServer.Utils.values(obj, queries_music.update_song_obj)) - self.emby_db.update_reference(*self.Utils.values(obj, database.queries.update_reference_obj)) + self.emby_db.update_reference(*self.EmbyServer.Utils.values(obj, database.queries.update_reference_obj)) self.LOG.info("UPDATE song [%s/%s/%s] %s: %s" % (obj['PathId'], obj['AlbumId'], obj['SongId'], obj['Id'], obj['Title'])) #Update the artist's discography @@ -341,21 +337,21 @@ def song_artist_discography(self, obj): temp_obj['Name'] = artist['Name'] temp_obj['Id'] = artist['Id'] artists.append(temp_obj['Name']) - Data = self.emby_db.get_item_by_id(*self.Utils.values(temp_obj, database.queries.get_item_obj)) + Data = self.emby_db.get_item_by_id(*self.EmbyServer.Utils.values(temp_obj, database.queries.get_item_obj)) if Data: temp_obj['ArtistId'] = Data[0] else: self.artist(self.EmbyServer.API.get_item(temp_obj['Id']), library=None) - temp_obj['ArtistId'] = self.emby_db.get_item_by_id(*self.Utils.values(temp_obj, database.queries.get_item_obj))[0] + temp_obj['ArtistId'] = self.emby_db.get_item_by_id(*self.EmbyServer.Utils.values(temp_obj, database.queries.get_item_obj))[0] - self.MusicDBIO.link(*self.Utils.values(temp_obj, queries_music.update_link_obj)) + self.MusicDBIO.link(*self.EmbyServer.Utils.values(temp_obj, queries_music.update_link_obj)) self.item_ids.append(temp_obj['Id']) if obj['Album']: temp_obj['Title'] = obj['Album'] temp_obj['Year'] = 0 - self.MusicDBIO.add_discography(*self.Utils.values(temp_obj, queries_music.update_discography_obj)) + self.MusicDBIO.add_discography(*self.EmbyServer.Utils.values(temp_obj, queries_music.update_discography_obj)) obj['AlbumArtists'] = artists @@ -367,15 +363,15 @@ def song_artist_link(self, obj): temp_obj['Name'] = artist['Name'] temp_obj['Id'] = artist['Id'] temp_obj['Index'] = index - Data = self.emby_db.get_item_by_id(*self.Utils.values(temp_obj, database.queries.get_item_obj)) + Data = self.emby_db.get_item_by_id(*self.EmbyServer.Utils.values(temp_obj, database.queries.get_item_obj)) if Data: temp_obj['ArtistId'] = Data[0] else: self.artist(self.EmbyServer.API.get_item(temp_obj['Id']), library=None) - temp_obj['ArtistId'] = self.emby_db.get_item_by_id(*self.Utils.values(temp_obj, database.queries.get_item_obj))[0] + temp_obj['ArtistId'] = self.emby_db.get_item_by_id(*self.EmbyServer.Utils.values(temp_obj, database.queries.get_item_obj))[0] - self.MusicDBIO.link_song_artist(*self.Utils.values(temp_obj, queries_music.update_song_artist_obj)) + self.MusicDBIO.link_song_artist(*self.EmbyServer.Utils.values(temp_obj, queries_music.update_song_artist_obj)) self.item_ids.append(temp_obj['Id']) #This updates: Favorite, LastPlayedDate, Playcount, PlaybackPositionTicks @@ -394,11 +390,11 @@ def userdata(self, item): if obj['Media'] == 'song': if obj['DatePlayed']: - obj['DatePlayed'] = self.Utils.convert_to_local(obj['DatePlayed']).split('.')[0].replace('T', " ") + obj['DatePlayed'] = self.EmbyServer.Utils.convert_to_local(obj['DatePlayed']).split('.')[0].replace('T', " ") - self.MusicDBIO.rate_song(*self.Utils.values(obj, queries_music.update_song_rating_obj)) + self.MusicDBIO.rate_song(*self.EmbyServer.Utils.values(obj, queries_music.update_song_rating_obj)) - self.emby_db.update_reference(*self.Utils.values(obj, database.queries.update_reference_obj)) + self.emby_db.update_reference(*self.EmbyServer.Utils.values(obj, database.queries.update_reference_obj)) self.LOG.info("USERDATA %s [%s] %s: %s" % (obj['Media'], obj['KodiId'], obj['Id'], obj['Title'])) #This updates: Favorite, LastPlayedDate, Playcount, PlaybackPositionTicks @@ -418,40 +414,40 @@ def remove(self, item_id): self.remove_song(obj['KodiId'], obj['Id']) self.emby_db.remove_wild_item(obj['Id']) - for item in self.emby_db.get_item_by_wild_id(*self.Utils.values(obj, database.queries.get_item_by_wild_obj)): + for item in self.emby_db.get_item_by_wild_id(*self.EmbyServer.Utils.values(obj, database.queries.get_item_by_wild_obj)): if item[1] == 'album': temp_obj = dict(obj) temp_obj['ParentId'] = item[0] - if not self.emby_db.get_item_by_parent_id(*self.Utils.values(temp_obj, database.queries.get_item_by_parent_song_obj)): + if not self.emby_db.get_item_by_parent_id(*self.EmbyServer.Utils.values(temp_obj, database.queries.get_item_by_parent_song_obj)): self.remove_album(temp_obj['ParentId'], obj['Id']) elif obj['Media'] == 'album': obj['ParentId'] = obj['KodiId'] - for song in self.emby_db.get_item_by_parent_id(*self.Utils.values(obj, database.queries.get_item_by_parent_song_obj)): + for song in self.emby_db.get_item_by_parent_id(*self.EmbyServer.Utils.values(obj, database.queries.get_item_by_parent_song_obj)): self.remove_song(song[1], obj['Id']) - self.emby_db.remove_items_by_parent_id(*self.Utils.values(obj, database.queries.delete_item_by_parent_song_obj)) + self.emby_db.remove_items_by_parent_id(*self.EmbyServer.Utils.values(obj, database.queries.delete_item_by_parent_song_obj)) self.remove_album(obj['KodiId'], obj['Id']) elif obj['Media'] == 'artist': obj['ParentId'] = obj['KodiId'] - for album in self.emby_db.get_item_by_parent_id(*self.Utils.values(obj, database.queries.get_item_by_parent_album_obj)): + for album in self.emby_db.get_item_by_parent_id(*self.EmbyServer.Utils.values(obj, database.queries.get_item_by_parent_album_obj)): temp_obj = dict(obj) temp_obj['ParentId'] = album[1] - for song in self.emby_db.get_item_by_parent_id(*self.Utils.values(temp_obj, database.queries.get_item_by_parent_song_obj)): + for song in self.emby_db.get_item_by_parent_id(*self.EmbyServer.Utils.values(temp_obj, database.queries.get_item_by_parent_song_obj)): self.remove_song(song[1], obj['Id']) - self.emby_db.remove_items_by_parent_id(*self.Utils.values(temp_obj, database.queries.delete_item_by_parent_song_obj)) - self.emby_db.remove_items_by_parent_id(*self.Utils.values(temp_obj, database.queries.delete_item_by_parent_artist_obj)) + self.emby_db.remove_items_by_parent_id(*self.EmbyServer.Utils.values(temp_obj, database.queries.delete_item_by_parent_song_obj)) + self.emby_db.remove_items_by_parent_id(*self.EmbyServer.Utils.values(temp_obj, database.queries.delete_item_by_parent_artist_obj)) self.remove_album(temp_obj['ParentId'], obj['Id']) - self.emby_db.remove_items_by_parent_id(*self.Utils.values(obj, database.queries.delete_item_by_parent_album_obj)) + self.emby_db.remove_items_by_parent_id(*self.EmbyServer.Utils.values(obj, database.queries.delete_item_by_parent_album_obj)) self.remove_artist(obj['KodiId'], obj['Id']) - self.emby_db.remove_item(*self.Utils.values(obj, database.queries.delete_item_obj)) + self.emby_db.remove_item(*self.EmbyServer.Utils.values(obj, database.queries.delete_item_obj)) def remove_artist(self, kodi_id, item_id): self.ArtworkDBIO.delete(kodi_id, "artist") @@ -484,12 +480,12 @@ def get_child(self, item_id): obj['ParentId'] = obj['KodiId'] - for album in self.emby_db.get_item_by_parent_id(*self.Utils.values(obj, database.queries.get_item_by_parent_album_obj)): + for album in self.emby_db.get_item_by_parent_id(*self.EmbyServer.Utils.values(obj, database.queries.get_item_by_parent_album_obj)): temp_obj = dict(obj) temp_obj['ParentId'] = album[1] child.append((album[0],)) - for song in self.emby_db.get_item_by_parent_id(*self.Utils.values(temp_obj, database.queries.get_item_by_parent_song_obj)): + for song in self.emby_db.get_item_by_parent_id(*self.EmbyServer.Utils.values(temp_obj, database.queries.get_item_by_parent_song_obj)): child.append((song[0],)) return child diff --git a/core/musicvideos.py b/core/musicvideos.py index 27869496f..36fc525cf 100644 --- a/core/musicvideos.py +++ b/core/musicvideos.py @@ -14,19 +14,19 @@ from . import common class MusicVideos(): - def __init__(self, EmbyServer, embydb, videodb, direct_path, Utils): + def __init__(self, EmbyServer, embydb, videodb): self.LOG = helper.loghandler.LOG('EMBY.core.musicvideos.MusicVideos') - self.Utils = Utils self.EmbyServer = EmbyServer self.emby = embydb self.video = videodb self.emby_db = database.emby_db.EmbyDatabase(embydb.cursor) - self.objects = obj_ops.Objects(self.Utils) + self.objects = obj_ops.Objects(self.EmbyServer.Utils) self.item_ids = [] - self.Common = common.Common(self.emby_db, self.objects, self.Utils, direct_path, self.EmbyServer) + self.Common = common.Common(self.emby_db, self.objects, self.EmbyServer) self.MusicVideosDBIO = MusicVideosDBIO(videodb.cursor) - self.KodiDBIO = kodi.Kodi(videodb.cursor, Utils) - self.ArtworkDBIO = artwork.Artwork(videodb.cursor, self.Utils) + self.KodiDBIO = kodi.Kodi(videodb.cursor, self.EmbyServer.Utils) + self.ArtworkDBIO = artwork.Artwork(videodb.cursor, self.EmbyServer.Utils) + self.APIHelper = helper.api.API(self.EmbyServer.Utils, self.EmbyServer.Data['auth.ssl']) def musicvideo(self, item, library): ''' If item does not exist, entry will be added. @@ -41,7 +41,6 @@ def musicvideo(self, item, library): if not library: return False - API = helper.api.API(item, self.Utils, self.EmbyServer.auth.get_serveraddress()) obj = self.objects.map(item, 'MusicVideo') obj['Item'] = item obj['Library'] = library @@ -54,7 +53,7 @@ def musicvideo(self, item, library): obj['FileId'] = e_item[1] obj['PathId'] = e_item[2] - if self.MusicVideosDBIO.get(*self.Utils.values(obj, queries_videos.get_musicvideo_obj)) is None: + if self.MusicVideosDBIO.get(*self.EmbyServer.Utils.values(obj, queries_videos.get_musicvideo_obj)) is None: update = False self.LOG.info("MvideoId %s missing from kodi. repairing the entry" % obj['MvideoId']) else: @@ -70,36 +69,36 @@ def musicvideo(self, item, library): obj['Path'] = obj['Item']['MediaSources'][0]['Path'] #don't use 3d movies as default - if "3d" in self.Utils.StringMod(obj['Item']['MediaSources'][0]['Path']): + if "3d" in self.EmbyServer.Utils.StringMod(obj['Item']['MediaSources'][0]['Path']): for DataSource in obj['Item']['MediaSources']: - if not "3d" in self.Utils.StringMod(DataSource['Path']): + if not "3d" in self.EmbyServer.Utils.StringMod(DataSource['Path']): DataSource = self.objects.MapMissingData(DataSource, 'MediaSources') obj['Path'] = DataSource['Path'] obj['MediaSourceID'] = DataSource['Id'] obj['Runtime'] = DataSource['RunTimeTicks'] break - obj['Path'] = API.get_file_path(obj['Path']) + obj['Path'] = self.APIHelper.get_file_path(obj['Path'], item) obj['LibraryId'] = library['Id'] obj['LibraryName'] = library['Name'] obj['Genres'] = obj['Genres'] or [] obj['ArtistItems'] = obj['ArtistItems'] or [] - obj['Studios'] = [API.validate_studio(studio) for studio in (obj['Studios'] or [])] - obj['Plot'] = API.get_overview(obj['Plot']) - obj['DateAdded'] = self.Utils.convert_to_local(obj['DateAdded']).split('.')[0].replace('T', " ") - obj['DatePlayed'] = None if not obj['DatePlayed'] else self.Utils.convert_to_local(obj['DatePlayed']).split('.')[0].replace('T', " ") - obj['PlayCount'] = API.get_playcount(obj['Played'], obj['PlayCount']) - obj['Resume'] = API.adjust_resume((obj['Resume'] or 0) / 10000000.0, self.Utils) + obj['Studios'] = [self.APIHelper.validate_studio(studio) for studio in (obj['Studios'] or [])] + obj['Plot'] = self.APIHelper.get_overview(obj['Plot'], item) + obj['DateAdded'] = self.EmbyServer.Utils.convert_to_local(obj['DateAdded']).split('.')[0].replace('T', " ") + obj['DatePlayed'] = None if not obj['DatePlayed'] else self.EmbyServer.Utils.convert_to_local(obj['DatePlayed']).split('.')[0].replace('T', " ") + obj['PlayCount'] = self.APIHelper.get_playcount(obj['Played'], obj['PlayCount']) + obj['Resume'] = self.APIHelper.adjust_resume((obj['Resume'] or 0) / 10000000.0) obj['Runtime'] = round(float((obj['Runtime'] or 0) / 10000000.0), 6) - obj['Premiere'] = self.Utils.convert_to_local(obj['Premiere']) if obj['Premiere'] else datetime.date(int(str(obj['Year'])[:4]) if obj['Year'] else 2021, 1, 1) + obj['Premiere'] = self.EmbyServer.Utils.convert_to_local(obj['Premiere']) if obj['Premiere'] else datetime.date(int(str(obj['Year'])[:4]) if obj['Year'] else 2021, 1, 1) obj['Genre'] = " / ".join(obj['Genres']) obj['Studio'] = " / ".join(obj['Studios']) obj['Artists'] = " / ".join(obj['Artists'] or []) obj['Directors'] = " / ".join(obj['Directors'] or []) - obj['Video'] = API.video_streams(obj['Video'] or [], obj['Container']) - obj['Audio'] = API.audio_streams(obj['Audio'] or []) - obj['Streams'] = API.media_streams(obj['Video'], obj['Audio'], obj['Subtitles']) - obj['Artwork'] = API.get_all_artwork(self.objects.map(item, 'Artwork')) + obj['Video'] = self.APIHelper.video_streams(obj['Video'] or [], obj['Container'], item) + obj['Audio'] = self.APIHelper.audio_streams(obj['Audio'] or []) + obj['Streams'] = self.APIHelper.media_streams(obj['Video'], obj['Audio'], obj['Subtitles']) + obj['Artwork'] = self.APIHelper.get_all_artwork(self.objects.map(item, 'Artwork')) PathValid, obj = self.Common.get_path_filename(obj, "musicvideos") if not PathValid: @@ -112,7 +111,7 @@ def musicvideo(self, item, library): artist['Type'] = "Artist" obj['People'] = obj['People'] or [] + obj['ArtistItems'] - obj['People'] = API.get_people_artwork(obj['People']) + obj['People'] = self.APIHelper.get_people_artwork(obj['People']) if obj['Index'] is None and obj['SortTitle'] is not None: search = re.search(r'^\d+\s?', obj['SortTitle']) @@ -134,36 +133,36 @@ def musicvideo(self, item, library): else: self.musicvideo_add(obj) - self.KodiDBIO.update_path(*self.Utils.values(obj, queries_videos.update_path_mvideo_obj)) - self.KodiDBIO.update_file(*self.Utils.values(obj, queries_videos.update_file_obj)) - self.KodiDBIO.add_tags(*self.Utils.values(obj, queries_videos.add_tags_mvideo_obj)) - self.KodiDBIO.add_genres(*self.Utils.values(obj, queries_videos.add_genres_mvideo_obj)) - self.KodiDBIO.add_studios(*self.Utils.values(obj, queries_videos.add_studios_mvideo_obj)) - self.KodiDBIO.add_playstate(*self.Utils.values(obj, queries_videos.add_bookmark_obj)) - self.KodiDBIO.add_people(*self.Utils.values(obj, queries_videos.add_people_mvideo_obj)) - self.KodiDBIO.add_streams(*self.Utils.values(obj, queries_videos.add_streams_obj)) + self.KodiDBIO.update_path(*self.EmbyServer.Utils.values(obj, queries_videos.update_path_mvideo_obj)) + self.KodiDBIO.update_file(*self.EmbyServer.Utils.values(obj, queries_videos.update_file_obj)) + self.KodiDBIO.add_tags(*self.EmbyServer.Utils.values(obj, queries_videos.add_tags_mvideo_obj)) + self.KodiDBIO.add_genres(*self.EmbyServer.Utils.values(obj, queries_videos.add_genres_mvideo_obj)) + self.KodiDBIO.add_studios(*self.EmbyServer.Utils.values(obj, queries_videos.add_studios_mvideo_obj)) + self.KodiDBIO.add_playstate(*self.EmbyServer.Utils.values(obj, queries_videos.add_bookmark_obj)) + self.KodiDBIO.add_people(*self.EmbyServer.Utils.values(obj, queries_videos.add_people_mvideo_obj)) + self.KodiDBIO.add_streams(*self.EmbyServer.Utils.values(obj, queries_videos.add_streams_obj)) self.ArtworkDBIO.add(obj['Artwork'], obj['MvideoId'], "musicvideo") self.item_ids.append(obj['Id']) if "StackTimes" in obj: - self.KodiDBIO.add_stacktimes(*self.Utils.values(obj, queries_videos.add_stacktimes_obj)) + self.KodiDBIO.add_stacktimes(*self.EmbyServer.Utils.values(obj, queries_videos.add_stacktimes_obj)) return not update #Add object to kodi def musicvideo_add(self, obj): obj = self.Common.Streamdata_add(obj, False) - obj['PathId'] = self.KodiDBIO.add_path(*self.Utils.values(obj, queries_videos.add_path_obj)) - obj['FileId'] = self.KodiDBIO.add_file(*self.Utils.values(obj, queries_videos.add_file_obj)) - self.MusicVideosDBIO.add(*self.Utils.values(obj, queries_videos.add_musicvideo_obj)) - self.emby_db.add_reference(*self.Utils.values(obj, database.queries.add_reference_mvideo_obj)) + obj['PathId'] = self.KodiDBIO.add_path(*self.EmbyServer.Utils.values(obj, queries_videos.add_path_obj)) + obj['FileId'] = self.KodiDBIO.add_file(*self.EmbyServer.Utils.values(obj, queries_videos.add_file_obj)) + self.MusicVideosDBIO.add(*self.EmbyServer.Utils.values(obj, queries_videos.add_musicvideo_obj)) + self.emby_db.add_reference(*self.EmbyServer.Utils.values(obj, database.queries.add_reference_mvideo_obj)) self.LOG.info("ADD mvideo [%s/%s/%s] %s: %s" % (obj['PathId'], obj['FileId'], obj['MvideoId'], obj['Id'], obj['Title'])) #Update object to kodi def musicvideo_update(self, obj): obj = self.Common.Streamdata_add(obj, True) - self.MusicVideosDBIO.update(*self.Utils.values(obj, queries_videos.update_musicvideo_obj)) - self.emby_db.update_reference(*self.Utils.values(obj, database.queries.update_reference_obj)) + self.MusicVideosDBIO.update(*self.EmbyServer.Utils.values(obj, queries_videos.update_musicvideo_obj)) + self.emby_db.update_reference(*self.EmbyServer.Utils.values(obj, database.queries.update_reference_obj)) self.LOG.info("UPDATE mvideo [%s/%s/%s] %s: %s" % (obj['PathId'], obj['FileId'], obj['MvideoId'], obj['Id'], obj['Title'])) def userdata(self, item): @@ -171,7 +170,6 @@ def userdata(self, item): Poster with progress bar ''' e_item = self.emby_db.get_item_by_id(item['Id']) - API = helper.api.API(item, self.Utils, self.EmbyServer.auth.get_serveraddress()) obj = self.objects.map(item, 'MusicVideoUserData') obj['Item'] = item @@ -182,20 +180,20 @@ def userdata(self, item): return obj = self.Common.Streamdata_add(obj, True) - obj['Resume'] = API.adjust_resume((obj['Resume'] or 0) / 10000000.0, self.Utils) + obj['Resume'] = self.APIHelper.adjust_resume((obj['Resume'] or 0) / 10000000.0) obj['Runtime'] = round(float((obj['Runtime'] or 0) / 10000000.0), 6) - obj['PlayCount'] = API.get_playcount(obj['Played'], obj['PlayCount']) + obj['PlayCount'] = self.APIHelper.get_playcount(obj['Played'], obj['PlayCount']) if obj['DatePlayed']: - obj['DatePlayed'] = self.Utils.convert_to_local(obj['DatePlayed']).split('.')[0].replace('T', " ") + obj['DatePlayed'] = self.EmbyServer.Utils.convert_to_local(obj['DatePlayed']).split('.')[0].replace('T', " ") if obj['Favorite']: - self.KodiDBIO.get_tag(*self.Utils.values(obj, queries_videos.get_tag_mvideo_obj)) + self.KodiDBIO.get_tag(*self.EmbyServer.Utils.values(obj, queries_videos.get_tag_mvideo_obj)) else: - self.KodiDBIO.remove_tag(*self.Utils.values(obj, queries_videos.delete_tag_mvideo_obj)) + self.KodiDBIO.remove_tag(*self.EmbyServer.Utils.values(obj, queries_videos.delete_tag_mvideo_obj)) - self.KodiDBIO.add_playstate(*self.Utils.values(obj, queries_videos.add_bookmark_obj)) - self.emby_db.update_reference(*self.Utils.values(obj, database.queries.update_reference_obj)) + self.KodiDBIO.add_playstate(*self.EmbyServer.Utils.values(obj, queries_videos.add_bookmark_obj)) + self.emby_db.update_reference(*self.EmbyServer.Utils.values(obj, database.queries.update_reference_obj)) self.LOG.info("USERDATA mvideo [%s/%s] %s: %s" % (obj['FileId'], obj['MvideoId'], obj['Id'], obj['Title'])) #Remove mvideoid, fileid, pathid, emby reference @@ -211,8 +209,8 @@ def remove(self, item_id): return self.ArtworkDBIO.delete(obj['MvideoId'], "musicvideo") - self.MusicVideosDBIO.delete(*self.Utils.values(obj, queries_videos.delete_musicvideo_obj)) - self.emby_db.remove_item(*self.Utils.values(obj, database.queries.delete_item_obj)) + self.MusicVideosDBIO.delete(*self.EmbyServer.Utils.values(obj, queries_videos.delete_musicvideo_obj)) + self.emby_db.remove_item(*self.EmbyServer.Utils.values(obj, database.queries.delete_item_obj)) self.LOG.info("DELETE musicvideo %s [%s/%s] %s" % (obj['MvideoId'], obj['PathId'], obj['FileId'], obj['Id'])) class MusicVideosDBIO(): diff --git a/core/obj_ops.py b/core/obj_ops.py index 4c146798c..79e15737f 100644 --- a/core/obj_ops.py +++ b/core/obj_ops.py @@ -6,10 +6,6 @@ def __init__(self, Utils): self.Utils = Utils self.mapped_item = {} self.objects = { - "video": "special://database/MyVideos119.db", - "music": "special://database/MyMusic82.db", - "texture": "special://database/Textures13.db", - "emby": "special://database/emby.db", "MovieProviderName": "imdb", "Movie": { "Id": "Id", @@ -129,7 +125,6 @@ def __init__(self, Utils): "AirsAfterSeason": "AirsAfterSeasonNumber", "AirsBeforeSeason": "AirsBeforeSeasonNumber,SortParentIndexNumber", "AirsBeforeEpisode": "AirsBeforeEpisodeNumber,SortIndexNumber", - "MultiEpisode": "IndexNumberEnd", "Played": "UserData/Played", "PlayCount": "UserData/PlayCount", "DateAdded": "DateCreated", @@ -355,14 +350,13 @@ def __init__(self, Utils): "DatePlayed": "UserData/LastPlayedDate", "UniqueId": "ProviderIds/MusicBrainzTrackId,ProviderIds/MusicBrainzAlbum,ProviderIds/MusicBrainzArtist", "Comment": "Overview", - "FileDate": "DateCreated", + "DateAdded": "DateCreated", "Played": "UserData/Played" }, "BrowsePhoto": { "Id": "Id", "Title": "Name", "Type": "Type", - "FileDate": "DateCreated", "Width": "Width", "Height": "Height", "Size": "Size", @@ -370,7 +364,8 @@ def __init__(self, Utils): "CameraMake": "CameraMake", "CameraModel": "CameraModel", "ExposureTime": "ExposureTime", - "FocalLength": "FocalLength" + "FocalLength": "FocalLength", + "DateAdded": "DateCreated" }, "BrowseFolder": { "Id": "Id", @@ -498,7 +493,7 @@ def MapMissingData(self, item, mapping_name): for key, _ in list(mapping.items()): if not key in item: - item[key] = "" + item[key] = None return item @@ -543,9 +538,9 @@ def map(self, item, mapping_name): if ':' in obj_param: result = [] - for d in self.__recursiveloop__(obj, obj_param): + for d in self.recursiveloop(obj, obj_param): - if obj_filters and self.__filters__(d, obj_filters): + if obj_filters and self.filters(d, obj_filters): result.append(d) elif not obj_filters: result.append(d) @@ -553,12 +548,12 @@ def map(self, item, mapping_name): obj = result obj_filters = {} elif '/' in obj_param: - obj = self.__recursive__(obj, obj_param) + obj = self.recursive(obj, obj_param) elif obj is item and obj is not None: obj = item.get(obj_param) if obj_filters and obj: - if not self.__filters__(obj, obj_filters): + if not self.filters(obj, obj_filters): obj = None if obj is None and len(params) != params.index(param): @@ -577,28 +572,28 @@ def map(self, item, mapping_name): return self.mapped_item - def __recursiveloop__(self, obj, keys): + def recursiveloop(self, obj, keys): first, rest = keys.split(':', 1) - obj = self.__recursive__(obj, first) + obj = self.recursive(obj, first) if obj: if rest: for item in obj: - self.__recursiveloop__(item, rest) + self.recursiveloop(item, rest) else: for item in obj: yield item - def __recursive__(self, obj, keys): + def recursive(self, obj, keys): for string in keys.split('/'): if not obj: - return False + return None obj = obj[int(string)] if string.isdigit() else obj.get(string) return obj - def __filters__(self, obj, filters): + def filters(self, obj, filters): result = False for key, value in iter(list(filters.items())): @@ -607,8 +602,7 @@ def __filters__(self, obj, filters): if value.startswith('!'): inverse = True value = value.split('!', 1)[1] - - if value.lower() == "null": + elif value.lower() == "null": value = None result = obj.get(key) != value if inverse else obj.get(key) == value diff --git a/core/queries_videos.py b/core/queries_videos.py index d1c439035..d00f27b92 100644 --- a/core/queries_videos.py +++ b/core/queries_videos.py @@ -129,7 +129,17 @@ update_studios = """INSERT OR REPLACE INTO studio_link(studio_id, media_id, media_type) VALUES (?, ?, ?)""" update_playcount = """UPDATE files SET playCount = ?, lastPlayed = ? WHERE idFile = ?""" update_tag = """INSERT OR REPLACE INTO tag_link(tag_id, media_id, media_type) VALUES (?, ?, ?)""" + + + + update_art = """UPDATE art SET url = ? WHERE media_id = ? AND media_type = ? AND type = ?""" + + + + + + update_actor = """INSERT OR REPLACE INTO actor_link(actor_id, media_id, media_type, role, cast_order) VALUES (?, ?, ?, ?, ?)""" update_link = """ INSERT OR REPLACE INTO {LinkType}(actor_id, media_id, media_type) VALUES (?, ?, ?) """ get_update_link = """SELECT * FROM {LinkType} WHERE actor_id = ? AND media_id = ? AND media_type = ? COLLATE NOCASE""" diff --git a/core/tvshows.py b/core/tvshows.py index 468bbef43..53b303e64 100644 --- a/core/tvshows.py +++ b/core/tvshows.py @@ -12,31 +12,21 @@ from . import artwork from . import kodi - - -import xbmc - - - - class TVShows(): - def __init__(self, EmbyServer, embydb, videodb, direct_path, Utils, Downloader, update_library=False): + def __init__(self, EmbyServer, embydb, videodb, update_library=False): self.LOG = helper.loghandler.LOG('EMBY.core.tvshows.TVShows') - self.Utils = Utils self.update_library = update_library self.EmbyServer = EmbyServer self.emby = embydb self.video = videodb - self.direct_path = direct_path self.emby_db = database.emby_db.EmbyDatabase(embydb.cursor) - self.objects = obj_ops.Objects(self.Utils) + self.objects = obj_ops.Objects(self.EmbyServer.Utils) self.item_ids = [] - self.display_multiep = self.Utils.settings('displayMultiEpLabel.bool') - self.Downloader = Downloader - self.Common = common.Common(self.emby_db, self.objects, self.Utils, self.direct_path, self.EmbyServer) - self.KodiDBIO = kodi.Kodi(videodb.cursor, Utils) + self.Common = common.Common(self.emby_db, self.objects, self.EmbyServer) + self.KodiDBIO = kodi.Kodi(videodb.cursor, self.EmbyServer.Utils) self.TVShowsDBIO = TVShowsDBIO(videodb.cursor) - self.ArtworkDBIO = artwork.Artwork(videodb.cursor, self.Utils) + self.ArtworkDBIO = artwork.Artwork(videodb.cursor, self.EmbyServer.Utils) + self.APIHelper = helper.api.API(self.EmbyServer.Utils, self.EmbyServer.Data['auth.ssl']) def tvshow(self, item, library, pooling=None, redirect=None): e_item = self.emby_db.get_item_by_id(item['Id']) @@ -45,7 +35,6 @@ def tvshow(self, item, library, pooling=None, redirect=None): if not library: return False - API = helper.api.API(item, self.Utils, self.EmbyServer.auth.get_serveraddress()) obj = self.objects.map(item, 'Series') obj['Item'] = item obj['Library'] = library @@ -53,9 +42,9 @@ def tvshow(self, item, library, pooling=None, redirect=None): obj['LibraryName'] = library['Name'] update = True - if not self.Utils.settings('syncEmptyShows.bool') and not obj['RecursiveCount']: + if not obj['RecursiveCount']: self.LOG.info("Skipping empty show %s: %s" % (obj['Title'], obj['Id'])) - TVShows(self.EmbyServer, self.emby, self.video, self.direct_path, self.Utils, self.Downloader, False).remove(obj['Id']) + TVShows(self.EmbyServer, self.emby, self.video, False).remove(obj['Id']) return False if pooling is None: @@ -63,13 +52,13 @@ def tvshow(self, item, library, pooling=None, redirect=None): if str(StackedID) != obj['Id']: - return TVShows(self.EmbyServer, self.emby, self.video, self.direct_path, self.Utils, self.Downloader, False).tvshow(obj['Item'], obj['Library'], StackedID, False) + return TVShows(self.EmbyServer, self.emby, self.video, False).tvshow(obj['Item'], obj['Library'], StackedID, False) if e_item: obj['ShowId'] = e_item[0] obj['PathId'] = e_item[2] - if self.TVShowsDBIO.get(*self.Utils.values(obj, queries_videos.get_tvshow_obj)) is None: + if self.TVShowsDBIO.get(*self.EmbyServer.Utils.values(obj, queries_videos.get_tvshow_obj)) is None: update = False self.LOG.info("ShowId %s missing from kodi. repairing the entry." % obj['ShowId']) else: @@ -77,16 +66,16 @@ def tvshow(self, item, library, pooling=None, redirect=None): self.LOG.debug("ShowId %s not found" % obj['Id']) obj['ShowId'] = self.TVShowsDBIO.create_entry() - obj['Path'] = API.get_file_path(obj['Item']['Path']) + obj['Path'] = self.APIHelper.get_file_path(obj['Item']['Path'], item) obj['Genres'] = obj['Genres'] or [] obj['People'] = obj['People'] or [] - obj['Mpaa'] = API.get_mpaa(obj['Mpaa']) - obj['Studios'] = [API.validate_studio(studio) for studio in (obj['Studios'] or [])] + obj['Mpaa'] = self.APIHelper.get_mpaa(obj['Mpaa'], item) + obj['Studios'] = [self.APIHelper.validate_studio(studio) for studio in (obj['Studios'] or [])] obj['Genre'] = " / ".join(obj['Genres']) - obj['People'] = API.get_people_artwork(obj['People']) - obj['Plot'] = API.get_overview(obj['Plot']) + obj['People'] = self.APIHelper.get_people_artwork(obj['People']) + obj['Plot'] = self.APIHelper.get_overview(obj['Plot'], item) obj['Studio'] = " / ".join(obj['Studios']) - obj['Artwork'] = API.get_all_artwork(self.objects.map(item, 'Artwork')) + obj['Artwork'] = self.APIHelper.get_all_artwork(self.objects.map(item, 'Artwork')) if obj['Status'] != 'Ended': obj['Status'] = None @@ -95,7 +84,7 @@ def tvshow(self, item, library, pooling=None, redirect=None): return "Invalid Filepath" if obj['Premiere']: - obj['Premiere'] = str(self.Utils.convert_to_local(obj['Premiere'])).split('.')[0].replace('T', " ") + obj['Premiere'] = str(self.EmbyServer.Utils.convert_to_local(obj['Premiere'])).split('.')[0].replace('T', " ") tags = [] tags.extend(obj['TagItems'] or obj['Tags'] or []) @@ -114,7 +103,7 @@ def tvshow(self, item, library, pooling=None, redirect=None): if pooling: obj['SeriesId'] = pooling self.LOG.info("POOL %s [%s/%s]" % (obj['Title'], obj['Id'], obj['SeriesId'])) - self.emby_db.add_reference(*self.Utils.values(obj, database.queries.add_reference_pool_obj)) + self.emby_db.add_reference(*self.EmbyServer.Utils.values(obj, database.queries.add_reference_pool_obj)) @@ -124,17 +113,17 @@ def tvshow(self, item, library, pooling=None, redirect=None): return True - self.TVShowsDBIO.link(*self.Utils.values(obj, queries_videos.update_tvshow_link_obj)) - self.KodiDBIO.update_path(*self.Utils.values(obj, queries_videos.update_path_tvshow_obj)) - self.KodiDBIO.add_tags(*self.Utils.values(obj, queries_videos.add_tags_tvshow_obj)) - self.KodiDBIO.add_people(*self.Utils.values(obj, queries_videos.add_people_tvshow_obj)) - self.KodiDBIO.add_genres(*self.Utils.values(obj, queries_videos.add_genres_tvshow_obj)) - self.KodiDBIO.add_studios(*self.Utils.values(obj, queries_videos.add_studios_tvshow_obj)) + self.TVShowsDBIO.link(*self.EmbyServer.Utils.values(obj, queries_videos.update_tvshow_link_obj)) + self.KodiDBIO.update_path(*self.EmbyServer.Utils.values(obj, queries_videos.update_path_tvshow_obj)) + self.KodiDBIO.add_tags(*self.EmbyServer.Utils.values(obj, queries_videos.add_tags_tvshow_obj)) + self.KodiDBIO.add_people(*self.EmbyServer.Utils.values(obj, queries_videos.add_people_tvshow_obj)) + self.KodiDBIO.add_genres(*self.EmbyServer.Utils.values(obj, queries_videos.add_genres_tvshow_obj)) + self.KodiDBIO.add_studios(*self.EmbyServer.Utils.values(obj, queries_videos.add_studios_tvshow_obj)) self.ArtworkDBIO.add(obj['Artwork'], obj['ShowId'], "tvshow") self.item_ids.append(obj['Id']) if "StackTimes" in obj: - self.KodiDBIO.add_stacktimes(*self.Utils.values(obj, queries_videos.add_stacktimes_obj)) + self.KodiDBIO.add_stacktimes(*self.EmbyServer.Utils.values(obj, queries_videos.add_stacktimes_obj)) if redirect: self.LOG.info("tvshow added as a redirect") @@ -159,11 +148,11 @@ def tvshow(self, item, library, pooling=None, redirect=None): except TypeError: self.season(season, library, obj['ShowId']) - season_id = self.TVShowsDBIO.get_season(*self.Utils.values(obj, queries_videos.get_season_special_obj)) + season_id = self.TVShowsDBIO.get_season(*self.EmbyServer.Utils.values(obj, queries_videos.get_season_special_obj)) self.ArtworkDBIO.add(obj['Artwork'], season_id, "season") for season in season_episodes: - for episodes in self.Downloader.get_episode_by_season(season_episodes[season], season): + for episodes in self.EmbyServer.API.get_episode_by_season(season_episodes[season], season): for episode in episodes['Items']: Ret = self.episode(episode, library) @@ -175,9 +164,9 @@ def tvshow(self, item, library, pooling=None, redirect=None): #Add object to kodi def tvshow_add(self, obj): obj['RatingId'] = self.KodiDBIO.create_entry_rating() - self.KodiDBIO.add_ratings(*self.Utils.values(obj, queries_videos.add_rating_tvshow_obj)) + self.KodiDBIO.add_ratings(*self.EmbyServer.Utils.values(obj, queries_videos.add_rating_tvshow_obj)) obj['Unique'] = self.TVShowsDBIO.create_entry_unique_id() - self.TVShowsDBIO.add_unique_id(*self.Utils.values(obj, queries_videos.add_unique_id_tvshow_obj)) + self.TVShowsDBIO.add_unique_id(*self.EmbyServer.Utils.values(obj, queries_videos.add_unique_id_tvshow_obj)) for provider in obj['UniqueIds'] or {}: unique_id = obj['UniqueIds'][provider] @@ -185,22 +174,22 @@ def tvshow_add(self, obj): if provider != 'tvdb': temp_obj = dict(obj, ProviderName=provider, UniqueId=unique_id, Unique=self.TVShowsDBIO.create_entry_unique_id()) - self.TVShowsDBIO.add_unique_id(*self.Utils.values(temp_obj, queries_videos.add_unique_id_tvshow_obj)) + self.TVShowsDBIO.add_unique_id(*self.EmbyServer.Utils.values(temp_obj, queries_videos.add_unique_id_tvshow_obj)) obj['TopPathId'] = self.KodiDBIO.add_path(obj['TopLevel']) - self.KodiDBIO.update_path(*self.Utils.values(obj, queries_videos.update_path_toptvshow_obj)) - obj['PathId'] = self.KodiDBIO.add_path(*self.Utils.values(obj, queries_videos.get_path_obj)) - self.TVShowsDBIO.add(*self.Utils.values(obj, queries_videos.add_tvshow_obj)) - self.emby_db.add_reference(*self.Utils.values(obj, database.queries.add_reference_tvshow_obj)) + self.KodiDBIO.update_path(*self.EmbyServer.Utils.values(obj, queries_videos.update_path_toptvshow_obj)) + obj['PathId'] = self.KodiDBIO.add_path(*self.EmbyServer.Utils.values(obj, queries_videos.get_path_obj)) + self.TVShowsDBIO.add(*self.EmbyServer.Utils.values(obj, queries_videos.add_tvshow_obj)) + self.emby_db.add_reference(*self.EmbyServer.Utils.values(obj, database.queries.add_reference_tvshow_obj)) self.LOG.info("ADD tvshow [%s/%s/%s] %s: %s" % (obj['TopPathId'], obj['PathId'], obj['ShowId'], obj['Id'], obj['Title'])) #Update object to kodi def tvshow_update(self, obj): - obj['RatingId'] = self.KodiDBIO.get_rating_id(*self.Utils.values(obj, queries_videos.get_rating_tvshow_obj)) - self.KodiDBIO.update_ratings(*self.Utils.values(obj, queries_videos.update_rating_tvshow_obj)) - self.KodiDBIO.remove_unique_ids(*self.Utils.values(obj, queries_videos.delete_unique_ids_tvshow_obj)) + obj['RatingId'] = self.KodiDBIO.get_rating_id(*self.EmbyServer.Utils.values(obj, queries_videos.get_rating_tvshow_obj)) + self.KodiDBIO.update_ratings(*self.EmbyServer.Utils.values(obj, queries_videos.update_rating_tvshow_obj)) + self.KodiDBIO.remove_unique_ids(*self.EmbyServer.Utils.values(obj, queries_videos.delete_unique_ids_tvshow_obj)) obj['Unique'] = self.TVShowsDBIO.create_entry_unique_id() - self.TVShowsDBIO.add_unique_id(*self.Utils.values(obj, queries_videos.add_unique_id_tvshow_obj)) + self.TVShowsDBIO.add_unique_id(*self.EmbyServer.Utils.values(obj, queries_videos.add_unique_id_tvshow_obj)) for provider in obj['UniqueIds'] or {}: unique_id = obj['UniqueIds'][provider] @@ -208,10 +197,10 @@ def tvshow_update(self, obj): if provider != 'tvdb': temp_obj = dict(obj, ProviderName=provider, UniqueId=unique_id, Unique=self.TVShowsDBIO.create_entry_unique_id()) - self.TVShowsDBIO.add_unique_id(*self.Utils.values(temp_obj, queries_videos.add_unique_id_tvshow_obj)) + self.TVShowsDBIO.add_unique_id(*self.EmbyServer.Utils.values(temp_obj, queries_videos.add_unique_id_tvshow_obj)) - self.TVShowsDBIO.update(*self.Utils.values(obj, queries_videos.update_tvshow_obj)) - self.emby_db.update_reference(*self.Utils.values(obj, database.queries.update_reference_obj)) + self.TVShowsDBIO.update(*self.EmbyServer.Utils.values(obj, queries_videos.update_tvshow_obj)) + self.emby_db.update_reference(*self.EmbyServer.Utils.values(obj, database.queries.update_reference_obj)) self.LOG.info("UPDATE tvshow [%s/%s] %s: %s" % (obj['PathId'], obj['ShowId'], obj['Id'], obj['Title'])) #Get the path and build it into protocol://path @@ -220,7 +209,7 @@ def get_path_filename(self, obj): self.LOG.info("Path is missing") return False - if self.direct_path: + if self.EmbyServer.Utils.direct_path: if '\\' in obj['Path']: obj['Path'] = "%s\\" % obj['Path'] obj['TopLevel'] = "%s\\" % ntpath.dirname(ntpath.dirname(obj['Path'])) @@ -228,10 +217,10 @@ def get_path_filename(self, obj): obj['Path'] = "%s/" % obj['Path'] obj['TopLevel'] = "%s/" % ntpath.dirname(ntpath.dirname(obj['Path'])) - obj['Path'] = self.Utils.StringDecode(obj['Path']) - obj['TopLevel'] = self.Utils.StringDecode(obj['TopLevel']) + obj['Path'] = self.EmbyServer.Utils.StringDecode(obj['Path']) + obj['TopLevel'] = self.EmbyServer.Utils.StringDecode(obj['TopLevel']) - if not self.Utils.validate(obj['Path']): + if not self.EmbyServer.Utils.validate(obj['Path']): return False else: obj['TopLevel'] = "http://127.0.0.1:57578/tvshows/" @@ -250,7 +239,6 @@ def season(self, item, library, show_id=None): if not library: return False - API = helper.api.API(item, self.Utils, self.EmbyServer.auth.get_serveraddress()) obj = self.objects.map(item, 'Season') obj['LibraryId'] = library['Id'] obj['ShowId'] = show_id @@ -259,11 +247,11 @@ def season(self, item, library, show_id=None): if not self.get_show_id(obj): return False - obj['SeasonId'] = self.TVShowsDBIO.get_season(*self.Utils.values(obj, queries_videos.get_season_obj)) - obj['Artwork'] = API.get_all_artwork(self.objects.map(item, 'Artwork')) + obj['SeasonId'] = self.TVShowsDBIO.get_season(*self.EmbyServer.Utils.values(obj, queries_videos.get_season_obj)) + obj['Artwork'] = self.APIHelper.get_all_artwork(self.objects.map(item, 'Artwork')) if obj['Location'] != 'Virtual': - self.emby_db.add_reference(*self.Utils.values(obj, database.queries.add_reference_season_obj)) + self.emby_db.add_reference(*self.EmbyServer.Utils.values(obj, database.queries.add_reference_season_obj)) self.item_ids.append(obj['Id']) self.ArtworkDBIO.add(obj['Artwork'], obj['SeasonId'], "season") @@ -282,7 +270,6 @@ def episode(self, item, library): if not library: return False - API = helper.api.API(item, self.Utils, self.EmbyServer.auth.get_serveraddress()) obj = self.objects.map(item, 'Episode') obj['Item'] = item obj['Library'] = library @@ -302,14 +289,14 @@ def episode(self, item, library): if str(StackedID) != obj['Id']: self.LOG.info("Skipping stacked episode %s [%s]" % (obj['Title'], obj['Id'])) - TVShows(self.EmbyServer, self.emby, self.video, self.direct_path, self.Utils, self.Downloader, False).remove(StackedID) + TVShows(self.EmbyServer, self.emby, self.video, False).remove(StackedID) if e_item: obj['EpisodeId'] = e_item[0] obj['FileId'] = e_item[1] obj['PathId'] = e_item[2] - if self.TVShowsDBIO.get_episode(*self.Utils.values(obj, queries_videos.get_episode_obj)) is None: + if self.TVShowsDBIO.get_episode(*self.EmbyServer.Utils.values(obj, queries_videos.get_episode_obj)) is None: update = False self.LOG.info("EpisodeId %s missing from kodi. repairing the entry." % obj['EpisodeId']) else: @@ -325,37 +312,37 @@ def episode(self, item, library): obj['Path'] = obj['Item']['MediaSources'][0]['Path'] #don't use 3d movies as default - if "3d" in self.Utils.StringMod(obj['Item']['MediaSources'][0]['Path']): + if "3d" in self.EmbyServer.Utils.StringMod(obj['Item']['MediaSources'][0]['Path']): for DataSource in obj['Item']['MediaSources']: - if not "3d" in self.Utils.StringMod(DataSource['Path']): + if not "3d" in self.EmbyServer.Utils.StringMod(DataSource['Path']): DataSource = self.objects.MapMissingData(DataSource, 'MediaSources') obj['Path'] = DataSource['Path'] obj['MediaSourceID'] = DataSource['Id'] obj['Runtime'] = DataSource['RunTimeTicks'] break - obj['Path'] = API.get_file_path(obj['Path']) + obj['Path'] = self.APIHelper.get_file_path(obj['Path'], item) obj['Index'] = obj['Index'] or -1 obj['Writers'] = " / ".join(obj['Writers'] or []) obj['Directors'] = " / ".join(obj['Directors'] or []) - obj['Plot'] = API.get_overview(obj['Plot']) - obj['Resume'] = API.adjust_resume((obj['Resume'] or 0) / 10000000.0, self.Utils) + obj['Plot'] = self.APIHelper.get_overview(obj['Plot'], item) + obj['Resume'] = self.APIHelper.adjust_resume((obj['Resume'] or 0) / 10000000.0) obj['Runtime'] = round(float((obj['Runtime'] or 0) / 10000000.0), 6) - obj['People'] = API.get_people_artwork(obj['People'] or []) - obj['DateAdded'] = self.Utils.convert_to_local(obj['DateAdded']).split('.')[0].replace('T', " ") - obj['DatePlayed'] = None if not obj['DatePlayed'] else self.Utils.convert_to_local(obj['DatePlayed']).split('.')[0].replace('T', " ") - obj['PlayCount'] = API.get_playcount(obj['Played'], obj['PlayCount']) - obj['Artwork'] = API.get_all_artwork(self.objects.map(item, 'Artwork')) - obj['Video'] = API.video_streams(obj['Video'] or [], obj['Container']) - obj['Audio'] = API.audio_streams(obj['Audio'] or []) - obj['Streams'] = API.media_streams(obj['Video'], obj['Audio'], obj['Subtitles']) + obj['People'] = self.APIHelper.get_people_artwork(obj['People'] or []) + obj['DateAdded'] = self.EmbyServer.Utils.convert_to_local(obj['DateAdded']).split('.')[0].replace('T', " ") + obj['DatePlayed'] = None if not obj['DatePlayed'] else self.EmbyServer.Utils.convert_to_local(obj['DatePlayed']).split('.')[0].replace('T', " ") + obj['PlayCount'] = self.APIHelper.get_playcount(obj['Played'], obj['PlayCount']) + obj['Artwork'] = self.APIHelper.get_all_artwork(self.objects.map(item, 'Artwork')) + obj['Video'] = self.APIHelper.video_streams(obj['Video'] or [], obj['Container'], item) + obj['Audio'] = self.APIHelper.audio_streams(obj['Audio'] or []) + obj['Streams'] = self.APIHelper.media_streams(obj['Video'], obj['Audio'], obj['Subtitles']) PathValid, obj = self.Common.get_path_filename(obj, "tvshows") if not PathValid: return "Invalid Filepath" if obj['Premiere']: - obj['Premiere'] = self.Utils.convert_to_local(obj['Premiere']).split('.')[0].replace('T', " ") + obj['Premiere'] = self.EmbyServer.Utils.convert_to_local(obj['Premiere']).split('.')[0].replace('T', " ") if obj['Season'] is None: if obj['AbsoluteNumber']: @@ -368,25 +355,22 @@ def episode(self, item, library): obj['AirsBeforeSeason'] = obj['AirsAfterSeason'] obj['AirsBeforeEpisode'] = 4096 # Kodi default number for afterseason ordering - if obj['MultiEpisode'] and self.display_multiep: - obj['Title'] = "| %02d | %s" % (obj['MultiEpisode'], obj['Title']) - if not self.get_show_id(obj): self.LOG.info("No series id associated") return False - obj['SeasonId'] = self.TVShowsDBIO.get_season(*self.Utils.values(obj, queries_videos.get_season_episode_obj)) + obj['SeasonId'] = self.TVShowsDBIO.get_season(*self.EmbyServer.Utils.values(obj, queries_videos.get_season_episode_obj)) if update: self.episode_update(obj) else: self.episode_add(obj) - self.KodiDBIO.update_path(*self.Utils.values(obj, queries_videos.update_path_episode_obj)) - self.KodiDBIO.update_file(*self.Utils.values(obj, queries_videos.update_file_obj)) - self.KodiDBIO.add_people(*self.Utils.values(obj, queries_videos.add_people_episode_obj)) - self.KodiDBIO.add_streams(*self.Utils.values(obj, queries_videos.add_streams_obj)) - self.KodiDBIO.add_playstate(*self.Utils.values(obj, queries_videos.add_bookmark_obj)) + self.KodiDBIO.update_path(*self.EmbyServer.Utils.values(obj, queries_videos.update_path_episode_obj)) + self.KodiDBIO.update_file(*self.EmbyServer.Utils.values(obj, queries_videos.update_file_obj)) + self.KodiDBIO.add_people(*self.EmbyServer.Utils.values(obj, queries_videos.add_people_episode_obj)) + self.KodiDBIO.add_streams(*self.EmbyServer.Utils.values(obj, queries_videos.add_streams_obj)) + self.KodiDBIO.add_playstate(*self.EmbyServer.Utils.values(obj, queries_videos.add_bookmark_obj)) self.ArtworkDBIO.update(obj['Artwork']['Primary'], obj['EpisodeId'], "episode", "thumb") self.item_ids.append(obj['Id']) return not update @@ -395,9 +379,9 @@ def episode(self, item, library): def episode_add(self, obj): obj = self.Common.Streamdata_add(obj, False) obj['RatingId'] = self.KodiDBIO.create_entry_rating() - self.KodiDBIO.add_ratings(*self.Utils.values(obj, queries_videos.add_rating_episode_obj)) + self.KodiDBIO.add_ratings(*self.EmbyServer.Utils.values(obj, queries_videos.add_rating_episode_obj)) obj['Unique'] = self.TVShowsDBIO.create_entry_unique_id() - self.TVShowsDBIO.add_unique_id(*self.Utils.values(obj, queries_videos.add_unique_id_episode_obj)) + self.TVShowsDBIO.add_unique_id(*self.EmbyServer.Utils.values(obj, queries_videos.add_unique_id_episode_obj)) for provider in obj['UniqueIds'] or {}: unique_id = obj['UniqueIds'][provider] @@ -405,29 +389,29 @@ def episode_add(self, obj): if provider != 'tvdb': temp_obj = dict(obj, ProviderName=provider, UniqueId=unique_id, Unique=self.TVShowsDBIO.create_entry_unique_id()) - self.TVShowsDBIO.add_unique_id(*self.Utils.values(temp_obj, queries_videos.add_unique_id_episode_obj)) + self.TVShowsDBIO.add_unique_id(*self.EmbyServer.Utils.values(temp_obj, queries_videos.add_unique_id_episode_obj)) - obj['PathId'] = self.KodiDBIO.add_path(*self.Utils.values(obj, queries_videos.add_path_obj)) - obj['FileId'] = self.KodiDBIO.add_file(*self.Utils.values(obj, queries_videos.add_file_obj)) + obj['PathId'] = self.KodiDBIO.add_path(*self.EmbyServer.Utils.values(obj, queries_videos.add_path_obj)) + obj['FileId'] = self.KodiDBIO.add_file(*self.EmbyServer.Utils.values(obj, queries_videos.add_file_obj)) try: - self.TVShowsDBIO.add_episode(*self.Utils.values(obj, queries_videos.add_episode_obj)) + self.TVShowsDBIO.add_episode(*self.EmbyServer.Utils.values(obj, queries_videos.add_episode_obj)) except sqlite3.IntegrityError: self.LOG.error("IntegrityError for %s" % obj) obj['EpisodeId'] = self.TVShowsDBIO.create_entry_episode() return self.episode_add(obj) - self.emby_db.add_reference(*self.Utils.values(obj, database.queries.add_reference_episode_obj)) + self.emby_db.add_reference(*self.EmbyServer.Utils.values(obj, database.queries.add_reference_episode_obj)) self.LOG.info("ADD episode [%s/%s/%s/%s] %s: %s" % (obj['ShowId'], obj['SeasonId'], obj['EpisodeId'], obj['FileId'], obj['Id'], obj['Title'])) #Update object to kodi def episode_update(self, obj): obj = self.Common.Streamdata_add(obj, True) - obj['RatingId'] = self.KodiDBIO.get_rating_id(*self.Utils.values(obj, queries_videos.get_rating_episode_obj)) - self.KodiDBIO.update_ratings(*self.Utils.values(obj, queries_videos.update_rating_episode_obj)) - self.KodiDBIO.remove_unique_ids(*self.Utils.values(obj, queries_videos.delete_unique_ids_episode_obj)) + obj['RatingId'] = self.KodiDBIO.get_rating_id(*self.EmbyServer.Utils.values(obj, queries_videos.get_rating_episode_obj)) + self.KodiDBIO.update_ratings(*self.EmbyServer.Utils.values(obj, queries_videos.update_rating_episode_obj)) + self.KodiDBIO.remove_unique_ids(*self.EmbyServer.Utils.values(obj, queries_videos.delete_unique_ids_episode_obj)) obj['Unique'] = self.TVShowsDBIO.create_entry_unique_id() - self.TVShowsDBIO.add_unique_id(*self.Utils.values(obj, queries_videos.add_unique_id_episode_obj)) + self.TVShowsDBIO.add_unique_id(*self.EmbyServer.Utils.values(obj, queries_videos.add_unique_id_episode_obj)) for provider in obj['UniqueIds'] or {}: unique_id = obj['UniqueIds'][provider] @@ -435,21 +419,21 @@ def episode_update(self, obj): if provider != 'tvdb': temp_obj = dict(obj, ProviderName=provider, UniqueId=unique_id, Unique=self.TVShowsDBIO.create_entry_unique_id()) - self.TVShowsDBIO.add_unique_id(*self.Utils.values(temp_obj, queries_videos.add_unique_id_episode_obj)) + self.TVShowsDBIO.add_unique_id(*self.EmbyServer.Utils.values(temp_obj, queries_videos.add_unique_id_episode_obj)) - self.TVShowsDBIO.update_episode(*self.Utils.values(obj, queries_videos.update_episode_obj)) - self.emby_db.update_reference(*self.Utils.values(obj, database.queries.update_reference_obj)) - self.emby_db.update_parent_id(*self.Utils.values(obj, database.queries.update_parent_episode_obj)) + self.TVShowsDBIO.update_episode(*self.EmbyServer.Utils.values(obj, queries_videos.update_episode_obj)) + self.emby_db.update_reference(*self.EmbyServer.Utils.values(obj, database.queries.update_reference_obj)) + self.emby_db.update_parent_id(*self.EmbyServer.Utils.values(obj, database.queries.update_parent_episode_obj)) self.LOG.info("UPDATE episode [%s/%s/%s/%s] %s: %s" % (obj['ShowId'], obj['SeasonId'], obj['EpisodeId'], obj['FileId'], obj['Id'], obj['Title'])) def get_show_id(self, obj): if obj.get('ShowId'): return True - obj['ShowId'] = self.emby_db.get_item_by_id(*self.Utils.values(obj, database.queries.get_item_series_obj)) + obj['ShowId'] = self.emby_db.get_item_by_id(*self.EmbyServer.Utils.values(obj, database.queries.get_item_series_obj)) if obj['ShowId'] is None: - TVShows(self.EmbyServer, self.emby, self.video, self.direct_path, self.Utils, self.Downloader, False).tvshow(self.EmbyServer.API.get_item(obj['SeriesId']), None, None, True) - Data = self.emby_db.get_item_by_id(*self.Utils.values(obj, database.queries.get_item_series_obj)) + TVShows(self.EmbyServer, self.emby, self.video, False).tvshow(self.EmbyServer.API.get_item(obj['SeriesId']), None, None, True) + Data = self.emby_db.get_item_by_id(*self.EmbyServer.Utils.values(obj, database.queries.get_item_series_obj)) if Data: obj['ShowId'] = Data[0] @@ -465,7 +449,6 @@ def get_show_id(self, obj): #This updates: Favorite, LastPlayedDate, Playcount, PlaybackPositionTicks def userdata(self, item): e_item = self.emby_db.get_item_by_id(item['Id']) - API = helper.api.API(item, self.Utils, self.EmbyServer.auth.get_serveraddress()) obj = self.objects.map(item, 'EpisodeUserData') obj['Item'] = item @@ -478,24 +461,24 @@ def userdata(self, item): if obj['Media'] == "tvshow": if obj['Favorite']: - self.KodiDBIO.get_tag(*self.Utils.values(obj, queries_videos.get_tag_episode_obj)) + self.KodiDBIO.get_tag(*self.EmbyServer.Utils.values(obj, queries_videos.get_tag_episode_obj)) else: - self.KodiDBIO.remove_tag(*self.Utils.values(obj, queries_videos.delete_tag_episode_obj)) + self.KodiDBIO.remove_tag(*self.EmbyServer.Utils.values(obj, queries_videos.delete_tag_episode_obj)) elif obj['Media'] == "episode": obj = self.Common.Streamdata_add(obj, True) - obj['Resume'] = API.adjust_resume((obj['Resume'] or 0) / 10000000.0, self.Utils) + obj['Resume'] = self.APIHelper.adjust_resume((obj['Resume'] or 0) / 10000000.0) obj['Runtime'] = round(float((obj['Runtime'] or 0) / 10000000.0), 6) - obj['PlayCount'] = API.get_playcount(obj['Played'], obj['PlayCount']) + obj['PlayCount'] = self.APIHelper.get_playcount(obj['Played'], obj['PlayCount']) if obj['DatePlayed']: - obj['DatePlayed'] = self.Utils.convert_to_local(obj['DatePlayed']).split('.')[0].replace('T', " ") + obj['DatePlayed'] = self.EmbyServer.Utils.convert_to_local(obj['DatePlayed']).split('.')[0].replace('T', " ") if obj['DateAdded']: - obj['DateAdded'] = self.Utils.convert_to_local(obj['DateAdded']).split('.')[0].replace('T', " ") + obj['DateAdded'] = self.EmbyServer.Utils.convert_to_local(obj['DateAdded']).split('.')[0].replace('T', " ") - self.KodiDBIO.add_playstate(*self.Utils.values(obj, queries_videos.add_bookmark_obj)) + self.KodiDBIO.add_playstate(*self.EmbyServer.Utils.values(obj, queries_videos.add_bookmark_obj)) - self.emby_db.update_reference(*self.Utils.values(obj, database.queries.update_reference_obj)) + self.emby_db.update_reference(*self.EmbyServer.Utils.values(obj, database.queries.update_reference_obj)) self.LOG.info("USERDATA %s [%s/%s] %s: %s" % (obj['Media'], obj['FileId'], obj['KodiId'], obj['Id'], obj['Title'])) return @@ -517,7 +500,7 @@ def remove(self, item_id): if obj['Media'] == 'episode': temp_obj = dict(obj) self.remove_episode(obj['KodiId'], obj['FileId'], obj['Id']) - season = self.emby_db.get_full_item_by_kodi_id(*self.Utils.values(obj, database.queries.delete_item_by_parent_season_obj)) + season = self.emby_db.get_full_item_by_kodi_id(*self.EmbyServer.Utils.values(obj, database.queries.delete_item_by_parent_season_obj)) if season: temp_obj['Id'] = season[0] @@ -525,52 +508,52 @@ def remove(self, item_id): else: return - if not self.emby_db.get_item_by_parent_id(*self.Utils.values(obj, database.queries.get_item_by_parent_episode_obj)): + if not self.emby_db.get_item_by_parent_id(*self.EmbyServer.Utils.values(obj, database.queries.get_item_by_parent_episode_obj)): self.remove_season(obj['ParentId'], obj['Id']) - self.emby_db.remove_item(*self.Utils.values(temp_obj, database.queries.delete_item_obj)) + self.emby_db.remove_item(*self.EmbyServer.Utils.values(temp_obj, database.queries.delete_item_obj)) - temp_obj['Id'] = self.emby_db.get_item_by_kodi_id(*self.Utils.values(temp_obj, database.queries.get_item_by_parent_tvshow_obj)) + temp_obj['Id'] = self.emby_db.get_item_by_kodi_id(*self.EmbyServer.Utils.values(temp_obj, database.queries.get_item_by_parent_tvshow_obj)) - if not self.TVShowsDBIO.get_total_episodes(*self.Utils.values(temp_obj, queries_videos.get_total_episodes_obj)): - for season in self.emby_db.get_item_by_parent_id(*self.Utils.values(temp_obj, database.queries.get_item_by_parent_season_obj)): + if not self.TVShowsDBIO.get_total_episodes(*self.EmbyServer.Utils.values(temp_obj, queries_videos.get_total_episodes_obj)): + for season in self.emby_db.get_item_by_parent_id(*self.EmbyServer.Utils.values(temp_obj, database.queries.get_item_by_parent_season_obj)): self.remove_season(season[1], obj['Id']) - self.emby_db.remove_items_by_parent_id(*self.Utils.values(temp_obj, database.queries.delete_item_by_parent_season_obj)) + self.emby_db.remove_items_by_parent_id(*self.EmbyServer.Utils.values(temp_obj, database.queries.delete_item_by_parent_season_obj)) self.remove_tvshow(temp_obj['ParentId'], obj['Id']) - self.emby_db.remove_item(*self.Utils.values(temp_obj, database.queries.delete_item_obj)) + self.emby_db.remove_item(*self.EmbyServer.Utils.values(temp_obj, database.queries.delete_item_obj)) elif obj['Media'] == 'tvshow': obj['ParentId'] = obj['KodiId'] - for season in self.emby_db.get_item_by_parent_id(*self.Utils.values(obj, database.queries.get_item_by_parent_season_obj)): + for season in self.emby_db.get_item_by_parent_id(*self.EmbyServer.Utils.values(obj, database.queries.get_item_by_parent_season_obj)): temp_obj = dict(obj) temp_obj['ParentId'] = season[1] - for episode in self.emby_db.get_item_by_parent_id(*self.Utils.values(temp_obj, database.queries.get_item_by_parent_episode_obj)): + for episode in self.emby_db.get_item_by_parent_id(*self.EmbyServer.Utils.values(temp_obj, database.queries.get_item_by_parent_episode_obj)): self.remove_episode(episode[1], episode[2], obj['Id']) - self.emby_db.remove_items_by_parent_id(*self.Utils.values(temp_obj, database.queries.delete_item_by_parent_episode_obj)) + self.emby_db.remove_items_by_parent_id(*self.EmbyServer.Utils.values(temp_obj, database.queries.delete_item_by_parent_episode_obj)) - self.emby_db.remove_items_by_parent_id(*self.Utils.values(obj, database.queries.delete_item_by_parent_season_obj)) + self.emby_db.remove_items_by_parent_id(*self.EmbyServer.Utils.values(obj, database.queries.delete_item_by_parent_season_obj)) self.remove_tvshow(obj['KodiId'], obj['Id']) elif obj['Media'] == 'season': obj['ParentId'] = obj['KodiId'] - for episode in self.emby_db.get_item_by_parent_id(*self.Utils.values(obj, database.queries.get_item_by_parent_episode_obj)): + for episode in self.emby_db.get_item_by_parent_id(*self.EmbyServer.Utils.values(obj, database.queries.get_item_by_parent_episode_obj)): self.remove_episode(episode[1], episode[2], obj['Id']) - self.emby_db.remove_items_by_parent_id(*self.Utils.values(obj, database.queries.delete_item_by_parent_episode_obj)) + self.emby_db.remove_items_by_parent_id(*self.EmbyServer.Utils.values(obj, database.queries.delete_item_by_parent_episode_obj)) self.remove_season(obj['KodiId'], obj['Id']) - if not self.emby_db.get_item_by_parent_id(*self.Utils.values(obj, database.queries.delete_item_by_parent_season_obj)): + if not self.emby_db.get_item_by_parent_id(*self.EmbyServer.Utils.values(obj, database.queries.delete_item_by_parent_season_obj)): self.remove_tvshow(obj['ParentId'], obj['Id']) - self.emby_db.remove_item_by_kodi_id(*self.Utils.values(obj, database.queries.delete_item_by_parent_tvshow_obj)) + self.emby_db.remove_item_by_kodi_id(*self.EmbyServer.Utils.values(obj, database.queries.delete_item_by_parent_tvshow_obj)) # Remove any series pooling episodes for episode in self.emby_db.get_media_by_parent_id(obj['Id']): self.remove_episode(episode[2], episode[3], obj['Id']) self.emby_db.remove_media_by_parent_id(obj['Id']) - self.emby_db.remove_item(*self.Utils.values(obj, database.queries.delete_item_obj)) + self.emby_db.remove_item(*self.EmbyServer.Utils.values(obj, database.queries.delete_item_obj)) def remove_tvshow(self, kodi_id, item_id): self.ArtworkDBIO.delete(kodi_id, "tvshow") @@ -606,12 +589,12 @@ def get_child(self, item_id): obj['ParentId'] = obj['KodiId'] - for season in self.emby_db.get_item_by_parent_id(*self.Utils.values(obj, database.queries.get_item_by_parent_season_obj)): + for season in self.emby_db.get_item_by_parent_id(*self.EmbyServer.Utils.values(obj, database.queries.get_item_by_parent_season_obj)): temp_obj = dict(obj) temp_obj['ParentId'] = season[1] child.append(season[0]) - for episode in self.emby_db.get_item_by_parent_id(*self.Utils.values(temp_obj, database.queries.get_item_by_parent_episode_obj)): + for episode in self.emby_db.get_item_by_parent_id(*self.EmbyServer.Utils.values(temp_obj, database.queries.get_item_by_parent_episode_obj)): child.append(episode[0]) for episode in self.emby_db.get_media_by_parent_id(obj['Id']): diff --git a/database/database.py b/database/database.py index 48a406497..7f6579b92 100644 --- a/database/database.py +++ b/database/database.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- -import json import os import sqlite3 @@ -7,7 +6,6 @@ import xbmcvfs import xbmcgui -import core.obj_ops import helper.loghandler from . import emby_db @@ -18,86 +16,22 @@ class Database(): discovered = False discovered_file = None - #file: emby, texture, music, video, :memory: or path to file def __init__(self, Utils, fileID, commit_close): self.Utils = Utils self.db_file = fileID self.commit_close = commit_close - self.objects = core.obj_ops.Objects(self.Utils) - self.path = None self.conn = None self.cursor = None #Open the connection and return the Database class. #This is to allow for the cursor, conn and others to be accessible. def __enter__(self): - self.path = self._sql(self.db_file) - - if not self.path: - return - - self.conn = sqlite3.connect(self.path, timeout=self.timeout) + self.conn = sqlite3.connect(self.Utils.DatabaseFiles[self.db_file], timeout=self.timeout) self.cursor = self.conn.cursor() - - if self.db_file in ('video', 'music', 'texture', 'emby'): - self.conn.execute("PRAGMA journal_mode=WAL") # to avoid writing conflict with kodi - + self.conn.execute("PRAGMA journal_mode=WAL") # to avoid writing conflict with kodi LOG.debug("--->[ database: %s ] %s" % (self.db_file, id(self.conn))) return self - def _get_database(self, path, silent): - path = self.Utils.translatePath(path) - - if not silent: - if not xbmcvfs.exists(path): - LOG.error("Database: %s missing" % path) - return False - - conn = sqlite3.connect(path) - cursor = conn.cursor() - cursor.execute("SELECT name FROM sqlite_master WHERE type='table';") - tables = cursor.fetchall() - conn.close() - - if not len(tables): - LOG.error("Database: %s malformed?" % path) - return False - - return path - - def _sql(self, DBFile): - databases = self.objects.objects - - if DBFile not in ('video', 'music', 'texture') or databases.get('database_set%s' % DBFile): - return self._get_database(databases[DBFile], True) - - #Read Database from filesystem - folder = self.Utils.translatePath("special://database/") - _, files = xbmcvfs.listdir(folder) - DBIDs = { - 'Textures': "texture", - 'MyMusic': "music", - 'MyVideos': "video" - } - - Version = 0 - - for DBID in DBIDs: - key = DBIDs[DBID] - - if key == DBFile: - for Filename in files: - if (Filename.startswith(DBID) and not Filename.endswith('-wal') and not Filename.endswith('-shm') and not Filename.endswith('db-journal')): - Temp = int(''.join(i for i in Filename if i.isdigit())) - - if Temp > Version: - databases[key] = os.path.join(folder, Filename) - databases['database_set%s' % key] = True - Version = Temp - - self.Utils.window('kodidbversion.' + DBFile, str(Version)) - return databases[DBFile] - #Close the connection and cursor def __exit__(self, exc_type, exc_val, exc_tb): changes = self.conn.total_changes @@ -113,57 +47,47 @@ def __exit__(self, exc_type, exc_val, exc_tb): self.cursor.close() self.conn.close() - #Open the databases to test if the file exists -def test_databases(Utils): - with Database(Utils, 'video', True): - with Database(Utils, 'music', True): - pass - +def EmbyDatabaseBuild(Utils): with Database(Utils, 'emby', True) as embydb: - emby_tables(embydb.cursor) - - -#Create the tables for the emby database -def emby_tables(cursor): - cursor.execute("CREATE TABLE IF NOT EXISTS emby(emby_id TEXT UNIQUE, media_folder TEXT, emby_type TEXT, media_type TEXT, kodi_id INTEGER, kodi_fileid INTEGER, kodi_pathid INTEGER, parent_id INTEGER, checksum INTEGER, emby_parent_id TEXT)") - cursor.execute("CREATE TABLE IF NOT EXISTS view(view_id TEXT UNIQUE, view_name TEXT, media_type TEXT)") - cursor.execute("CREATE TABLE IF NOT EXISTS MediaSources(emby_id TEXT, MediaIndex INTEGER, Protocol TEXT, MediaSourceId TEXT, Path TEXT, Type TEXT, Container TEXT, Size INTEGER, Name TEXT, IsRemote TEXT, RunTimeTicks INTEGER, SupportsTranscoding TEXT, SupportsDirectStream TEXT, SupportsDirectPlay TEXT, IsInfiniteStream TEXT, RequiresOpening TEXT, RequiresClosing TEXT, RequiresLooping TEXT, SupportsProbing TEXT, Formats TEXT, Bitrate INTEGER, RequiredHttpHeaders TEXT, ReadAtNativeFramerate TEXT, DefaultAudioStreamIndex INTEGER)") - cursor.execute("CREATE TABLE IF NOT EXISTS VideoStreams(emby_id TEXT, MediaIndex INTEGER, VideoIndex INTEGER, Codec TEXT, TimeBase TEXT, CodecTimeBase TEXT, VideoRange TEXT, DisplayTitle TEXT, IsInterlaced TEXT, BitRate INTEGER, BitDepth INTEGER, RefFrames INTEGER, IsDefault TEXT, IsForced TEXT, Height INTEGER, Width INTEGER, AverageFrameRate INTEGER, RealFrameRate INTEGER, Profile TEXT, Type TEXT, AspectRatio TEXT, IsExternal TEXT, IsTextSubtitleStream TEXT, SupportsExternalStream TEXT, Protocol TEXT, PixelFormat TEXT, Level INTEGER, IsAnamorphic TEXT, StreamIndex INTEGER)") - cursor.execute("CREATE TABLE IF NOT EXISTS AudioStreams(emby_id TEXT, MediaIndex INTEGER, AudioIndex INTEGER, Codec TEXT, Language TEXT, TimeBase TEXT, CodecTimeBase TEXT, DisplayTitle TEXT, DisplayLanguage TEXT, IsInterlaced TEXT, ChannelLayout TEXT, BitRate INTEGER, Channels INTEGER, SampleRate INTEGER, IsDefault TEXT, IsForced TEXT, Profile TEXT, Type TEXT, IsExternal TEXT, IsTextSubtitleStream TEXT, SupportsExternalStream TEXT, Protocol TEXT, StreamIndex INTEGER)") - cursor.execute("CREATE TABLE IF NOT EXISTS Subtitle(emby_id TEXT, MediaIndex INTEGER, SubtitleIndex INTEGER, Codec TEXT, Language TEXT, TimeBase TEXT, CodecTimeBase TEXT, DisplayTitle TEXT, DisplayLanguage TEXT, IsInterlaced TEXT, IsDefault TEXT, IsForced TEXT, Path TEXT, Type TEXT, IsExternal TEXT, IsTextSubtitleStream TEXT, SupportsExternalStream TEXT, Protocol TEXT, StreamIndex INTEGER)") + embydb.cursor.execute("CREATE TABLE IF NOT EXISTS emby(emby_id TEXT UNIQUE, media_folder TEXT, emby_type TEXT, media_type TEXT, kodi_id INTEGER, kodi_fileid INTEGER, kodi_pathid INTEGER, parent_id INTEGER, checksum INTEGER, emby_parent_id TEXT)") + embydb.cursor.execute("CREATE TABLE IF NOT EXISTS view(view_id TEXT UNIQUE, view_name TEXT, media_type TEXT)") + embydb.cursor.execute("CREATE TABLE IF NOT EXISTS MediaSources(emby_id TEXT, MediaIndex INTEGER, Protocol TEXT, MediaSourceId TEXT, Path TEXT, Type TEXT, Container TEXT, Size INTEGER, Name TEXT, IsRemote TEXT, RunTimeTicks INTEGER, SupportsTranscoding TEXT, SupportsDirectStream TEXT, SupportsDirectPlay TEXT, IsInfiniteStream TEXT, RequiresOpening TEXT, RequiresClosing TEXT, RequiresLooping TEXT, SupportsProbing TEXT, Formats TEXT, Bitrate INTEGER, RequiredHttpHeaders TEXT, ReadAtNativeFramerate TEXT, DefaultAudioStreamIndex INTEGER)") + embydb.cursor.execute("CREATE TABLE IF NOT EXISTS VideoStreams(emby_id TEXT, MediaIndex INTEGER, VideoIndex INTEGER, Codec TEXT, TimeBase TEXT, CodecTimeBase TEXT, VideoRange TEXT, DisplayTitle TEXT, IsInterlaced TEXT, BitRate INTEGER, BitDepth INTEGER, RefFrames INTEGER, IsDefault TEXT, IsForced TEXT, Height INTEGER, Width INTEGER, AverageFrameRate INTEGER, RealFrameRate INTEGER, Profile TEXT, Type TEXT, AspectRatio TEXT, IsExternal TEXT, IsTextSubtitleStream TEXT, SupportsExternalStream TEXT, Protocol TEXT, PixelFormat TEXT, Level INTEGER, IsAnamorphic TEXT, StreamIndex INTEGER)") + embydb.cursor.execute("CREATE TABLE IF NOT EXISTS AudioStreams(emby_id TEXT, MediaIndex INTEGER, AudioIndex INTEGER, Codec TEXT, Language TEXT, TimeBase TEXT, CodecTimeBase TEXT, DisplayTitle TEXT, DisplayLanguage TEXT, IsInterlaced TEXT, ChannelLayout TEXT, BitRate INTEGER, Channels INTEGER, SampleRate INTEGER, IsDefault TEXT, IsForced TEXT, Profile TEXT, Type TEXT, IsExternal TEXT, IsTextSubtitleStream TEXT, SupportsExternalStream TEXT, Protocol TEXT, StreamIndex INTEGER)") + embydb.cursor.execute("CREATE TABLE IF NOT EXISTS Subtitle(emby_id TEXT, MediaIndex INTEGER, SubtitleIndex INTEGER, Codec TEXT, Language TEXT, TimeBase TEXT, CodecTimeBase TEXT, DisplayTitle TEXT, DisplayLanguage TEXT, IsInterlaced TEXT, IsDefault TEXT, IsForced TEXT, Path TEXT, Type TEXT, IsExternal TEXT, IsTextSubtitleStream TEXT, SupportsExternalStream TEXT, Protocol TEXT, StreamIndex INTEGER)") - columns = cursor.execute("SELECT * FROM VideoStreams") - descriptions = [description[0] for description in columns.description] + columns = embydb.cursor.execute("SELECT * FROM VideoStreams") + descriptions = [description[0] for description in columns.description] - if 'StreamIndex' not in descriptions: - LOG.info("Add missing column VideoStreams -> StreamIndex") - cursor.execute("ALTER TABLE VideoStreams ADD COLUMN StreamIndex 'INTEGER'") + if 'StreamIndex' not in descriptions: + LOG.info("Add missing column VideoStreams -> StreamIndex") + embydb.cursor.execute("ALTER TABLE VideoStreams ADD COLUMN StreamIndex 'INTEGER'") - columns = cursor.execute("SELECT * FROM AudioStreams") - descriptions = [description[0] for description in columns.description] + columns = embydb.cursor.execute("SELECT * FROM AudioStreams") + descriptions = [description[0] for description in columns.description] - if 'StreamIndex' not in descriptions: - LOG.info("Add missing column AudioStreams -> StreamIndex") - cursor.execute("ALTER TABLE AudioStreams ADD COLUMN StreamIndex 'INTEGER'") + if 'StreamIndex' not in descriptions: + LOG.info("Add missing column AudioStreams -> StreamIndex") + embydb.cursor.execute("ALTER TABLE AudioStreams ADD COLUMN StreamIndex 'INTEGER'") - columns = cursor.execute("SELECT * FROM Subtitle") - descriptions = [description[0] for description in columns.description] + columns = embydb.cursor.execute("SELECT * FROM Subtitle") + descriptions = [description[0] for description in columns.description] - if 'StreamIndex' not in descriptions: - LOG.info("Add missing column Subtitle -> StreamIndex") - cursor.execute("ALTER TABLE Subtitle ADD COLUMN StreamIndex 'INTEGER'") + if 'StreamIndex' not in descriptions: + LOG.info("Add missing column Subtitle -> StreamIndex") + embydb.cursor.execute("ALTER TABLE Subtitle ADD COLUMN StreamIndex 'INTEGER'") - columns = cursor.execute("SELECT * FROM emby") - descriptions = [description[0] for description in columns.description] + columns = embydb.cursor.execute("SELECT * FROM emby") + descriptions = [description[0] for description in columns.description] - if 'emby_parent_id' not in descriptions: - LOG.info("Add missing column emby_parent_id") - cursor.execute("ALTER TABLE emby ADD COLUMN emby_parent_id 'TEXT'") + if 'emby_parent_id' not in descriptions: + LOG.info("Add missing column emby_parent_id") + embydb.cursor.execute("ALTER TABLE emby ADD COLUMN emby_parent_id 'TEXT'") - if 'presentation_key' not in descriptions: - LOG.info("Add missing column presentation_key") - cursor.execute("ALTER TABLE emby ADD COLUMN presentation_key 'TEXT'") + if 'presentation_key' not in descriptions: + LOG.info("Add missing column presentation_key") + embydb.cursor.execute("ALTER TABLE emby ADD COLUMN presentation_key 'TEXT'") #Reset both the emby database and the kodi database. def reset(Utils, Force): @@ -316,32 +240,13 @@ def reset_artwork(Utils): LOG.warning("[ reset artwork ]") -def get_credentials(Utils): - path = Utils.translatePath("special://profile/addon_data/plugin.video.emby-next-gen/") - if not xbmcvfs.exists(path): - xbmcvfs.mkdirs(path) - if xbmcvfs.exists(os.path.join(path, "data.json")): - with open(os.path.join(path, 'data.json'), 'rb') as infile: - credentials = json.load(infile) - else: - credentials = {} - credentials['Servers'] = credentials.get('Servers', []) - return credentials -def save_credentials(Utils, credentials): - credentials = credentials or {} - path = Utils.translatePath("special://profile/addon_data/plugin.video.emby-next-gen/") - if not xbmcvfs.exists(path): - xbmcvfs.mkdirs(path) - credentials = json.dumps(credentials, sort_keys=True, indent=4, ensure_ascii=False) - with open(os.path.join(path, 'data.json'), 'wb') as outfile: - outfile.write(credentials.encode('utf-8')) #Get Kodi ID from emby ID def get_kodiID(Utils, emby_id): diff --git a/database/library.py b/database/library.py index f5c49fafb..e2e9acb7d 100644 --- a/database/library.py +++ b/database/library.py @@ -16,31 +16,26 @@ import core.tvshows import core.music import emby.views -import emby.downloader import helper.loghandler from . import database from . import sync class Library(threading.Thread): - def __init__(self, Monitor, server_id): + def __init__(self, Player, EmbyServer): self.LOG = helper.loghandler.LOG('EMBY.library.Library') - self.Monitor = Monitor - self.server_id = server_id - self.EmbyServer = self.Monitor.EmbyServer[self.server_id] + self.Player = Player + self.EmbyServer = EmbyServer self.SyncSkipResume = False - self.SyncInProgress = False self.SyncLater = False - self.started = False self.stop_thread = False self.suspend = False self.pending_refresh = False self.screensaver = None self.progress_updates = None self.total_updates = 0 - self.direct_path = self.Monitor.Service.Utils.settings('useDirectPaths') == "1" - self.LIMIT = min(int(self.Monitor.Service.Utils.settings('limitIndex') or 15), 50) - self.DTHREADS = min(int(self.Monitor.Service.Utils.settings('limitThreads') or 3), 3) - self.MinsyncProgress = int(self.Monitor.Service.Utils.settings('syncProgress') or 50) + self.LIMIT = min(int(self.EmbyServer.Utils.settings('limitIndex') or 15), 50) + self.DTHREADS = min(int(self.EmbyServer.Utils.settings('limitThreads') or 3), 3) + self.MinsyncProgress = int(self.EmbyServer.Utils.settings('syncProgress') or 50) self.updated_queue = Queue.Queue() self.userdata_queue = Queue.Queue() self.removed_queue = Queue.Queue() @@ -57,13 +52,12 @@ def __init__(self, Monitor, server_id): self.writer_threads_updated = [] self.writer_threads_userdata = [] self.writer_threads_removed = [] - self.sync = sync.Sync(self) - self.Views = emby.views.Views(self) + self.ThreadingLock = threading.Lock() + self.sync = sync.Sync(self.EmbyServer, self.Player, self.ThreadingLock) + self.Views = emby.views.Views(self.EmbyServer) self.Views.verify_kodi_defaults() self.Views.get_nodes() - self.Downloader = emby.downloader.Downloader(self.Monitor.Service.Utils, self.EmbyServer) self.progress_percent = 0 - self.ThreadingLock = threading.Lock() threading.Thread.__init__(self) self.start() @@ -113,32 +107,46 @@ def set_progress_dialog(self): if self.progress_updates is None: self.LOG.info("-->[ pdialog ]") self.progress_updates = xbmcgui.DialogProgressBG() - self.progress_updates.create(self.Monitor.Service.Utils.Translate('addon_name'), self.Monitor.Service.Utils.Translate(33178)) + self.progress_updates.create(self.EmbyServer.Utils.Translate('addon_name'), self.EmbyServer.Utils.Translate(33178)) def update_progress_dialog(self, item): if self.progress_updates: message = self.get_naming(item) - self.progress_updates.update(self.progress_percent, message="%s: %s" % (self.Monitor.Service.Utils.Translate(33178), message)) + self.progress_updates.update(self.progress_percent, message="%s: %s" % (self.EmbyServer.Utils.Translate(33178), message)) def run(self): self.LOG.warning("--->[ library ]") + self.Views.get_views() + self.Views.get_nodes() + + if self.EmbyServer.Utils.SyncData['Libraries']: + self.sync_libraries(False) + elif not self.EmbyServer.Utils.settings('SyncInstallRunDone.bool'): + if not self.sync.libraries(None, False, False): + if self.SyncLater: + self.EmbyServer.Utils.dialog("ok", heading="{emby}", line1=self.EmbyServer.Utils.Translate(33129)) + self.EmbyServer.Utils.settings('SyncInstallRunDone.bool', True) + self.EmbyServer.Utils.SyncData['Libraries'] = [] + self.EmbyServer.Utils.save_sync(self.EmbyServer.Utils.SyncData) + + self.Views.get_nodes() + xbmc.executebuiltin('ReloadSkin()') + + self.get_fast_sync() while not self.stop_thread: - if self.Monitor.waitForAbort(0.5): + if xbmc.Monitor().waitForAbort(0.5): break - if not self.started and not self.startup(): - self.stop_client() - if self.sync.running: continue self.service() - if self.Monitor.Service.SyncPause: + if self.Player.SyncPause: continue - self.Monitor.Service.SyncPause = False + self.Player.SyncPause = False self.LOG.warning("---<[ library ]") def service(self): @@ -152,10 +160,12 @@ def service(self): if thread.Done(): threads.remove(thread) - if not self.Monitor.player.isPlayingVideo() or self.Monitor.Service.Utils.settings('syncDuringPlay.bool') or xbmc.getCondVisibility('VideoPlayer.Content(livetv)'): - if not self.Monitor.player.isPlayingVideo() or xbmc.getCondVisibility('VideoPlayer.Content(livetv)'): + PlayingVideo = self.Player.isPlayingVideo() + + if not PlayingVideo or self.EmbyServer.Utils.settings('syncDuringPlay.bool') or xbmc.getCondVisibility('VideoPlayer.Content(livetv)'): + if not PlayingVideo or xbmc.getCondVisibility('VideoPlayer.Content(livetv)'): if not self.SyncSkipResume: - if self.Monitor.Service.Utils.get_sync()['Libraries']: + if self.EmbyServer.Utils.SyncData['Libraries']: self.sync_libraries(True) self.worker_remove_lib() @@ -170,41 +180,31 @@ def service(self): self.worker_notify() if self.pending_refresh: - self.SyncInProgress = True self.set_progress_dialog() - if not self.Monitor.Service.Utils.settings('dbSyncScreensaver.bool') and self.screensaver is None: + if not self.EmbyServer.Utils.settings('dbSyncScreensaver.bool') and self.screensaver is None: xbmc.executebuiltin('InhibitIdleShutdown(true)') - self.screensaver = self.Monitor.Service.Utils.Screensaver - self.Monitor.Service.Utils.set_screensaver(value="") + self.screensaver = self.EmbyServer.Utils.Screensaver + self.EmbyServer.Utils.set_screensaver(value="") - if (self.pending_refresh and not self.download_threads and not self.writer_threads_updated and not self.writer_threads_userdata and not self.writer_threads_removed): + if self.pending_refresh and not self.download_threads and not self.writer_threads_updated and not self.writer_threads_userdata and not self.writer_threads_removed: self.pending_refresh = False - self.save_last_sync() + self.EmbyServer.Utils.save_last_sync() self.total_updates = 0 - self.SyncInProgress = False if self.progress_updates: self.LOG.info("--<[ pdialog ]") self.progress_updates.close() self.progress_updates = None - if not self.Monitor.Service.Utils.settings('dbSyncScreensaver.bool') and self.screensaver is not None: + if not self.EmbyServer.Utils.settings('dbSyncScreensaver.bool') and self.screensaver is not None: xbmc.executebuiltin('InhibitIdleShutdown(false)') - self.Monitor.Service.Utils.set_screensaver(value=self.screensaver) + self.EmbyServer.Utils.set_screensaver(value=self.screensaver) self.screensaver = None if not xbmc.getCondVisibility('Window.IsMedia'): xbmc.executebuiltin('UpdateLibrary(video)') - def stop_client(self): - self.stop_thread = True - - #When there's an active thread. Let the main thread know - def enable_pending_refresh(self): - self.pending_refresh = True - self.SyncInProgress = True - #Get how many items are queued up for worker threads def worker_queue_size(self): total = 0 @@ -238,10 +238,6 @@ def _worker_removed_size(self): return total - #Wait 60 seconds to verify the item by moving it to the updated queue to - #verify item is still available to user. - #Used for internal deletion--callback takes too long - #Used for parental control--server does not send a new event when item has been blocked. def worker_verify(self): if self.verify_queue.qsize(): ready = [] @@ -275,11 +271,7 @@ def worker_sort(self): #Update items in the Kodi database def worker_updates(self): - if self._worker_removed_size(): - self.LOG.info("[ DELAY UPDATES ]") - return - - if len(self.writer_threads_updated): + if self._worker_removed_size() or len(self.writer_threads_updated): self.LOG.info("[ DELAY UPDATES ]") return @@ -294,15 +286,11 @@ def worker_updates(self): self.LOG.info("-->[ q:updated/%s/%s ]" % (queues, id(new_thread))) self.writer_threads_updated.append(new_thread) - self.enable_pending_refresh() + self.pending_refresh = True #Update userdata in the Kodi database def worker_userdata(self): - if self._worker_removed_size(): - self.LOG.info("[ DELAY UPDATES ]") - return - - if len(self.writer_threads_userdata): + if self._worker_removed_size() or len(self.writer_threads_userdata): self.LOG.info("[ DELAY UPDATES ]") return @@ -317,7 +305,7 @@ def worker_userdata(self): self.LOG.info("-->[ q:userdata/%s/%s ]" % (queues, id(new_thread))) self.writer_threads_userdata.append(new_thread) - self.enable_pending_refresh() + self.pending_refresh = True #Remove items from the Kodi database def worker_remove(self): @@ -336,7 +324,7 @@ def worker_remove(self): self.LOG.info("-->[ q:removed/%s/%s ]" % (queues, id(new_thread))) self.writer_threads_removed.append(new_thread) - self.enable_pending_refresh() + self.pending_refresh = True #Notify the user of new additions def worker_notify(self): @@ -351,7 +339,7 @@ def worker_remove_lib(self): library_id = self.remove_lib_queue.get() self.sync.remove_library(library_id) - if self.Monitor.Service.SyncPause: + if self.Player.SyncPause: return self.Views.remove_library(library_id) @@ -366,7 +354,7 @@ def worker_add_lib(self): library_id, update = self.add_lib_queue.get() self.sync.libraries(library_id, update, False) - if self.Monitor.Service.SyncPause: + if self.Player.SyncPause: return self.Views.get_nodes() @@ -374,47 +362,19 @@ def worker_add_lib(self): xbmc.executebuiltin("Container.Refresh") def sync_libraries(self, forced): - self.sync.libraries(None, False, forced) + if not self.sync.libraries(None, False, forced): + self.SyncSkipResume = True - if self.Monitor.Service.SyncPause: + if self.Player.SyncPause: return self.Views.get_nodes() - #Run at startup. - #Check databases. - #Check for the server plugin. - def startup(self): - self.started = True - self.Views.get_views() - self.Views.get_nodes() - - if self.Monitor.Service.Utils.get_sync()['Libraries']: - self.sync_libraries(False) - elif not self.Monitor.Service.Utils.settings('SyncInstallRunDone.bool'): - if not self.sync.libraries(None, False, False): - if self.SyncLater: - self.Monitor.Service.Utils.dialog("ok", heading="{emby}", line1=self.Monitor.Service.Utils.Translate(33129)) - self.Monitor.Service.Utils.settings('SyncInstallRunDone.bool', True) - syncLibs = self.Monitor.Service.Utils.get_sync() - syncLibs['Libraries'] = [] - self.Monitor.Service.Utils.save_sync(syncLibs) - return True - else: - return False - - self.Views.get_nodes() - xbmc.executebuiltin('ReloadSkin()') - return True - - self.get_fast_sync() - return True - def get_fast_sync(self): enable_fast_sync = False - if self.Monitor.Service.Utils.settings('SyncInstallRunDone.bool'): - if self.Monitor.Service.Utils.settings('kodiCompanion.bool'): + if self.EmbyServer.Utils.settings('SyncInstallRunDone.bool'): + if self.EmbyServer.Utils.settings('kodiCompanion.bool'): for plugin in self.EmbyServer.API.get_plugins(): if plugin['Name'] in ("Emby.Kodi Sync Queue", "Kodi companion"): enable_fast_sync = True @@ -425,33 +385,72 @@ def get_fast_sync(self): #Movie and userdata not provided by server yet def fast_sync(self, plugin): - last_sync = self.Monitor.Service.Utils.settings('LastIncrementalSync') + last_sync = self.EmbyServer.Utils.settings('LastIncrementalSync') self.LOG.info("--[ retrieve changes ] %s" % last_sync) + LibraryViews = {} + + with database.Database(self.EmbyServer.Utils, 'emby', False) as embydb: + emby_db = database.emby_db.EmbyDatabase(embydb.cursor) + result = emby_db.get_views() + + for Data in result: + LibID, LibName, LibContent = Data + LibraryViews[LibID] = LibContent + + for library in self.EmbyServer.Utils.SyncData['Whitelist']: + library = library.replace('Mixed:', "") + + if LibraryViews[library] == "musicvideos": + result = self.EmbyServer.API.get_itemsSync(library, "MusicVideo", False, {'MinDateLastSaved': last_sync}) + elif LibraryViews[library] == "movies": + result = self.EmbyServer.API.get_itemsSync(library, "BoxSet,Movie", False, {'MinDateLastSaved': last_sync}) + elif LibraryViews[library] == "tvshows": + result = self.EmbyServer.API.get_itemsSync(library, "Series,Season,Episode", False, {'MinDateLastSaved': last_sync}) + elif LibraryViews[library] == "music": + result = self.EmbyServer.API.get_itemsSync(library, "MusicArtist,MusicAlbum,Audio", False, {'MinDateLastSaved': last_sync}) + elif LibraryViews[library] == "mixed": + result = self.EmbyServer.API.get_itemsSync(library.replace('Mixed:', ""), "Series,Season,Episode,BoxSet,Movie,MusicVideo,MusicArtist,MusicAlbum,Audio", False, {'MinDateLastSaved': last_sync}) + else: + result = False - for library in self.Monitor.Service.Utils.get_sync()['Whitelist']: - for data in self.Downloader.get_items(library.replace('Mixed:', ""), "Series,Season,Episode,BoxSet,Movie,MusicVideo,MusicArtist,MusicAlbum,Audio", False, {'MinDateLastSaved': last_sync}): - with database.Database(self.Monitor.Service.Utils, 'emby', True) as embydb: + if result: + with database.Database(self.EmbyServer.Utils, 'emby', False) as embydb: emby_db = database.emby_db.EmbyDatabase(embydb.cursor) - for item in data['Items']: - if item['Type'] in self.updated_output: - item['Library'] = {} - item['Library']['Id'] = library - item['Library']['Name'] = emby_db.get_view_name(library) - self.updated_output[item['Type']].put(item) - self.total_updates += 1 + for data in result: + for item in data['Items']: + if item['Type'] in self.updated_output: + item['Library'] = {} + item['Library']['Id'] = library + item['Library']['Name'] = emby_db.get_view_name(library) + self.updated_output[item['Type']].put(item) + self.total_updates += 1 + + if LibraryViews[library] == "musicvideos": + result = self.EmbyServer.API.get_itemsSync(library, "MusicVideo", False, {'MinDateLastSavedForUser': last_sync}) + elif LibraryViews[library] == "tvshows": + result = self.EmbyServer.API.get_itemsSync(library, "Episode", False, {'MinDateLastSavedForUser': last_sync}) + elif LibraryViews[library] == "movies": + result = self.EmbyServer.API.get_itemsSync(library, "Movie", False, {'MinDateLastSavedForUser': last_sync}) + elif LibraryViews[library] == "music": + result = self.EmbyServer.API.get_itemsSync(library, "Audio", False, {'MinDateLastSavedForUser': last_sync}) + elif LibraryViews[library] == "mixed": + result = self.EmbyServer.API.get_itemsSync(library.replace('Mixed:', ""), "Episode,Movie,MusicVideo,Audio", False, {'MinDateLastSavedForUser': last_sync}) + else: + result = False - for data in self.Downloader.get_items(library.replace('Mixed:', ""), "Episode,Movie,MusicVideo,Audio", False, {'MinDateLastSavedForUser': last_sync}): - with database.Database(self.Monitor.Service.Utils, 'emby', True) as embydb: + if result: + with database.Database(self.EmbyServer.Utils, 'emby', False) as embydb: emby_db = database.emby_db.EmbyDatabase(embydb.cursor) - for item in data['Items']: - if item['Type'] in self.userdata_output: - item['Library'] = {} - item['Library']['Id'] = library - item['Library']['Name'] = emby_db.get_view_name(library) - self.userdata_output[item['Type']].put(item) - self.total_updates += 1 + for data in result: + for item in data['Items']: + if item['Type'] in self.userdata_output: + item['Library'] = {} + item['Library']['Id'] = library + item['Library']['Name'] = emby_db.get_view_name(library) + self.userdata_output[item['Type']].put(item) + self.total_updates += 1 if plugin: result = self.EmbyServer.API.get_sync_queue(last_sync, None) #Kodi companion plugin @@ -459,12 +458,6 @@ def fast_sync(self, plugin): return True - def save_last_sync(self): - time_now = datetime.utcnow() - timedelta(minutes=2) - last_sync = time_now.strftime('%Y-%m-%dT%H:%M:%Sz') - self.Monitor.Service.Utils.settings('LastIncrementalSync', value=last_sync) - self.LOG.info("--[ sync/%s ]" % last_sync) - #Select from libraries synced. Either update or repair libraries. #Send event back to service.py def select_libraries(self, mode): @@ -475,19 +468,18 @@ def select_libraries(self, mode): 'RemoveLibrarySelection': 'RemoveLibrary' } - syncData = self.Monitor.Service.Utils.get_sync() - whitelist = [x.replace('Mixed:', "") for x in syncData['Whitelist']] + whitelist = [x.replace('Mixed:', "") for x in self.EmbyServer.Utils.SyncData['Whitelist']] libraries = [] - with database.Database(self.Monitor.Service.Utils, 'emby', True) as embydb: + with database.Database(self.EmbyServer.Utils, 'emby', True) as embydb: db = database.emby_db.EmbyDatabase(embydb.cursor) if mode in ('SyncLibrarySelection', 'RepairLibrarySelection', 'RemoveLibrarySelection'): - for library in syncData['Whitelist']: + for library in self.EmbyServer.Utils.SyncData['Whitelist']: name = db.get_view_name(library.replace('Mixed:', "")) libraries.append({'Id': library, 'Name': name}) else: - available = [x for x in syncData['SortedViews'] if x not in whitelist] + available = [x for x in self.EmbyServer.Utils.SyncData['SortedViews'] if x not in whitelist] for library in available: name, media = db.get_view(library) @@ -496,8 +488,8 @@ def select_libraries(self, mode): libraries.append({'Id': library, 'Name': name}) choices = [x['Name'] for x in libraries] - choices.insert(0, self.Monitor.Service.Utils.Translate(33121)) - selection = self.Monitor.Service.Utils.dialog("multi", self.Monitor.Service.Utils.Translate(33120), choices) + choices.insert(0, self.EmbyServer.Utils.Translate(33121)) + selection = self.EmbyServer.Utils.dialog("multi", self.EmbyServer.Utils.Translate(33120), choices) if selection is None: return @@ -511,7 +503,7 @@ def select_libraries(self, mode): library = libraries[x - 1] selected_libraries.append(library['Id']) - self.Monitor.Service.Utils.event(modes[mode], {'Id': ','.join([libraries[x - 1]['Id'] for x in selection]), 'Update': mode == 'SyncLibrarySelection', 'ServerId': self.server_id}) + self.EmbyServer.Utils.event(modes[mode], {'Id': ','.join([libraries[x - 1]['Id'] for x in selection]), 'Update': mode == 'SyncLibrarySelection', 'ServerId': self.EmbyServer.server_id}) def patch_music(self, notification): self.sync.patch_music(notification) @@ -528,7 +520,7 @@ def remove_library(self, library_id): def userdata(self, data): items = [x['ItemId'] for x in data] - for item in self.Monitor.Service.Utils.split_list(items, self.LIMIT): + for item in self.EmbyServer.Utils.split_list(items, self.LIMIT): self.userdata_queue.put(item) self.total_updates += len(items) @@ -536,7 +528,7 @@ def userdata(self, data): #Add item_id to updated queue def updated(self, data): - for item in self.Monitor.Service.Utils.split_list(data, self.LIMIT): + for item in self.EmbyServer.Utils.split_list(data, self.LIMIT): self.updated_queue.put(item) self.total_updates += len(data) @@ -567,8 +559,8 @@ def __init__(self, queue, library, DB): self.LOG = helper.loghandler.LOG('EMBY.library.UpdatedWorker') self.library = library self.queue = queue - self.notify = self.library.Monitor.Service.Utils.settings('newContent.bool') - self.DB = database.Database(self.library.Monitor.Service.Utils, DB, True) + self.notify = self.library.EmbyServer.Utils.settings('newContent.bool') + self.DB = database.Database(self.library.EmbyServer.Utils, DB, True) self.library.set_progress_dialog() self.is_done = False threading.Thread.__init__(self) @@ -580,7 +572,7 @@ def Done(self): def run(self): with self.library.ThreadingLock: with self.DB as kodidb: - with database.Database(self.library.Monitor.Service.Utils, 'emby', True) as embydb: + with database.Database(self.library.EmbyServer.Utils, 'emby', True) as embydb: while not self.queue.empty(): item = self.queue.get() self.library.update_progress_dialog(item) @@ -591,23 +583,23 @@ def run(self): LibID = None if item['Type'] == 'Movie': - Ret = core.movies.Movies(self.library.EmbyServer, embydb, kodidb, self.library.direct_path, self.library.Monitor.Service.Utils, self.library.Downloader).movie(item, LibID) + Ret = core.movies.Movies(self.library.EmbyServer, embydb, kodidb).movie(item, LibID) elif item['Type'] == 'BoxSet': - Ret = core.movies.Movies(self.library.EmbyServer, embydb, kodidb, self.library.direct_path, self.library.Monitor.Service.Utils, self.library.Downloader).boxset(item) + Ret = core.movies.Movies(self.library.EmbyServer, embydb, kodidb).boxset(item) elif item['Type'] == 'MusicVideo': - Ret = core.musicvideos.MusicVideos(self.library.EmbyServer, embydb, kodidb, self.library.direct_path, self.library.Monitor.Service.Utils).musicvideo(item, LibID) + Ret = core.musicvideos.MusicVideos(self.library.EmbyServer, embydb, kodidb).musicvideo(item, LibID) elif item['Type'] == 'Series': - Ret = core.tvshows.TVShows(self.library.EmbyServer, embydb, kodidb, self.library.direct_path, self.library.Monitor.Service.Utils, self.library.Downloader).tvshow(item, LibID) + Ret = core.tvshows.TVShows(self.library.EmbyServer, embydb, kodidb).tvshow(item, LibID) elif item['Type'] == 'Season': - Ret = core.tvshows.TVShows(self.library.EmbyServer, embydb, kodidb, self.library.direct_path, self.library.Monitor.Service.Utils, self.library.Downloader).season(item, LibID) + Ret = core.tvshows.TVShows(self.library.EmbyServer, embydb, kodidb).season(item, LibID) elif item['Type'] == 'Episode': - Ret = core.tvshows.TVShows(self.library.EmbyServer, embydb, kodidb, self.library.direct_path, self.library.Monitor.Service.Utils, self.library.Downloader).episode(item, LibID) + Ret = core.tvshows.TVShows(self.library.EmbyServer, embydb, kodidb).episode(item, LibID) elif item['Type'] == 'MusicAlbum': - Ret = core.music.Music(self.library.EmbyServer, embydb, kodidb, self.library.direct_path, self.library.Monitor.Service.Utils).album(item, LibID) + Ret = core.music.Music(self.library.EmbyServer, embydb, kodidb).album(item, LibID) elif item['Type'] == 'Audio': - Ret = core.music.Music(self.library.EmbyServer, embydb, kodidb, self.library.direct_path, self.library.Monitor.Service.Utils).song(item, LibID) + Ret = core.music.Music(self.library.EmbyServer, embydb, kodidb).song(item, LibID) elif item['Type'] in ('MusicArtist', 'AlbumArtist'): - Ret = core.music.Music(self.library.EmbyServer, embydb, kodidb, self.library.direct_path, self.library.Monitor.Service.Utils).artist(item, LibID) + Ret = core.music.Music(self.library.EmbyServer, embydb, kodidb).artist(item, LibID) else: self.LOG.error("Media Type not found: %s" % item['Type']) break @@ -618,7 +610,7 @@ def run(self): if Ret and self.notify: self.library.notify_output.put({'Type': item['Type'], 'Name': self.library.get_naming(item)}) - if self.library.Monitor.Service.SyncPause: + if self.library.Player.SyncPause: break self.LOG.info("--<[ q:updated/%s ]" % id(self)) @@ -630,7 +622,7 @@ def __init__(self, queue, library, DB): self.LOG = helper.loghandler.LOG('EMBY.library.UserDataWorker') self.library = library self.queue = queue - self.DB = database.Database(self.library.Monitor.Service.Utils, DB, True) + self.DB = database.Database(self.library.EmbyServer.Utils, DB, True) self.is_done = False self.library.set_progress_dialog() threading.Thread.__init__(self) @@ -642,24 +634,24 @@ def Done(self): def run(self): with self.library.ThreadingLock: with self.DB as kodidb: - with database.Database(self.library.Monitor.Service.Utils, 'emby', True) as embydb: + with database.Database(self.library.EmbyServer.Utils, 'emby', True) as embydb: while not self.queue.empty(): item = self.queue.get() self.library.update_progress_dialog(item) if item['Type'] in ('Movie', 'BoxSet'): - core.movies.Movies(self.library.EmbyServer, embydb, kodidb, self.library.direct_path, self.library.Monitor.Service.Utils, self.library.Downloader).userdata(item) + core.movies.Movies(self.library.EmbyServer, embydb, kodidb).userdata(item) elif item['Type'] == 'MusicVideo': - core.musicvideos.MusicVideos(self.library.EmbyServer, embydb, kodidb, self.library.direct_path, self.library.Monitor.Service.Utils).userdata(item) + core.musicvideos.MusicVideos(self.library.EmbyServer, embydb, kodidb).userdata(item) elif item['Type'] in ('TVShow', 'Series', 'Season', 'Episode'): - core.tvshows.TVShows(self.library.EmbyServer, embydb, kodidb, self.library.direct_path, self.library.Monitor.Service.Utils, self.library.Downloader).userdata(item) + core.tvshows.TVShows(self.library.EmbyServer, embydb, kodidb).userdata(item) elif item['Type'] in ('Music', 'MusicAlbum', 'MusicArtist', 'AlbumArtist', 'Audio'): - core.music.Music(self.library.EmbyServer, embydb, kodidb, self.library.direct_path, self.library.Monitor.Service.Utils).userdata(item) + core.music.Music(self.library.EmbyServer, embydb, kodidb).userdata(item) - if self.library.Monitor.Service.SyncPause: + if self.library.Player.SyncPause: break self.LOG.info("--<[ q:userdata/%s ]" % id(self)) @@ -678,7 +670,7 @@ def Done(self): def run(self): with self.library.ThreadingLock: - with database.Database(self.library.Monitor.Service.Utils, 'emby', True) as embydb: + with database.Database(self.library.EmbyServer.Utils, 'emby', True) as embydb: db = database.emby_db.EmbyDatabase(embydb.cursor) while not self.library.removed_queue.empty(): @@ -696,7 +688,7 @@ def run(self): for item in items: self.library.removed_output[item[1]].put({'Id': item[0], 'Type': item[1]}) - if self.library.Monitor.Service.ShouldStop or self.library.Monitor.sleep: + if self.library.stop_thread: break self.LOG.info("--<[ q:sort/%s ]" % id(self)) @@ -707,7 +699,7 @@ def __init__(self, queue, library, DB): self.LOG = helper.loghandler.LOG('EMBY.library.RemovedWorker') self.library = library self.queue = queue - self.DB = database.Database(self.library.Monitor.Service.Utils, DB, True) + self.DB = database.Database(self.library.EmbyServer.Utils, DB, True) self.is_done = False threading.Thread.__init__(self) self.start() @@ -718,23 +710,23 @@ def Done(self): def run(self): with self.library.ThreadingLock: with self.DB as kodidb: - with database.Database(self.library.Monitor.Service.Utils, 'emby', True) as embydb: + with database.Database(self.library.EmbyServer.Utils, 'emby', True) as embydb: while not self.queue.empty(): item = self.queue.get() if item['Type'] in ('Movie', 'BoxSet'): - core.movies.Movies(self.library.EmbyServer, embydb, kodidb, self.library.direct_path, self.library.Monitor.Service.Utils, self.library.Downloader).remove(item['Id']) + core.movies.Movies(self.library.EmbyServer, embydb, kodidb).remove(item['Id']) elif item['Type'] == 'MusicVideo': - core.musicvideos.MusicVideos(self.library.EmbyServer, embydb, kodidb, self.library.direct_path, self.library.Monitor.Service.Utils).remove(item['Id']) + core.musicvideos.MusicVideos(self.library.EmbyServer, embydb, kodidb).remove(item['Id']) elif item['Type'] in ('TVShow', 'Series', 'Season', 'Episode'): - core.tvshows.TVShows(self.library.EmbyServer, embydb, kodidb, self.library.direct_path, self.library.Monitor.Service.Utils, self.library.Downloader).remove(item['Id']) + core.tvshows.TVShows(self.library.EmbyServer, embydb, kodidb).remove(item['Id']) elif item['Type'] in ('Music', 'MusicAlbum', 'MusicArtist', 'AlbumArtist', 'Audio'): - core.music.Music(self.library.EmbyServer, embydb, kodidb, self.library.direct_path, self.library.Monitor.Service.Utils).remove(item['Id']) + core.music.Music(self.library.EmbyServer, embydb, kodidb).remove(item['Id']) - if self.library.Monitor.Service.SyncPause: + if self.library.Player.SyncPause: break self.LOG.info("--<[ q:removed/%s ]" % id(self)) @@ -744,8 +736,8 @@ class NotifyWorker(threading.Thread): def __init__(self, library): self.LOG = helper.loghandler.LOG('EMBY.library.NotifyWorker') self.library = library - self.video_time = int(self.library.Monitor.Service.Utils.settings('newvideotime')) * 1000 - self.music_time = int(self.library.Monitor.Service.Utils.settings('newmusictime')) * 1000 + self.video_time = int(self.library.EmbyServer.Utils.settings('newvideotime')) * 1000 + self.music_time = int(self.library.EmbyServer.Utils.settings('newmusictime')) * 1000 self.is_done = False threading.Thread.__init__(self) self.start() @@ -758,10 +750,10 @@ def run(self): item = self.library.notify_output.get() time = self.music_time if item['Type'] == 'Audio' else self.video_time - if time and (not self.library.Monitor.player.isPlayingVideo() or xbmc.getCondVisibility('VideoPlayer.Content(livetv)')): - self.library.Monitor.Service.Utils.dialog("notification", heading="%s %s" % (self.library.Monitor.Service.Utils.Translate(33049), item['Type']), message=item['Name'], icon="{emby}", time=time, sound=False) + if time and (not self.library.Player.isPlayingVideo() or xbmc.getCondVisibility('VideoPlayer.Content(livetv)')): + self.library.EmbyServer.Utils.dialog("notification", heading="%s %s" % (self.library.EmbyServer.Utils.Translate(33049), item['Type']), message=item['Name'], icon="{emby}", time=time, sound=False) - if self.library.Monitor.Service.ShouldStop or self.library.Monitor.sleep: + if self.library.stop_thread: break self.LOG.info("--<[ q:notify/%s ]" % id(self)) diff --git a/database/queries.py b/database/queries.py index 1b2921dac..aaf15e329 100644 --- a/database/queries.py +++ b/database/queries.py @@ -35,7 +35,7 @@ get_videostreams = """SELECT * FROM VideoStreams WHERE emby_id = ? AND MediaIndex = ?""" get_mediasourceid = """SELECT Id FROM MediaSources WHERE emby_id = ?""" get_mediasource = """SELECT * FROM MediaSources WHERE emby_id = ?""" -get_kodiid = """SELECT kodi_id, presentation_key FROM emby WHERE emby_id = ?""" +get_kodiid = """SELECT kodi_id, presentation_key, kodi_fileid FROM emby WHERE emby_id = ?""" get_AudioStreams = """SELECT * FROM AudioStreams WHERE emby_id = ? AND MediaIndex = ?""" get_Subtitles = """SELECT * FROM Subtitle WHERE emby_id = ? AND MediaIndex = ?""" get_kodifileid = """SELECT kodi_fileid FROM emby WHERE emby_id = ?""" @@ -48,15 +48,7 @@ add_reference_boxset_obj = ["{Id}", "{SetId}", None, None, "BoxSet", "set", None, "{Checksum}", None, None, "{PresentationKey}"] add_reference_tvshow_obj = ["{Id}", "{ShowId}", None, "{PathId}", "Series", "tvshow", None, "{Checksum}", "{LibraryId}", "{EmbyParentId}", "{PresentationKey}"] add_reference_season_obj = ["{Id}", "{SeasonId}", None, None, "Season", "season", "{ShowId}", None, "{LibraryId}", None, "{PresentationKey}"] - - - - add_reference_pool_obj = ["{SeriesId}", "{ShowId}", None, "{PathId}", "Series", "tvshow", None, "{Checksum}", "{LibraryId}", None, "{PresentationKey}"] - - - - add_reference_episode_obj = ["{Id}", "{EpisodeId}", "{FileId}", "{PathId}", "Episode", "episode", "{SeasonId}", "{Checksum}", "{LibraryId}", "{EmbyParentId}", "{PresentationKey}"] add_reference_mvideo_obj = ["{Id}", "{MvideoId}", "{FileId}", "{PathId}", "MusicVideo", "musicvideo", None, "{Checksum}", "{LibraryId}", "{EmbyParentId}", "{PresentationKey}"] add_reference_artist_obj = ["{Id}", "{ArtistId}", None, None, "{ArtistType}", "artist", None, "{Checksum}", "{LibraryId}", "{EmbyParentId}", "{PresentationKey}"] diff --git a/database/sync.py b/database/sync.py index 346aa9806..d93446afe 100644 --- a/database/sync.py +++ b/database/sync.py @@ -15,70 +15,57 @@ from . import emby_db class Sync(): - def __init__(self, library): + def __init__(self, EmbyServer, Player, ThreadingLock): self.LOG = helper.loghandler.LOG('EMBY.database.sync') - self.library = library - self.SyncData = {} + self.EmbyServer = EmbyServer + self.Player = Player + self.ThreadingLock = ThreadingLock self.running = False - self.SyncInProgress = False self.screensaver = None self.update_library = False - self.xmls = helper.xmls.Xmls(self.library.Monitor.Service.Utils) - self.direct_path = self.library.Monitor.Service.Utils.settings('useDirectPaths') == "1" + self.xmls = helper.xmls.Xmls(self.EmbyServer.Utils) if self.running: - self.library.Monitor.Service.Utils.dialog("ok", heading="{emby}", line1=self.library.Monitor.Service.Utils.Translate(33197)) + self.EmbyServer.Utils.dialog("ok", heading="{emby}", line1=self.EmbyServer.Utils.Translate(33197)) return - #Do everything we need before the sync - def __enter__(self): - self.LOG.info("-->[ fullsync ]") - - if not self.library.Monitor.Service.Utils.settings('dbSyncScreensaver.bool'): - xbmc.executebuiltin('InhibitIdleShutdown(true)') - self.screensaver = self.library.Monitor.Service.Utils.WebserverData - self.library.Monitor.Service.Utils.set_screensaver(value="") - - self.running = True - self.SyncInProgress = True - return self - #Assign the restore point and save the sync status def _restore_point(self, restore): - self.SyncData['RestorePoint'] = restore - self.library.Monitor.Service.Utils.save_sync(self.SyncData, False) + self.EmbyServer.Utils.SyncData['RestorePoint'] = restore + self.EmbyServer.Utils.save_sync(self.EmbyServer.Utils.SyncData, False) #Map the syncing process and start the sync. Ensure only one sync is running #force to resume any previous sync def libraries(self, library_id, update, forced): self.update_library = update - self.SyncData = self.library.Monitor.Service.Utils.get_sync() if library_id: libraries = library_id.split(',') for selected in libraries: - if selected not in [x.replace('Mixed:', "") for x in self.SyncData['Libraries']]: + if selected not in [x.replace('Mixed:', "") for x in self.EmbyServer.Utils.SyncData['Libraries']]: library = self.get_libraries(selected) if library: - self.SyncData['Libraries'].append("Mixed:%s" % selected if library[1] == 'mixed' else selected) + self.EmbyServer.Utils.SyncData['Libraries'].append("Mixed:%s" % selected if library[1] == 'mixed' else selected) if library[1] in ('mixed', 'movies'): - self.SyncData['Libraries'].append('Boxsets:%s' % selected) + self.EmbyServer.Utils.SyncData['Libraries'].append('Boxsets:%s' % selected) else: - self.SyncData['Libraries'].append(selected) + self.EmbyServer.Utils.SyncData['Libraries'].append(selected) else: if not self.mapping(forced): - return + return False self.xmls.sources() - if not self.xmls.advanced_settings() and self.SyncData['Libraries']: - self.start() + if not self.xmls.advanced_settings() and self.EmbyServer.Utils.SyncData['Libraries']: + self.FullSync() + + return True def get_libraries(self, library_id): - with database.Database(self.library.Monitor.Service.Utils, 'emby', True) as embydb: + with database.Database(self.EmbyServer.Utils, 'emby', True) as embydb: if not library_id: return emby_db.EmbyDatabase(embydb.cursor).get_views() @@ -87,16 +74,15 @@ def get_libraries(self, library_id): #Load the mapping of the full sync. #This allows us to restore a previous sync def mapping(self, forced): - if self.SyncData['Libraries']: - if not forced and not self.library.Monitor.Service.Utils.dialog("yesno", heading="{emby}", line1=self.library.Monitor.Service.Utils.Translate(33102)): - if not self.library.Monitor.Service.Utils.dialog("yesno", heading="{emby}", line1=self.library.Monitor.Service.Utils.Translate(33173)): - self.library.Monitor.Service.Utils.dialog("ok", heading="{emby}", line1=self.library.Monitor.Service.Utils.Translate(33122)) - self.library.SyncSkipResume = True - self.library.Monitor.Service.SyncPause = True + if self.EmbyServer.Utils.SyncData['Libraries']: + if not forced and not self.EmbyServer.Utils.dialog("yesno", heading="{emby}", line1=self.EmbyServer.Utils.Translate(33102)): + if not self.EmbyServer.Utils.dialog("yesno", heading="{emby}", line1=self.EmbyServer.Utils.Translate(33173)): + self.EmbyServer.Utils.dialog("ok", heading="{emby}", line1=self.EmbyServer.Utils.Translate(33122)) + self.Player.SyncPause = True return False - self.SyncData['Libraries'] = [] - self.SyncData['RestorePoint'] = {} + self.EmbyServer.Utils.SyncData['Libraries'] = [] + self.EmbyServer.Utils.SyncData['RestorePoint'] = {} else: self.LOG.info("generate full sync") libraries = [] @@ -111,28 +97,26 @@ def mapping(self, forced): return False if [x['Media'] for x in libraries if x['Media'] in ('movies', 'mixed')]: - self.SyncData['Libraries'].append("Boxsets:") + self.EmbyServer.Utils.SyncData['Libraries'].append("Boxsets:") - self.library.Monitor.Service.Utils.save_sync(self.SyncData, True) + self.EmbyServer.Utils.save_sync(self.EmbyServer.Utils.SyncData, True) return True #Select all or certain libraries to be whitelisted def select_libraries(self, libraries): - if self.library.Monitor.Service.Utils.dialog("yesno", heading="{emby}", line1=self.library.Monitor.Service.Utils.Translate(33125), nolabel=self.library.Monitor.Service.Utils.Translate(33127), yeslabel=self.library.Monitor.Service.Utils.Translate(33126)): + if self.EmbyServer.Utils.dialog("yesno", heading="{emby}", line1=self.EmbyServer.Utils.Translate(33125), nolabel=self.EmbyServer.Utils.Translate(33127), yeslabel=self.EmbyServer.Utils.Translate(33126)): self.LOG.info("Selected sync later") - self.library.SyncLater = True return False choices = [x['Name'] for x in libraries] - choices.insert(0, self.library.Monitor.Service.Utils.Translate(33121)) - selection = self.library.Monitor.Service.Utils.dialog("multi", self.library.Monitor.Service.Utils.Translate(33120), choices) + choices.insert(0, self.EmbyServer.Utils.Translate(33121)) + selection = self.EmbyServer.Utils.dialog("multi", self.EmbyServer.Utils.Translate(33120), choices) if selection is None: return False if not selection: self.LOG.info("Nothing was selected") - self.library.SyncLater = True return False if 0 in selection: @@ -148,34 +132,47 @@ def select_libraries(self, libraries): else: selected_libraries.append("Mixed:%s" % library['Id']) - self.SyncData['Libraries'] = selected_libraries + self.EmbyServer.Utils.SyncData['Libraries'] = selected_libraries return [libraries[x - 1] for x in selection] #Main sync process - def start(self): - self.LOG.info("starting sync with %s" % self.SyncData['Libraries']) - self.library.Monitor.Service.Utils.save_sync(self.SyncData, True) + def FullSync(self): + self.LOG.info("-->[ starting sync with %s ]" % self.EmbyServer.Utils.SyncData['Libraries']) + + if not self.EmbyServer.Utils.settings('dbSyncScreensaver.bool'): + xbmc.executebuiltin('InhibitIdleShutdown(true)') + self.screensaver = self.EmbyServer.Utils.Screensaver + self.EmbyServer.Utils.set_screensaver(value="") + + self.running = True + self.EmbyServer.Utils.save_sync(self.EmbyServer.Utils.SyncData, True) start_time = datetime.datetime.now() - for library in list(self.SyncData['Libraries']): + for library in list(self.EmbyServer.Utils.SyncData['Libraries']): if not self.process_library(library): + self.running = False return - if not library.startswith('Boxsets:') and library not in self.SyncData['Whitelist']: - self.SyncData['Whitelist'].append(library) + if not library.startswith('Boxsets:') and library not in self.EmbyServer.Utils.SyncData['Whitelist']: + self.EmbyServer.Utils.SyncData['Whitelist'].append(library) - self.SyncData['Libraries'].pop(self.SyncData['Libraries'].index(library)) + self.EmbyServer.Utils.SyncData['Libraries'].pop(self.EmbyServer.Utils.SyncData['Libraries'].index(library)) self._restore_point({}) elapsed = datetime.datetime.now() - start_time - self.library.Monitor.Service.Utils.settings('SyncInstallRunDone.bool', True) - self.library.save_last_sync() - self.library.Monitor.Service.Utils.save_sync(self.SyncData, True) + self.EmbyServer.Utils.settings('SyncInstallRunDone.bool', True) + self.EmbyServer.Utils.save_last_sync() + self.EmbyServer.Utils.save_sync(self.EmbyServer.Utils.SyncData, True) xbmc.executebuiltin('UpdateLibrary(video)') - self.library.Monitor.Service.Utils.dialog("notification", heading="{emby}", message="%s %s" % (self.library.Monitor.Service.Utils.Translate(33025), str(elapsed).split('.')[0]), icon="{emby}", sound=False) - self.LOG.info("Full sync completed in: %s" % str(elapsed).split('.')[0]) + self.EmbyServer.Utils.dialog("notification", heading="{emby}", message="%s %s" % (self.EmbyServer.Utils.Translate(33025), str(elapsed).split('.')[0]), icon="{emby}", sound=False) + self.running = False + + if self.screensaver is not None: + xbmc.executebuiltin('InhibitIdleShutdown(false)') + self.EmbyServer.Utils.set_screensaver(value=self.screensaver) + + self.LOG.info("--<[ Full sync completed in: %s ]" % str(elapsed).split('.')[0]) - #Add a library by it's id. Create a node and a playlist whenever appropriate def process_library(self, library_id): if library_id.startswith('Boxsets:'): if library_id.endswith('Refresh'): @@ -185,13 +182,13 @@ def process_library(self, library_id): return True - library = self.library.EmbyServer.API.get_item(library_id.replace('Mixed:', "")) + library = self.EmbyServer.API.get_item(library_id.replace('Mixed:', "")) if library_id.startswith('Mixed:'): self.movies(library) - self.SyncData['RestorePoint'] = {} + self.EmbyServer.Utils.SyncData['RestorePoint'] = {} self.tvshows(library) - self.SyncData['RestorePoint'] = {} + self.EmbyServer.Utils.SyncData['RestorePoint'] = {} else: if library['CollectionType'] == 'movies': self.movies(library) @@ -200,11 +197,11 @@ def process_library(self, library_id): elif library['CollectionType'] == 'tvshows': self.tvshows(library) elif library['CollectionType'] == 'music': - self.library.Monitor.Service.Utils.settings('enableMusic.bool', True) + self.EmbyServer.Utils.settings('enableMusic.bool', True) self.music(library) - if self.library.Monitor.Service.SyncPause: - self.library.Monitor.Service.Utils.save_sync(self.SyncData, True) + if self.Player.SyncPause: + self.EmbyServer.Utils.save_sync(self.EmbyServer.Utils.SyncData, True) return False return True @@ -212,23 +209,23 @@ def process_library(self, library_id): #Process movies from a single library def movies(self, library): dialog = xbmcgui.DialogProgressBG() - dialog.create(self.library.Monitor.Service.Utils.Translate('addon_name'), "%s %s" % (self.library.Monitor.Service.Utils.Translate('gathering'), "Movies")) + dialog.create(self.EmbyServer.Utils.Translate('addon_name'), "%s %s" % (self.EmbyServer.Utils.Translate('gathering'), "Movies")) - with self.library.ThreadingLock: - with database.Database(self.library.Monitor.Service.Utils, 'video', True) as videodb: - with database.Database(self.library.Monitor.Service.Utils, 'emby', True) as embydb: - MoviesObject = core.movies.Movies(self.library.EmbyServer, embydb, videodb, self.direct_path, self.library.Monitor.Service.Utils, self.library.Downloader) - TotalRecords = self.library.Downloader.get_TotalRecordsRegular(library['Id'], "Movie") + with self.ThreadingLock: + with database.Database(self.EmbyServer.Utils, 'video', True) as videodb: + with database.Database(self.EmbyServer.Utils, 'emby', True) as embydb: + MoviesObject = core.movies.Movies(self.EmbyServer, embydb, videodb) + TotalRecords = self.EmbyServer.API.get_TotalRecordsRegular(library['Id'], "Movie") - for items in self.library.Downloader.get_items(library['Id'], "Movie", False, self.SyncData['RestorePoint'].get('params')): + for items in self.EmbyServer.API.get_itemsSync(library['Id'], "Movie", False, self.EmbyServer.Utils.SyncData['RestorePoint'].get('params')): self._restore_point(items['RestorePoint']) start_index = items['RestorePoint']['params']['StartIndex'] for index, movie in enumerate(items['Items']): - dialog.update(int((float(start_index + index) / TotalRecords) * 100), heading="%s: %s" % (self.library.Monitor.Service.Utils.Translate('addon_name'), library['Name']), message=movie['Name']) + dialog.update(int((float(start_index + index) / TotalRecords) * 100), heading="%s: %s" % (self.EmbyServer.Utils.Translate('addon_name'), library['Name']), message=movie['Name']) MoviesObject.movie(movie, library) - if self.library.Monitor.Service.SyncPause: + if self.Player.SyncPause: dialog.close() return @@ -243,32 +240,31 @@ def movies(self, library): dialog.close() - #Process tvshows and episodes from a single library def tvshows(self, library): dialog = xbmcgui.DialogProgressBG() - dialog.create(self.library.Monitor.Service.Utils.Translate('addon_name'), "%s %s" % (self.library.Monitor.Service.Utils.Translate('gathering'), "TV Shows")) + dialog.create(self.EmbyServer.Utils.Translate('addon_name'), "%s %s" % (self.EmbyServer.Utils.Translate('gathering'), "TV Shows")) - with self.library.ThreadingLock: - with database.Database(self.library.Monitor.Service.Utils, 'video', True) as videodb: - with database.Database(self.library.Monitor.Service.Utils, 'emby', True) as embydb: - TVShowsObject = core.tvshows.TVShows(self.library.EmbyServer, embydb, videodb, self.direct_path, self.library.Monitor.Service.Utils, self.library.Downloader, True) - TotalRecords = self.library.Downloader.get_TotalRecordsRegular(library['Id'], "Series") + with self.ThreadingLock: + with database.Database(self.EmbyServer.Utils, 'video', True) as videodb: + with database.Database(self.EmbyServer.Utils, 'emby', True) as embydb: + TVShowsObject = core.tvshows.TVShows(self.EmbyServer, embydb, videodb, True) + TotalRecords = self.EmbyServer.API.get_TotalRecordsRegular(library['Id'], "Series") - for items in self.library.Downloader.get_items(library['Id'], "Series", False, self.SyncData['RestorePoint'].get('params')): + for items in self.EmbyServer.API.get_itemsSync(library['Id'], "Series", False, self.EmbyServer.Utils.SyncData['RestorePoint'].get('params')): self._restore_point(items['RestorePoint']) start_index = items['RestorePoint']['params']['StartIndex'] for index, show in enumerate(items['Items']): percent = int((float(start_index + index) / TotalRecords)*100) - dialog.update(percent, heading="%s: %s" % (self.library.Monitor.Service.Utils.Translate('addon_name'), library['Name']), message=show['Name']) + dialog.update(percent, heading="%s: %s" % (self.EmbyServer.Utils.Translate('addon_name'), library['Name']), message=show['Name']) if TVShowsObject.tvshow(show, library, None, None): - for episodes in self.library.Downloader.get_episode_by_show(show['Id']): + for episodes in self.EmbyServer.API.get_episode_by_show(show['Id']): for episode in episodes['Items']: dialog.update(percent, message="%s/%s" % (show['Name'], episode['Name'][:10])) TVShowsObject.episode(episode, library) - if self.library.Monitor.Service.SyncPause: + if self.Player.SyncPause: dialog.close() return @@ -287,26 +283,25 @@ def tvshows(self, library): dialog.close() - #Process musicvideos from a single library def musicvideos(self, library): dialog = xbmcgui.DialogProgressBG() - dialog.create(self.library.Monitor.Service.Utils.Translate('addon_name'), "%s %s" % (self.library.Monitor.Service.Utils.Translate('gathering'), "Musicvideos")) + dialog.create(self.EmbyServer.Utils.Translate('addon_name'), "%s %s" % (self.EmbyServer.Utils.Translate('gathering'), "Musicvideos")) - with self.library.ThreadingLock: - with database.Database(self.library.Monitor.Service.Utils, 'video', True) as videodb: - with database.Database(self.library.Monitor.Service.Utils, 'emby', True) as embydb: - MusicVideosObject = core.musicvideos.MusicVideos(self.library.EmbyServer, embydb, videodb, self.direct_path, self.library.Monitor.Service.Utils) - TotalRecords = self.library.Downloader.get_TotalRecordsRegular(library['Id'], "MusicVideo") + with self.ThreadingLock: + with database.Database(self.EmbyServer.Utils, 'video', True) as videodb: + with database.Database(self.EmbyServer.Utils, 'emby', True) as embydb: + MusicVideosObject = core.musicvideos.MusicVideos(self.EmbyServer, embydb, videodb) + TotalRecords = self.EmbyServer.API.get_TotalRecordsRegular(library['Id'], "MusicVideo") - for items in self.library.Downloader.get_items(library['Id'], "MusicVideo", False, self.SyncData['RestorePoint'].get('params')): + for items in self.EmbyServer.API.get_itemsSync(library['Id'], "MusicVideo", False, self.EmbyServer.Utils.SyncData['RestorePoint'].get('params')): self._restore_point(items['RestorePoint']) start_index = items['RestorePoint']['params']['StartIndex'] for index, mvideo in enumerate(items['Items']): - dialog.update(int((float(start_index + index) / TotalRecords) * 100), heading="%s: %s" % (self.library.Monitor.Service.Utils.Translate('addon_name'), library['Name']), message=mvideo['Name']) + dialog.update(int((float(start_index + index) / TotalRecords) * 100), heading="%s: %s" % (self.EmbyServer.Utils.Translate('addon_name'), library['Name']), message=mvideo['Name']) MusicVideosObject.musicvideo(mvideo, library) - if self.library.Monitor.Service.SyncPause: + if self.Player.SyncPause: dialog.close() return @@ -321,40 +316,39 @@ def musicvideos(self, library): dialog.close() - #Process artists, album, songs from a single library def music(self, library): self.patch_music(True) dialog = xbmcgui.DialogProgressBG() - dialog.create(self.library.Monitor.Service.Utils.Translate('addon_name'), "%s %s" % (self.library.Monitor.Service.Utils.Translate('gathering'), "Music")) + dialog.create(self.EmbyServer.Utils.Translate('addon_name'), "%s %s" % (self.EmbyServer.Utils.Translate('gathering'), "Music")) - with self.library.ThreadingLock: - with database.Database(self.library.Monitor.Service.Utils, 'music', True) as musicdb: - with database.Database(self.library.Monitor.Service.Utils, 'emby', True) as embydb: - MusicObject = core.music.Music(self.library.EmbyServer, embydb, musicdb, self.direct_path, self.library.Monitor.Service.Utils) - TotalRecords = self.library.Downloader.get_TotalRecordsArtists(library['Id']) + with self.ThreadingLock: + with database.Database(self.EmbyServer.Utils, 'music', True) as musicdb: + with database.Database(self.EmbyServer.Utils, 'emby', True) as embydb: + MusicObject = core.music.Music(self.EmbyServer, embydb, musicdb) + TotalRecords = self.EmbyServer.API.get_TotalRecordsArtists(library['Id']) - for items in self.library.Downloader.get_artists(library['Id'], False, self.SyncData['RestorePoint'].get('params')): + for items in self.EmbyServer.API.get_artists(library['Id'], False, self.EmbyServer.Utils.SyncData['RestorePoint'].get('params')): self._restore_point(items['RestorePoint']) start_index = items['RestorePoint']['params']['StartIndex'] for index, artist in enumerate(items['Items']): percent = int((float(start_index + index) / TotalRecords) * 100) - dialog.update(percent, heading="%s: %s" % (self.library.Monitor.Service.Utils.Translate('addon_name'), library['Name']), message=artist['Name']) + dialog.update(percent, heading="%s: %s" % (self.EmbyServer.Utils.Translate('addon_name'), library['Name']), message=artist['Name']) MusicObject.artist(artist, library) - for albums in self.library.Downloader.get_albums_by_artist(library['Id'], artist['Id'], False): + for albums in self.EmbyServer.API.get_albums_by_artist(library['Id'], artist['Id'], False): for album in albums['Items']: MusicObject.album(album, library) - if self.library.Monitor.Service.SyncPause: + if self.Player.SyncPause: dialog.close() return - for songs in self.library.Downloader.get_songs_by_artist(library['Id'], artist['Id'], False): + for songs in self.EmbyServer.API.get_songs_by_artist(library['Id'], artist['Id'], False): for song in songs['Items']: MusicObject.song(song, library) - if self.library.Monitor.Service.SyncPause: + if self.Player.SyncPause: dialog.close() return @@ -373,26 +367,25 @@ def music(self, library): dialog.close() - #Process all boxsets def boxsets(self, library_id): dialog = xbmcgui.DialogProgressBG() - dialog.create(self.library.Monitor.Service.Utils.Translate('addon_name'), "%s %s" % (self.library.Monitor.Service.Utils.Translate('gathering'), "Boxsets")) + dialog.create(self.EmbyServer.Utils.Translate('addon_name'), "%s %s" % (self.EmbyServer.Utils.Translate('gathering'), "Boxsets")) - with self.library.ThreadingLock: - with database.Database(self.library.Monitor.Service.Utils, 'video', True) as videodb: - with database.Database(self.library.Monitor.Service.Utils, 'emby', True) as embydb: - MoviesObject = core.movies.Movies(self.library.EmbyServer, embydb, videodb, self.direct_path, self.library.Monitor.Service.Utils, self.library.Downloader) - TotalRecords = self.library.Downloader.get_TotalRecordsRegular(library_id, "BoxSet") + with self.ThreadingLock: + with database.Database(self.EmbyServer.Utils, 'video', True) as videodb: + with database.Database(self.EmbyServer.Utils, 'emby', True) as embydb: + MoviesObject = core.movies.Movies(self.EmbyServer, embydb, videodb) + TotalRecords = self.EmbyServer.API.get_TotalRecordsRegular(library_id, "BoxSet") - for items in self.library.Downloader.get_items(library_id, "BoxSet", False, self.SyncData['RestorePoint'].get('params')): + for items in self.EmbyServer.API.get_itemsSync(library_id, "BoxSet", False, self.EmbyServer.Utils.SyncData['RestorePoint'].get('params')): self._restore_point(items['RestorePoint']) start_index = items['RestorePoint']['params']['StartIndex'] for index, boxset in enumerate(items['Items']): - dialog.update(int((float(start_index + index) / TotalRecords) * 100), heading="%s: %s" % (self.library.Monitor.Service.Utils.Translate('addon_name'), self.library.Monitor.Service.Utils.Translate('boxsets')), message=boxset['Name']) + dialog.update(int((float(start_index + index) / TotalRecords) * 100), heading="%s: %s" % (self.EmbyServer.Utils.Translate('addon_name'), self.EmbyServer.Utils.Translate('boxsets')), message=boxset['Name']) MoviesObject.boxset(boxset) - if self.library.Monitor.Service.SyncPause: + if self.Player.SyncPause: dialog.close() return @@ -400,32 +393,30 @@ def boxsets(self, library_id): #Delete all exisitng boxsets and re-add def refresh_boxsets(self): - with self.library.ThreadingLock: - with database.Database(self.library.Monitor.Service.Utils, 'video', True) as videodb: - with database.Database(self.library.Monitor.Service.Utils, 'emby', True) as embydb: - MoviesObject = core.movies.Movies(self.library.EmbyServer, embydb, videodb, self.direct_path, self.library.Monitor.Service.Utils, self.library.Downloader) + with self.ThreadingLock: + with database.Database(self.EmbyServer.Utils, 'video', True) as videodb: + with database.Database(self.EmbyServer.Utils, 'emby', True) as embydb: + MoviesObject = core.movies.Movies(self.EmbyServer, embydb, videodb) MoviesObject.boxsets_reset() self.boxsets(None) - #Patch the music database to silence the rescan prompt def patch_music(self, notification): - with self.library.ThreadingLock: - with database.Database(self.library.Monitor.Service.Utils, 'music', True) as musicdb: - core.music.MusicDBIO(musicdb.cursor, int(self.library.Monitor.Service.Utils.window('kodidbversion.music'))).disable_rescan() + with self.ThreadingLock: + with database.Database(self.EmbyServer.Utils, 'music', True) as musicdb: + core.music.MusicDBIO(musicdb.cursor, self.EmbyServer.Utils.DatabaseFiles['music-version']).disable_rescan() - self.library.Monitor.Service.Utils.settings('MusicRescan.bool', True) + self.EmbyServer.Utils.settings('MusicRescan.bool', True) if notification: - self.library.Monitor.Service.Utils.dialog("notification", heading="{emby}", message=self.library.Monitor.Service.Utils.Translate('task_success'), icon="{emby}", time=1000, sound=False) + self.EmbyServer.Utils.dialog("notification", heading="{emby}", message=self.EmbyServer.Utils.Translate('task_success'), icon="{emby}", time=1000, sound=False) #Remove library by their id from the Kodi database def remove_library(self, library_id): dialog = xbmcgui.DialogProgressBG() - dialog.create(self.library.Monitor.Service.Utils.Translate('addon_name')) - direct_path = self.library.direct_path + dialog.create(self.EmbyServer.Utils.Translate('addon_name')) - with database.Database(self.library.Monitor.Service.Utils, 'emby', True) as embydb: + with database.Database(self.EmbyServer.Utils, 'emby', True) as embydb: db = emby_db.EmbyDatabase(embydb.cursor) library = db.get_view(library_id.replace('Mixed:', "")) items = db.get_item_by_media_folder(library_id.replace('Mixed:', "")) @@ -434,57 +425,44 @@ def remove_library(self, library_id): if items: count = 0 - with self.library.ThreadingLock: - with database.Database(self.library.Monitor.Service.Utils, media, True) as kodidb: + with self.ThreadingLock: + with database.Database(self.EmbyServer.Utils, media, True) as kodidb: if library[1] == 'mixed': movies = [x for x in items if x[1] == 'Movie'] tvshows = [x for x in items if x[1] == 'Series'] - MediaObject = core.movies.Movies(self.library.EmbyServer, embydb, kodidb, direct_path, self.library.Monitor.Service.Utils, self.library.Downloader).remove + MediaObject = core.movies.Movies(self.EmbyServer, embydb, kodidb).remove for item in movies: MediaObject(item[0]) - dialog.update(int((float(count) / float(len(items)) * 100)), heading="%s: %s" % (self.library.Monitor.Service.Utils.Translate('addon_name'), library[0])) + dialog.update(int((float(count) / float(len(items)) * 100)), heading="%s: %s" % (self.EmbyServer.Utils.Translate('addon_name'), library[0])) count += 1 - MediaObject = core.tvshows.TVShows(self.library.EmbyServer, embydb, kodidb, direct_path, self.library.Monitor.Service.Utils, self.library.Downloader).remove + MediaObject = core.tvshows.TVShows(self.EmbyServer, embydb, kodidb).remove for item in tvshows: MediaObject(item[0]) - dialog.update(int((float(count) / float(len(items)) * 100)), heading="%s: %s" % (self.library.Monitor.Service.Utils.Translate('addon_name'), library[0])) + dialog.update(int((float(count) / float(len(items)) * 100)), heading="%s: %s" % (self.EmbyServer.Utils.Translate('addon_name'), library[0])) count += 1 else: if items[0][1] in ('Movie', 'BoxSet'): - MediaObject = core.movies.Movies(self.library.EmbyServer, embydb, kodidb, direct_path, self.library.Monitor.Service.Utils, self.library.Downloader).remove + MediaObject = core.movies.Movies(self.EmbyServer, embydb, kodidb).remove if items[0][1] == 'MusicVideo': - MediaObject = core.musicvideos.MusicVideos(self.library.EmbyServer, embydb, kodidb, direct_path, self.library.Monitor.Service.Utils).remove + MediaObject = core.musicvideos.MusicVideos(self.EmbyServer, embydb, kodidb).remove if items[0][1] in ('TVShow', 'Series', 'Season', 'Episode'): - MediaObject = core.tvshows.TVShows(self.library.EmbyServer, embydb, kodidb, direct_path, self.library.Monitor.Service.Utils, self.library.Downloader).remove + MediaObject = core.tvshows.TVShows(self.EmbyServer, embydb, kodidb).remove if items[0][1] in ('Music', 'MusicAlbum', 'MusicArtist', 'AlbumArtist', 'Audio'): - MediaObject = core.music.Music(self.library.EmbyServer, embydb, kodidb, direct_path, self.library.Monitor.Service.Utils).remove + MediaObject = core.music.Music(self.EmbyServer, embydb, kodidb).remove for item in items: MediaObject(item[0]) - dialog.update(int((float(count) / float(len(items)) * 100)), heading="%s: %s" % (self.library.Monitor.Service.Utils.Translate('addon_name'), library[0])) + dialog.update(int((float(count) / float(len(items)) * 100)), heading="%s: %s" % (self.EmbyServer.Utils.Translate('addon_name'), library[0])) count += 1 dialog.close() - self.SyncData = self.library.Monitor.Service.Utils.get_sync() - if library_id in self.SyncData['Whitelist']: - self.SyncData['Whitelist'].remove(library_id) - elif 'Mixed:%s' % library_id in self.SyncData['Whitelist']: - self.SyncData['Whitelist'].remove('Mixed:%s' % library_id) - - self.library.Monitor.Service.Utils.save_sync(self.SyncData, True) - - #Exiting sync - def __exit__(self, exc_type, exc_val, exc_tb): - self.running = False - self.SyncInProgress = False - - if self.screensaver is not None: - xbmc.executebuiltin('InhibitIdleShutdown(false)') - self.library.Monitor.Service.Utils.set_screensaver(value=self.screensaver) - self.screensaver = None + if library_id in self.EmbyServer.Utils.SyncData['Whitelist']: + self.EmbyServer.Utils.SyncData['Whitelist'].remove(library_id) + elif 'Mixed:%s' % library_id in self.EmbyServer.Utils.SyncData['Whitelist']: + self.EmbyServer.Utils.SyncData['Whitelist'].remove('Mixed:%s' % library_id) - self.LOG.info("--<[ fullsync ]") + self.EmbyServer.Utils.save_sync(self.EmbyServer.Utils.SyncData, True) diff --git a/dialogs/context.py b/dialogs/context.py index 9b3b9b1ec..336a18c2f 100644 --- a/dialogs/context.py +++ b/dialogs/context.py @@ -57,6 +57,5 @@ def _add_editcontrol(self, x, y, height, width): self.addControl(control) return control - @classmethod - def _add_listitem(cls, label): + def _add_listitem(self, label): return xbmcgui.ListItem(label) diff --git a/dialogs/serverconnect.py b/dialogs/serverconnect.py index e493d4c15..65030dbcb 100644 --- a/dialogs/serverconnect.py +++ b/dialogs/serverconnect.py @@ -70,8 +70,7 @@ def onInit(self): if self.servers: self.setFocus(self.list_) - @classmethod - def _add_listitem(cls, label, server_id, server_type): + def _add_listitem(self, label, server_id, server_type): item = xbmcgui.ListItem(label) item.setProperty('id', server_id) item.setProperty('server_type', server_type) diff --git a/emby/connect.py b/emby/connect.py index c0ecfa498..f25d3674f 100644 --- a/emby/connect.py +++ b/emby/connect.py @@ -1,28 +1,30 @@ # -*- coding: utf-8 -*- +import json +import os + import xbmcaddon +import xbmcvfs -import database.database import dialogs.serverconnect import dialogs.usersconnect import dialogs.loginconnect import dialogs.loginmanual import dialogs.servermanual import helper.loghandler -import helper.api import emby.main -class Connect(): #ADD SERVER NUMBER FOR SELECTION OR RETURN SERVER ARRAY - def __init__(self, Monitor): - self.Monitor = Monitor +class Connect(): + def __init__(self, Utils): + self.Utils = Utils self.XML_PATH = (xbmcaddon.Addon("plugin.video.emby-next-gen").getAddonInfo('path'), "default", "1080i") self.LOG = helper.loghandler.LOG('EMBY.emby.connect.Connect') self.user = None self.config = None self.connect_manager = None - self.EmbyServerObj = emby.main.Emby() + self.EmbyServer = emby.main.Emby(self.Utils) def _save_servers(self, new_servers, default): - credentials = database.database.get_credentials(self.Monitor.Service.Utils) + credentials = self.get_credentials() if not new_servers: return credentials @@ -58,42 +60,87 @@ def _save_servers(self, new_servers, default): #If a server id is specified then only a login dialog will be shown for that server. def register(self, options): self.LOG.info("--[ server/%s ]" % "DEFAULT") - credentials = database.database.get_credentials(self.Monitor.Service.Utils) - new_credentials = self.register_client(credentials, options, not self.Monitor.Service.Utils.settings('SyncInstallRunDone.bool')) + credentials = self.get_credentials() + new_credentials = self.register_client(credentials, options, not self.Utils.settings('SyncInstallRunDone.bool')) if new_credentials: server_id = new_credentials['Servers'][0]['Id'] credentials = self._save_servers(new_credentials['Servers'], server_id) new_credentials.update(credentials) - database.database.save_credentials(self.Monitor.Service.Utils, new_credentials) - return server_id, self.EmbyServerObj #, new_credentials['Servers'][0]['Name'] + self.save_credentials(new_credentials) + return server_id, self.EmbyServer return False, None + + + + + def save_credentials(self, credentials): + path = self.Utils.translatePath("special://profile/addon_data/plugin.video.emby-next-gen/") + + if not xbmcvfs.exists(path): + xbmcvfs.mkdirs(path) + + credentials = json.dumps(credentials, sort_keys=True, indent=4, ensure_ascii=False) + + with open(os.path.join(path, 'data.json'), 'wb') as outfile: + outfile.write(credentials.encode('utf-8')) + + + + + def get_credentials(self): + + +#self.EmbyServer.server_id + + + + path = self.Utils.translatePath("special://profile/addon_data/plugin.video.emby-next-gen/") + + if not xbmcvfs.exists(path): + xbmcvfs.mkdirs(path) + + if xbmcvfs.exists(os.path.join(path, "data.json")): + with open(os.path.join(path, 'data.json'), 'rb') as infile: + credentials = json.load(infile) + else: + credentials = {} + + credentials['Servers'] = credentials.get('Servers', []) + return credentials + + + + + + + #Returns boolean value. #True: verify connection. def get_ssl(self): - return self.Monitor.Service.Utils.settings('sslverify.bool') + return self.Utils.settings('sslverify.bool') #Set Emby client def set_client(self): - self.EmbyServerObj.Data['app.name'] = "Kodi" - self.EmbyServerObj.Data['app.version'] = self.Monitor.Service.Utils.device_info['Version'] - self.EmbyServerObj.Data['app.device_name'] = self.Monitor.Service.Utils.device_info['DeviceName'] - self.EmbyServerObj.Data['app.device_id'] = self.Monitor.Service.Utils.device_info['DeviceId'] - self.EmbyServerObj.Data['app.capabilities'] = None - self.EmbyServerObj.Data['http.user_agent'] = "Emby-Kodi/%s" % self.Monitor.Service.Utils.device_info['Version'] - self.EmbyServerObj.Data['auth.ssl'] = self.Monitor.Service.Utils.settings('sslverify.bool') + self.EmbyServer.Data['app.name'] = "Kodi" + self.EmbyServer.Data['app.version'] = self.Utils.device_info['Version'] + self.EmbyServer.Data['app.device_name'] = self.Utils.device_info['DeviceName'] + self.EmbyServer.Data['app.device_id'] = self.Utils.device_info['DeviceId'] + self.EmbyServer.Data['app.capabilities'] = None + self.EmbyServer.Data['http.user_agent'] = "Emby-Kodi/%s" % self.Utils.device_info['Version'] + self.EmbyServer.Data['auth.ssl'] = self.Utils.settings('sslverify.bool') def register_client(self, credentials, options, server_selection): self.set_client() - self.connect_manager = self.EmbyServerObj.auth - state = self.EmbyServerObj.authenticate(credentials or {}, options or {}) + self.connect_manager = self.EmbyServer.auth + state = self.EmbyServer.authenticate(credentials or {}, options or {}) if state: if state['State'] == 3: #SignedIn server_id = state['Servers'][0]['Id'] - self.EmbyServerObj.server_id = server_id + self.EmbyServer.server_id = server_id return state['Credentials'] if state['State'] == 0: #Unavailable @@ -106,24 +153,26 @@ def register_client(self, credentials, options, server_selection): return False elif state['State'] == 2: #ServerSignIn if 'ExchangeToken' not in state['Servers'][0]: - self.login() + result = self.login() + + if not result: + return False + elif state['State'] == 0: #Unavailable return False return self.register_client(state['Credentials'], options, False) - return False -# return self.EmbyServerObj.auth.credentials.get_credentials() #Save user info def get_user(self): - self.user = self.EmbyServerObj.API.get_user(None) - self.config = self.EmbyServerObj.API.get_system_info() - self.Monitor.Service.Utils.settings('username', self.user['Name']) + self.user = self.EmbyServer.API.get_user(None) + self.config = self.EmbyServer.API.get_system_info() + self.Utils.settings('username', self.user['Name']) if 'PrimaryImageTag' in self.user: - self.Monitor.Service.Utils.window('emby.UserImage', helper.api.API(self.user, self.Monitor.Service.Utils, self.EmbyServerObj.auth.get_serveraddress()).get_user_artwork(self.user['Id'])) + self.Utils.window('emby.UserImage', self.EmbyServer.API.get_user_artwork(self.user['Id'])) def select_servers(self, state): if not state: @@ -159,18 +208,18 @@ def select_servers(self, state): return self.select_servers(None) #Setup manual servers - def setup_manual_server(self): - credentials = database.database.get_credentials(self.Monitor.Service.Utils) - self.set_client() - self.EmbyServerObj.auth.credentials.set_credentials(credentials) - manager = self.EmbyServerObj.auth +# def setup_manual_server(self): +# credentials = database.database.get_credentials(self.Utils) +# self.set_client() +# self.EmbyServer.auth.credentials.set_credentials(credentials) +# manager = self.EmbyServer.auth - if not self.manual_server(manager): - return +# if not self.manual_server(manager): +# return - new_credentials = self.EmbyServerObj.auth.credentials.get_credentials() - credentials = self._save_servers(new_credentials['Servers'], False) - database.database.save_credentials(self.Monitor.Service.Utils, credentials) +# new_credentials = self.EmbyServer.auth.credentials.get_credentials() +# credentials = self._save_servers(new_credentials['Servers'], False) +# database.database.save_credentials(self.Utils, credentials) #Return server or raise error def manual_server(self, manager): @@ -185,18 +234,19 @@ def manual_server(self, manager): return False #Setup emby connect by itself - def setup_login_connect(self): - credentials = database.database.get_credentials(self.Monitor.Service.Utils) - self.set_client() - self.EmbyServerObj.auth.credentials.set_credentials(credentials) - manager = self.EmbyServerObj.auth +# def setup_login_connect(self): +# credentials = database.database.get_credentials(self.Utils) +# self.set_client() +# self.EmbyServer.auth.credentials.set_credentials(credentials) +# manager = self.EmbyServer.auth +# result = self.login_connect(manager) - if not self.login_connect(manager): - return +# if not result: +# return - new_credentials = self.EmbyServerObj.auth.credentials.get_credentials() - credentials = self._save_servers(new_credentials['Servers'], False) - database.database.save_credentials(self.Monitor.Service.Utils, credentials) +# new_credentials = self.EmbyServer.auth.credentials.get_credentials() +# credentials = self._save_servers(new_credentials['Servers'], False) +# database.database.save_credentials(self.Utils, credentials) #Return connect user or raise error def login_connect(self, manager): @@ -210,8 +260,8 @@ def login_connect(self, manager): return False #"Connect user is not logged in" def login(self): - users = self.EmbyServerObj.API.get_public_users() - server = self.EmbyServerObj.auth.get_serveraddress() + users = self.EmbyServer.API.get_public_users() + server = self.EmbyServer.auth.get_serveraddress() if not users: return self.login_manual(None, None) @@ -242,19 +292,6 @@ def login(self): return self.login() - #Setup manual login by itself for default server - def setup_login_manual(self, server_id): - credentials = database.database.get_credentials(self.Monitor.Service.Utils) - self.set_client() - self.EmbyServerObj.auth.credentials.set_credentials(credentials) - - if not self.login_manual(None, self.EmbyServerObj.auth): - return - - new_credentials = self.EmbyServerObj.auth.credentials.get_credentials() - credentials = self._save_servers(new_credentials['Servers'], False) - database.database.save_credentials(self.Monitor.Service.Utils, credentials) - #Return manual login user authenticated or raise error def login_manual(self, user, manager): Dialog = dialogs.loginmanual.LoginManual("script-emby-connect-login-manual.xml", *self.XML_PATH) @@ -268,25 +305,24 @@ def login_manual(self, user, manager): #Stop client and remove server def remove_server(self, server_id): - self.Monitor.EmbyServer[server_id].close() - credentials = database.database.get_credentials(self.Monitor.Service.Utils) + credentials = self.get_credentials() for server in credentials['Servers']: if server['Id'] == server_id: credentials['Servers'].remove(server) break - database.database.save_credentials(self.Monitor.Service.Utils, credentials) + self.save_credentials(credentials) self.LOG.info("[ remove server ] %s" % server_id) #Allow user to setup ssl verification for additional servers def set_ssl(self, server_id): - value = self.Monitor.Service.Utils.Dialog("yesno", heading="{emby}", line1=self.Monitor.Service.Utils.Translate(33217)) - credentials = database.database.get_credentials(self.Monitor.Service.Utils) + value = self.Utils.Dialog("yesno", heading="{emby}", line1=self.Utils.Translate(33217)) + credentials = self.get_credentials() for server in credentials['Servers']: if server['Id'] == server_id: server['verify'] = bool(value) - database.database.save_credentials(self.Monitor.Service.Utils, credentials) + self.save_credentials(credentials) self.LOG.info("[ ssl/%s/%s ]" % (server_id, server['verify'])) break diff --git a/emby/core/api.py b/emby/core/api.py index 44d7bae0c..e66e008b3 100644 --- a/emby/core/api.py +++ b/emby/core/api.py @@ -1,16 +1,227 @@ # -*- coding: utf-8 -*- +import helper.loghandler + class API(): def __init__(self, EmbyServer): self.EmbyServer = EmbyServer - self.info = ( - "Path,Genres,SortName,Studios,Writer,Taglines,LocalTrailerCount,Video3DFormat," - "OfficialRating,CumulativeRunTimeTicks,ItemCounts,PremiereDate,ProductionYear," - "Metascore,AirTime,DateCreated,People,Overview,CommunityRating,StartDate," - "CriticRating,CriticRatingSummary,Etag,ShortOverview,ProductionLocations," - "Tags,ProviderIds,ParentId,RemoteTrailers,SpecialEpisodeNumbers,Status,EndDate," - "MediaSources,VoteCount,RecursiveItemCount,PrimaryImageAspectRatio,DisplayOrder," - "PresentationUniqueKey,OriginalTitle,MediaSources,AlternateMediaSources,PartCount" - ) + self.LOG = helper.loghandler.LOG('EMBY.emby.api.API') + self.LIMIT = min(int(self.EmbyServer.Utils.settings('limitIndex') or 15), 50) + self.info = "Path,Genres,SortName,Studios,Writer,Taglines,LocalTrailerCount,Video3DFormat,OfficialRating,CumulativeRunTimeTicks,ItemCounts,PremiereDate,ProductionYear,Metascore,AirTime,DateCreated,People,Overview,CommunityRating,StartDate,CriticRating,CriticRatingSummary,Etag,ShortOverview,ProductionLocations,Tags,ProviderIds,ParentId,RemoteTrailers,SpecialEpisodeNumbers,Status,EndDate,MediaSources,VoteCount,RecursiveItemCount,PrimaryImageAspectRatio,DisplayOrder,PresentationUniqueKey,OriginalTitle,AlternateMediaSources,PartCount" + self.music_info = "Etag,Genres,SortName,Studios,Writer,PremiereDate,ProductionYear,OfficialRating,CumulativeRunTimeTicks,Metascore,CommunityRating,AirTime,DateCreated,MediaStreams,People,ProviderIds,Overview,ItemCounts,PresentationUniqueKey" + self.browse_info = "DateCreated,EpisodeCount,SeasonCount,Path,Genres,Studios,Taglines,MediaStreams,Overview,Etag,ProductionLocations,Width,Height,RecursiveItemCount,ChildCount" + + #This confirms a single item from the library matches the view it belongs to. + #Used to detect grouped libraries. + def validate_view(self, library_id, item_id): + try: + result = self._get("Users/{UserId}/Items", {'ParentId': library_id, 'Recursive': True, 'Ids': item_id}) + except Exception: + return False + + return bool(len(result['Items'])) + + #Get emby user profile picture. + def get_user_artwork(self, user_id): + return "%s/emby/Users/%s/Images/Primary?Format=original" % (self.EmbyServer.Data['auth.server'], user_id) + + #Get dynamic listings + def get_filtered_section(self, parent_id, media, limit, recursive, sort, sort_order, filters, extra, NoSort): + if NoSort: + params = { + 'ParentId': parent_id, + 'IncludeItemTypes': media, + 'IsMissing': False, + 'Recursive': recursive if recursive is not None else True, + 'Limit': limit, + 'ImageTypeLimit': 1, + 'IsVirtualUnaired': False, + 'Fields': self.browse_info + } + else: + params = { + 'ParentId': parent_id, + 'IncludeItemTypes': media, + 'IsMissing': False, + 'Recursive': recursive if recursive is not None else True, + 'Limit': limit, + 'SortBy': sort or "SortName", + 'SortOrder': sort_order or "Ascending", + 'ImageTypeLimit': 1, + 'IsVirtualUnaired': False, + 'Fields': self.browse_info + } + + if filters: + if 'Boxsets' in filters: + filters.remove('Boxsets') + params['CollapseBoxSetItems'] = self.EmbyServer.Utils.settings('groupedSets.bool') + + params['Filters'] = ','.join(filters) + + if self.EmbyServer.Utils.settings('getCast.bool'): + params['Fields'] += ",People" + + if media and 'Photo' in media: + params['Fields'] += ",Width,Height" + + if extra is not None: + params.update(extra) + + return self._get("Users/{UserId}/Items", params) + + def get_movies_by_boxset(self, boxset_id): + for items in self.get_itemsSync(boxset_id, "Movie", False, None): + yield items + + def get_episode_by_show(self, show_id): + query = { + 'url': "Shows/%s/Episodes" % show_id, + 'params': { + 'EnableUserData': True, + 'EnableImages': True, + 'UserId': "{UserId}", + 'Fields': self.info + } + } + + for items in self._get_items(query, self.LIMIT): + yield items + + def get_episode_by_season(self, show_id, season_id): + query = { + 'url': "Shows/%s/Episodes" % show_id, + 'params': { + 'SeasonId': season_id, + 'EnableUserData': True, + 'EnableImages': True, + 'UserId': "{UserId}", + 'Fields': self.info + } + } + + for items in self._get_items(query, self.LIMIT): + yield items + + def get_itemsSync(self, parent_id, item_type, basic, params): + query = { + 'url': "Users/{UserId}/Items", + 'params': { + 'ParentId': parent_id, + 'IncludeItemTypes': item_type, + 'Fields': "Etag,PresentationUniqueKey" if basic else self.info, + 'CollapseBoxSetItems': False, + 'IsVirtualUnaired': False, + 'EnableTotalRecordCount': False, + 'LocationTypes': "FileSystem,Remote,Offline", + 'IsMissing': False, + 'Recursive': True + } + } + + if params: + query['params'].update(params) + + for items in self._get_items(query, self.LIMIT): + yield items + + def get_artists(self, parent_id, basic, params): + query = { + 'url': "Artists", + 'params': { + 'UserId': "{UserId}", + 'ParentId': parent_id, + 'Fields': "Etag,PresentationUniqueKey" if basic else self.music_info, + 'CollapseBoxSetItems': False, + 'IsVirtualUnaired': False, + 'EnableTotalRecordCount': False, + 'LocationTypes': "FileSystem,Remote,Offline", + 'IsMissing': False, + 'Recursive': True + } + } + + if params: + query['params'].update(params) + + for items in self._get_items(query, self.LIMIT): + yield items + + def get_albums_by_artist(self, parent_id, artist_id, basic): + params = { + 'ParentId': parent_id, + 'ArtistIds': artist_id + } + + for items in self.get_itemsSync(None, "MusicAlbum", basic, params): + yield items + + def get_songs_by_artist(self, parent_id, artist_id, basic): + params = { + 'ParentId': parent_id, + 'ArtistIds': artist_id + } + + for items in self.get_itemsSync(None, "Audio", basic, params): + yield items + + def get_TotalRecordsRegular(self, parent_id, item_type): + Params = { + 'ParentId': parent_id, + 'IncludeItemTypes': item_type, + 'CollapseBoxSetItems': False, + 'IsVirtualUnaired': False, + 'IsMissing': False, + 'EnableTotalRecordCount': True, + 'LocationTypes': "FileSystem,Remote,Offline", + 'Recursive': True, + 'Limit': 1 + } + + return self._get("Users/{UserId}/Items", Params)['TotalRecordCount'] + + def get_TotalRecordsArtists(self, parent_id): + Params = { + 'UserId': "{UserId}", + 'ParentId': parent_id, + 'CollapseBoxSetItems': False, + 'IsVirtualUnaired': False, + 'IsMissing': False, + 'EnableTotalRecordCount': True, + 'LocationTypes': "FileSystem,Remote,Offline", + 'Recursive': True, + 'Limit': 1 + } + return self._get("Artists", Params)['TotalRecordCount'] + + def _get_items(self, query, LIMIT): + items = { + 'Items': [], + 'RestorePoint': {} + } + + url = query['url'] + params = query.get('params', {}) + index = params.get('StartIndex', 0) + + while True: + params['StartIndex'] = index + params['Limit'] = LIMIT + + try: + result = self._get(url, params) or {'Items': []} + except Exception as error: + self.LOG.error("ERROR: %s" % error) + result = {'Items': []} + + if result['Items'] == []: + items['TotalRecordCount'] = index + break + + items['Items'].extend(result['Items']) + items['RestorePoint'] = query + yield items + del items['Items'][:] + index += LIMIT def emby_url(self, handler): return "%s/emby/%s" % (self.EmbyServer.Data['auth.server'], handler) @@ -43,10 +254,6 @@ def _delete(self, handler, params): return self._http("DELETE", handler, {'params': params}) - ################################################################################################# - # Bigger section of the Emby api - ################################################################################################# - def try_server(self): return self._get("System/Info/Public", None) @@ -92,10 +299,6 @@ def artwork(self, item_id, art, max_width, ext, index): return self.emby_url("Items/%s/Images/%s/%s?MaxWidth=%s&format=%s" % (item_id, art, index, max_width, ext)) - ################################################################################################# - # More granular api - ################################################################################################# - def get_users(self, disabled, hidden): return self._get("Users", { 'IsDisabled': disabled, @@ -126,8 +329,8 @@ def get_items(self, item_ids): def get_sessions(self): return self.sessions("", "GET", {'ControllableByUserId': "{UserId}"}, None) - def get_device(self, device_id): - return self.sessions("", "GET", {'DeviceId': device_id}, None) + def get_device(self): + return self.sessions("", "GET", {'DeviceId': self.EmbyServer.Data['app.device_id']}, None) def post_session(self, session_id, url, params, data): return self.sessions("/%s/%s" % (session_id, url), "POST", params, data) @@ -336,8 +539,8 @@ def get_live_stream(self, item_id, play_id, token, profile): def close_live_stream(self, live_id): return self._post("LiveStreams/Close", {'LiveStreamId': live_id}, False) - def close_transcode(self, device_id): - return self._delete("Videos/ActiveEncodings", {'DeviceId': device_id}) + def close_transcode(self): + return self._delete("Videos/ActiveEncodings", {'DeviceId': self.EmbyServer.Data['app.device_id']}) def delete_item(self, item_id): return self.items("/%s" % item_id, "DELETE", None, None) diff --git a/emby/core/configuration.py b/emby/core/configuration.py deleted file mode 100644 index a9b30f40f..000000000 --- a/emby/core/configuration.py +++ /dev/null @@ -1,61 +0,0 @@ -# -*- coding: utf-8 -*- -#This will hold all configs from the client. -#Configuration set here will be used for the HTTP client. -import helper.loghandler - -class Config(): - def __init__(self): - self.LOG = helper.loghandler.LOG('Emby.emby.core.configuration') - self.LOG.debug("Configuration initializing...") - self.data = {} - self.http(None, 3, 30) - - def __shortcuts__(self, key): - if key == "auth": - return self.auth - - if key == "app": - return self.app - - if key == "http": - return self.http - - if key == "data": - return self - - return None - - def __setstate__(self, data): - self.data = data - - def __getstate__(self): - return self.data - - def __setitem__(self, key, value): - self.data[key] = value - - def __getitem__(self, key): - return self.data.get(key, self.__shortcuts__(key)) - - def app(self, name, version, device_name, device_id, capabilities, device_pixel_ratio): - self.LOG.debug("Begin app constructor") - self.data['app.name'] = name - self.data['app.version'] = version - self.data['app.device_name'] = device_name - self.data['app.device_id'] = device_id - self.data['app.capabilities'] = capabilities - self.data['app.device_pixel_ratio'] = device_pixel_ratio - self.data['app.default'] = False - - def auth(self, server, user_id, token, ssl): - self.LOG.debug("Begin auth constructor") - self.data['auth.server'] = server - self.data['auth.user_id'] = user_id - self.data['auth.token'] = token - self.data['auth.ssl'] = ssl - - def http(self, user_agent, max_retries, timeout): - self.LOG.debug("Begin http constructor") - self.data['http.max_retries'] = max_retries - self.data['http.timeout'] = timeout - self.data['http.user_agent'] = user_agent diff --git a/emby/core/connection_manager.py b/emby/core/connection_manager.py index daabde9f4..14bf71f85 100644 --- a/emby/core/connection_manager.py +++ b/emby/core/connection_manager.py @@ -6,7 +6,6 @@ import helper.loghandler import emby.core.credentials -import emby.core.http class ConnectionManager(): def __init__(self, EmbyServer): @@ -16,7 +15,6 @@ def __init__(self, EmbyServer): self.user = {} self.EmbyServer = EmbyServer self.credentials = emby.core.credentials.Credentials() - self.http = emby.core.http.HTTP(self.EmbyServer) def get_server_address(self, server, mode): modes = {0: server.get('LocalAddress'), 1: server.get('RemoteAddress'), 2: server.get('ManualAddress')} #Local...Remote...Manual @@ -41,7 +39,7 @@ def clear_data(self): def revoke_token(self): self.LOG.info("revoking token") - self.get_server_info()['AccessToken'] = None +# self.get_server_info()['AccessToken'] = None self.credentials.get_credentials(self.credentials.get_credentials()) self.EmbyServer.Data['auth.token'] = None @@ -61,12 +59,6 @@ def get_available_servers(self): self._merge_servers(servers, found_servers) self._merge_servers(servers, connect_servers) servers = self._filter_servers(servers, connect_servers) - -# try: -# servers.sort(key=lambda x: datetime.datetime.strptime(x['DateLastAccessed'], "%Y-%m-%dT%H:%M:%SZ"), reverse=True) -# except TypeError: -# servers.sort(key=lambda x: datetime.datetime(*(time.strptime(x['DateLastAccessed'], "%Y-%m-%dT%H:%M:%SZ")[0:6])), reverse=True) - credentials['Servers'] = servers self.credentials.get_credentials(credentials) return servers @@ -98,15 +90,12 @@ def login_to_connect(self, username, password): self.credentials.get_credentials(credentials) # Signed in self._on_connect_user_signin(result['User']) - return result def login(self, server, username, password, clear, options): if not username: - return False #"username cannot be empty" - - if not password: - return False #"password cannot be empty" + self.LOG.error("username cannot be empty") + return False request = { 'type': "POST", @@ -188,13 +177,15 @@ def _request_url(self, request, headers, MSGs): if headers: self._get_headers(request) - return self.http.request(request, MSGs) + return self.EmbyServer.http.request(request, MSGs) def _get_headers(self, request): headers = request.setdefault('headers', {}) if request.get('dataType') == "json": headers['Accept'] = "application/json" + headers['Accept-Charset'] = "UTF-8,*" + headers['Accept-encoding'] = "gzip" request.pop('dataType') headers['X-Application'] = "%s/%s" % (self.EmbyServer.Data['app.name'], self.EmbyServer.Data['app.version']) @@ -351,7 +342,6 @@ def _get_connect_servers(self, credentials): if not result: return [] - for server in result: servers.append({ 'ExchangeToken': server['AccessKey'], @@ -371,11 +361,6 @@ def _get_last_used_server(self): if not len(servers): return -# try: -# servers.sort(key=lambda x: datetime.datetime.strptime(x['DateLastAccessed'], "%Y-%m-%dT%H:%M:%SZ"), reverse=True) -# except TypeError: -# servers.sort(key=lambda x: datetime.datetime(*(time.strptime(x['DateLastAccessed'], "%Y-%m-%dT%H:%M:%SZ")[0:6])), reverse=True) - return servers[0] def _merge_servers(self, list1, list2): @@ -463,12 +448,14 @@ def _save_user_info_into_credentials(self, server, user): def _add_authentication_info_from_connect(self, server, connection_mode, credentials, options): if not server.get('ExchangeToken'): - return False #"server['ExchangeToken'] cannot be null" + self.LOG.error('server ExchangeToken cannot be null') + return False if not credentials.get('ConnectUserId'): - return False #"credentials['ConnectUserId'] cannot be null" + self.LOG.error('credentials ConnectUserId cannot be null') + return False - auth = "MediaBrowser " + auth = "Emby " auth += "Client=%s, " % self.EmbyServer.Data['app.name'] auth += "Device=%s, " % self.EmbyServer.Data['app.device_name'] auth += "DeviceId=%s, " % self.EmbyServer.Data['app.device_id'] @@ -482,8 +469,8 @@ def _add_authentication_info_from_connect(self, server, connection_mode, credent 'ConnectUserId': credentials['ConnectUserId'] }, 'headers': { - 'X-MediaBrowser-Token': server['ExchangeToken'], - 'X-Emby-Authorization': auth + 'X-Emby-Token': server['ExchangeToken'], + 'Authorization': auth } }, True, False) @@ -535,7 +522,7 @@ def _validate_authentication(self, server, connection_mode, options): 'verify': options.get('ssl'), 'dataType': "json", 'headers': { - 'X-MediaBrowser-Token': server['AccessToken'] + 'X-Emby-Token': server['AccessToken'] } }, True, False) diff --git a/emby/core/http.py b/emby/core/http.py index 4da7259e2..ecbe1780d 100644 --- a/emby/core/http.py +++ b/emby/core/http.py @@ -26,6 +26,7 @@ def stop_session(self): try: self.LOG.warning("--<[ session/%s ]" % id(self.session)) self.session.close() + self.session = None except Exception as error: self.LOG.warning("The requests session could not be terminated: %s" % error) @@ -156,11 +157,7 @@ def _request(self, data): if 'url' not in data: data['url'] = "%s/emby/%s" % (self.EmbyServer.Data['auth.server'], data.pop('handler', "")) - Ret = self._get_header(data) - - if not Ret: - return False - + self.get_header(data) data['timeout'] = data.get('timeout') or self.EmbyServer.Data['http.timeout'] data['url'] = self._replace_user_info(data['url']) @@ -187,7 +184,7 @@ def _process_params(self, params): if isinstance(value, (str, unicode)): params[key] = self._replace_user_info(value) - def _get_header(self, data): + def get_header(self, data): data['headers'] = data.setdefault('headers', {}) if not data['headers']: @@ -199,8 +196,9 @@ def _get_header(self, data): }) if 'Authorization' not in data['headers']: - if not self._authorization(data): - return False + self._authorization(data) +# if not self._authorization(data): +# return False return data @@ -208,7 +206,7 @@ def _authorization(self, data): if not self.EmbyServer.Data['app.device_name']: return False #Device name cannot be null - auth = "MediaBrowser " + auth = "Emby " auth += "Client=%s, " % self.EmbyServer.Data['app.name'] auth += "Device=%s, " % self.EmbyServer.Data['app.device_name'] auth += "DeviceId=%s, " % self.EmbyServer.Data['app.device_id'] @@ -217,7 +215,7 @@ def _authorization(self, data): if self.EmbyServer.Data['auth.token'] and self.EmbyServer.Data['auth.user_id']: auth += ', UserId=%s' % self.EmbyServer.Data['auth.user_id'] - data['headers'].update({'Authorization': auth, 'X-MediaBrowser-Token': self.EmbyServer.Data['auth.token']}) + data['headers'].update({'Authorization': auth, 'X-Emby-Token': self.EmbyServer.Data['auth.token']}) return data diff --git a/emby/core/ws_client.py b/emby/core/ws_client.py index 88351de26..edc74871a 100644 --- a/emby/core/ws_client.py +++ b/emby/core/ws_client.py @@ -237,10 +237,11 @@ def sendCommands(self, payload, opcode): length = len(data) while data: - l = self.sock.send(data) - data = data[l:] - - return length + try: + l = self.sock.send(data) + data = data[l:] + except: #Offline + break def ping(self): while True: diff --git a/emby/downloader.py b/emby/downloader.py deleted file mode 100644 index 2ff99839f..000000000 --- a/emby/downloader.py +++ /dev/null @@ -1,252 +0,0 @@ -# -*- coding: utf-8 -*- -import helper.loghandler - -class Downloader(): - def __init__(self, Utils, EmbyServer): - self.Utils = Utils - self.EmbyServer = EmbyServer - self.LOG = helper.loghandler.LOG('EMBY.emby.downloader.Downloader') - self.LIMIT = min(int(self.Utils.settings('limitIndex') or 15), 50) - self.info = ("Path,Genres,SortName,Studios,Writer,Taglines,LocalTrailerCount,Video3DFormat,OfficialRating,CumulativeRunTimeTicks,ItemCounts,PremiereDate,ProductionYear,Metascore,AirTime,DateCreated,People,Overview,CommunityRating,StartDate,CriticRating,CriticRatingSummary,Etag,ShortOverview,ProductionLocations,Tags,ProviderIds,ParentId,RemoteTrailers,SpecialEpisodeNumbers,Status,EndDate,MediaSources,VoteCount,RecursiveItemCount,PrimaryImageAspectRatio,DisplayOrder,PresentationUniqueKey,OriginalTitle,MediaSources,AlternateMediaSources,PartCount") - self.browse_info = ("DateCreated,EpisodeCount,SeasonCount,Path,Genres,Studios,Taglines,MediaStreams,Overview,Etag,ProductionLocations,Width,Height,RecursiveItemCount,ChildCount") - - def get_embyserver_url(self, handler): - if handler.startswith('/'): - handler = handler[1:] - self.LOG.warning("handler starts with /: %s" % handler) - - return "{server}/emby/%s" % handler - - def _http(self, action, url, request): - request.update({'url': url, 'type': action}) - return self.EmbyServer.http.request(request) - - def _get(self, handler, params): - return self._http("GET", self.get_embyserver_url(handler), {'params': params}) - - def _post(self, handler, json, params): - return self._http("POST", self.get_embyserver_url(handler), {'params': params, 'json': json}) - - def _delete(self, handler, params): - return self._http("DELETE", self.get_embyserver_url(handler), {'params': params}) - - #This confirms a single item from the library matches the view it belongs to. - #Used to detect grouped libraries. - def validate_view(self, library_id, item_id): - try: - result = self._get("Users/{UserId}/Items", {'ParentId': library_id, 'Recursive': True, 'Ids': item_id}) - except Exception: - return False - - return bool(len(result['Items'])) - - #Get dynamic listings - def get_filtered_section(self, parent_id, media, limit, recursive, sort, sort_order, filters, extra, NoSort): - if NoSort: - params = { - 'ParentId': parent_id, - 'IncludeItemTypes': media, - 'IsMissing': False, - 'Recursive': recursive if recursive is not None else True, - 'Limit': limit, - 'ImageTypeLimit': 1, - 'IsVirtualUnaired': False, - 'Fields': self.browse_info - } - else: - params = { - 'ParentId': parent_id, - 'IncludeItemTypes': media, - 'IsMissing': False, - 'Recursive': recursive if recursive is not None else True, - 'Limit': limit, - 'SortBy': sort or "SortName", - 'SortOrder': sort_order or "Ascending", - 'ImageTypeLimit': 1, - 'IsVirtualUnaired': False, - 'Fields': self.browse_info - } - - if filters: - if 'Boxsets' in filters: - filters.remove('Boxsets') - params['CollapseBoxSetItems'] = self.Utils.settings('groupedSets.bool') - - params['Filters'] = ','.join(filters) - - if self.Utils.settings('getCast.bool'): - params['Fields'] += ",People" - - if media and 'Photo' in media: - params['Fields'] += ",Width,Height" - - if extra is not None: - params.update(extra) - - return self._get("Users/{UserId}/Items", params) - - def get_movies_by_boxset(self, boxset_id): - for items in self.get_items(boxset_id, "Movie", False, None): - yield items - - def get_episode_by_show(self, show_id): - query = { - 'url': "Shows/%s/Episodes" % show_id, - 'params': { - 'EnableUserData': True, - 'EnableImages': True, - 'UserId': "{UserId}", - 'Fields': self.info - } - } - - for items in self._get_items(query, self.LIMIT): - yield items - - def get_episode_by_season(self, show_id, season_id): - query = { - 'url': "Shows/%s/Episodes" % show_id, - 'params': { - 'SeasonId': season_id, - 'EnableUserData': True, - 'EnableImages': True, - 'UserId': "{UserId}", - 'Fields': self.info - } - } - - for items in self._get_items(query, self.LIMIT): - yield items - - def get_items(self, parent_id, item_type, basic, params): - query = { - 'url': "Users/{UserId}/Items", - 'params': { - 'ParentId': parent_id, - 'IncludeItemTypes': item_type, - 'Fields': "Etag,PresentationUniqueKey" if basic else self.info, - 'SortOrder': "Ascending", - 'SortBy': "SortName", - 'CollapseBoxSetItems': False, - 'IsVirtualUnaired': False, - 'EnableTotalRecordCount': False, - 'LocationTypes': "FileSystem,Remote,Offline", - 'IsMissing': False, - 'Recursive': True - } - } - - if params: - query['params'].update(params) - - for items in self._get_items(query, self.LIMIT): - yield items - - def get_artists(self, parent_id, basic, params): - music_info = ( - "Etag,Genres,SortName,Studios,Writer,PremiereDate,ProductionYear," - "OfficialRating,CumulativeRunTimeTicks,Metascore,CommunityRating," - "AirTime,DateCreated,MediaStreams,People,ProviderIds,Overview,ItemCounts," - "PresentationUniqueKey" - ) - query = { - 'url': "Artists", - 'params': { - 'UserId': "{UserId}", - 'ParentId': parent_id, - 'SortBy': "SortName", - 'SortOrder': "Ascending", - 'Fields': "Etag,PresentationUniqueKey" if basic else music_info, - 'CollapseBoxSetItems': False, - 'IsVirtualUnaired': False, - 'EnableTotalRecordCount': False, - 'LocationTypes': "FileSystem,Remote,Offline", - 'IsMissing': False, - 'Recursive': True - } - } - - if params: - query['params'].update(params) - - for items in self._get_items(query, self.LIMIT): - yield items - - def get_albums_by_artist(self, parent_id, artist_id, basic): - params = { - 'SortBy': "DateCreated", - 'ParentId': parent_id, - 'ArtistIds': artist_id - } #fixme: test -> remove sortby, but check impact on dynamic lists - - for items in self.get_items(None, "MusicAlbum", basic, params): - yield items - - def get_songs_by_artist(self, parent_id, artist_id, basic): - params = { - 'SortBy': "DateCreated", - 'ParentId': parent_id, - 'ArtistIds': artist_id - } #fixme: test -> remove sortby, but check impact on dynamic lists - - for items in self.get_items(None, "Audio", basic, params): - yield items - - def get_TotalRecordsRegular(self, parent_id, item_type): - Params = { - 'ParentId': parent_id, - 'IncludeItemTypes': item_type, - 'CollapseBoxSetItems': False, - 'IsVirtualUnaired': False, - 'IsMissing': False, - 'EnableTotalRecordCount': True, - 'LocationTypes': "FileSystem,Remote,Offline", - 'Recursive': True, - 'Limit': 1 - } - - return self._get("Users/{UserId}/Items", Params)['TotalRecordCount'] - - def get_TotalRecordsArtists(self, parent_id): - Params = { - 'UserId': "{UserId}", - 'ParentId': parent_id, - 'CollapseBoxSetItems': False, - 'IsVirtualUnaired': False, - 'IsMissing': False, - 'EnableTotalRecordCount': True, - 'LocationTypes': "FileSystem,Remote,Offline", - 'Recursive': True, - 'Limit': 1 - } - return self._get("Artists", Params)['TotalRecordCount'] - - def _get_items(self, query, LIMIT): - items = { - 'Items': [], - 'RestorePoint': {} - } - - url = query['url'] - params = query.get('params', {}) - index = params.get('StartIndex', 0) - - while True: - params['StartIndex'] = index - params['Limit'] = LIMIT - - try: - result = self._get(url, params) or {'Items': []} - except Exception as error: - self.LOG.error("ERROR: %s" % error) - result = {'Items': []} - - if result['Items'] == []: - items['TotalRecordCount'] = index - break - - items['Items'].extend(result['Items']) - items['RestorePoint'] = query - yield items - del items['Items'][:] - index += LIMIT diff --git a/emby/main.py b/emby/main.py index 0d12e0a68..3e26c2e64 100644 --- a/emby/main.py +++ b/emby/main.py @@ -6,32 +6,29 @@ from .core import connection_manager class Emby(): - def __init__(self, server_id=None): + def __init__(self, Utils, server_id=None): self.LOG = helper.loghandler.LOG('EMBY.emby.main') self.logged_in = False - self.server_id = server_id self.wsock = None self.http = http.HTTP(self) self.auth = connection_manager.ConnectionManager(self) + self.server_id = server_id + self.Utils = Utils self.API = api.API(self) - self.Data = {'http.user_agent': None, 'http.timeout': 30, 'http.max_retries': 3, 'auth.server': None, 'auth.user_id': None, 'auth.token': None, 'auth.ssl': None, 'app.name': None, 'app.version': None, 'app.device_name': None, 'app.device_id': None, 'app.capabilities': None, 'app.session': None} - self.LOG.info("---[ START EMBYCLIENT: ]---") - - def set_state(self, state): - if not state: - self.LOG.warning("state cannot be empty") - return - - if state.get('config'): - self.Data = state['config'] + self.Data = {'http.user_agent': None, 'http.timeout': 30, 'http.max_retries': 3, 'auth.server': None, 'auth.user_id': None, 'auth.token': None, 'auth.ssl': None, 'app.name': None, 'app.version': None, 'app.device_name': None, 'app.device_id': self.Utils.get_device_id(False), 'app.capabilities': None} + self.LOG.info("---[ INIT EMBYCLIENT: ]---") - if state.get('credentials'): - self.logged_in = True - self.auth.credentials.set_credentials(state['credentials'] or {}) - self.auth.server_id = state['credentials']['Servers'][0]['Id'] + def set_state(self): + state = self.Utils.window('emby.server.%s.state.json' % self.server_id) + self.Data = state['config'] + self.logged_in = True + self.auth.credentials.set_credentials(state['credentials'] or {}) + self.server_id = state['credentials']['Servers'][0]['Id'] + self.LOG.info("---[ SET EMBYCLIENT: %s ]---" % self.server_id) - def get_state(self): - return {'config': self.Data, 'credentials': self.auth.credentials.get_credentials()} + def save_state(self): + self.Utils.window('emby.server.%s.state.json' % self.server_id, {'config': self.Data, 'credentials': self.auth.credentials.get_credentials()}) + self.Utils.window('emby.servers.json', {self.server_id : 'online'}) def authenticate(self, credentials, options): self.auth.credentials.set_credentials(credentials or {}) @@ -49,14 +46,57 @@ def authenticate(self, credentials, options): def start(self): if not self.logged_in: + self.LOG.error("User is not logged in.") return False #"User is not authenticated." + self.LOG.info("---[ START EMBYCLIENT: %s ]---" % self.server_id) self.http.start_session() + self.API.post_capabilities({ + 'PlayableMediaTypes': "Audio,Video", + 'SupportsMediaControl': True, + 'SupportedCommands': ( + "MoveUp,MoveDown,MoveLeft,MoveRight,Select," + "Back,ToggleContextMenu,ToggleFullscreen,ToggleOsdMenu," + "GoHome,PageUp,NextLetter,GoToSearch," + "GoToSettings,PageDown,PreviousLetter,TakeScreenshot," + "VolumeUp,VolumeDown,ToggleMute,SendString,DisplayMessage," + "SetAudioStreamIndex,SetSubtitleStreamIndex," + "SetRepeatMode," + "Mute,Unmute,SetVolume," + "Play,Playstate,PlayNext,PlayMediaSource" + ), + 'IconUrl': "https://raw.githubusercontent.com/MediaBrowser/plugin.video.emby/master/kodi_icon.png" + }) + + if self.Utils.settings('addUsers'): + session = self.API.get_device() + users = self.Utils.settings('addUsers').split(',') + hidden = None if self.Utils.settings('addUsersHidden.bool') else False + all_users = self.API.get_users(False, hidden) + + for additional in users: + for user in all_users: + if user['Id'] == additional: + self.API.session_add_user(session[0]['Id'], user['Id'], True) + + #add additional users + for i in range(10): + self.Utils.window('emby.AdditionalUserImage.%s' % i, clear=True) + + for index, user in enumerate(session[0]['AdditionalUsers']): + info = self.API.get_user(user['UserId']) + image = self.API.get_user_artwork(user['UserId']) + self.Utils.window('emby.AdditionalUserImage.%s' % index, image) + self.Utils.window('emby.AdditionalUserPosition.%s' % user['UserId'], str(index)) + + self.save_state() + + #Websocket self.wsock = ws_client.WSClient(self.Data['auth.server'], self.Data['app.device_id'], self.Data['auth.token'], self.server_id) self.wsock.start() def stop(self): - self.LOG.info("---[ STOPPED EMBYCLIENT: %s ]---" % self.server_id) + self.LOG.info("---[ STOP EMBYCLIENT: %s ]---" % self.server_id) self.wsock.close() self.wsock = None self.http.stop_session() diff --git a/emby/views.py b/emby/views.py index 20ac50ab4..4e87809e1 100644 --- a/emby/views.py +++ b/emby/views.py @@ -15,27 +15,27 @@ import helper.loghandler class Views(): - def __init__(self, Library): + def __init__(self, Embyserver): + self.EmbyServer = Embyserver self.limit = 25 self.media_folders = None - self.Library = Library - self.SyncData = self.Library.Monitor.Service.Utils.get_sync() self.LOG = helper.loghandler.LOG('EMBY.emby.views.Views') + self.APIHelper = helper.api.API(self.EmbyServer.Utils, self.EmbyServer.Data['auth.ssl']) self.NODES = { 'tvshows': [ ('alphabet', None), ('all', None), - ('recent', self.Library.Monitor.Service.Utils.Translate(30170)), - ('recentepisodes', self.Library.Monitor.Service.Utils.Translate(30175)), - ('inprogress', self.Library.Monitor.Service.Utils.Translate(30171)), - ('inprogressepisodes', self.Library.Monitor.Service.Utils.Translate(30178)), - ('nextepisodes', self.Library.Monitor.Service.Utils.Translate(30179)), + ('recent', self.EmbyServer.Utils.Translate(30170)), + ('recentepisodes', self.EmbyServer.Utils.Translate(30175)), + ('inprogress', self.EmbyServer.Utils.Translate(30171)), + ('inprogressepisodes', self.EmbyServer.Utils.Translate(30178)), + ('nextepisodes', self.EmbyServer.Utils.Translate(30179)), ('genres', 135), - ('random', self.Library.Monitor.Service.Utils.Translate(30229)), - ('recommended', self.Library.Monitor.Service.Utils.Translate(30230)), - ('years', self.Library.Monitor.Service.Utils.Translate(33218)), - ('actors', self.Library.Monitor.Service.Utils.Translate(33219)), - ('tags', self.Library.Monitor.Service.Utils.Translate(33220)), + ('random', self.EmbyServer.Utils.Translate(30229)), + ('recommended', self.EmbyServer.Utils.Translate(30230)), + ('years', self.EmbyServer.Utils.Translate(33218)), + ('actors', self.EmbyServer.Utils.Translate(33219)), + ('tags', self.EmbyServer.Utils.Translate(33220)), ('unwatched', "Unwatched TV Shows"), ('unwatchedepisodes', "Unwatched Episodes"), ('studios', "Studios"), @@ -46,16 +46,16 @@ def __init__(self, Library): 'movies': [ ('alphabet', None), ('all', None), - ('recent', self.Library.Monitor.Service.Utils.Translate(30174)), - ('inprogress', self.Library.Monitor.Service.Utils.Translate(30177)), - ('unwatched', self.Library.Monitor.Service.Utils.Translate(30189)), + ('recent', self.EmbyServer.Utils.Translate(30174)), + ('inprogress', self.EmbyServer.Utils.Translate(30177)), + ('unwatched', self.EmbyServer.Utils.Translate(30189)), ('sets', 20434), ('genres', 135), - ('random', self.Library.Monitor.Service.Utils.Translate(30229)), - ('recommended', self.Library.Monitor.Service.Utils.Translate(30230)), - ('years', self.Library.Monitor.Service.Utils.Translate(33218)), - ('actors', self.Library.Monitor.Service.Utils.Translate(33219)), - ('tags', self.Library.Monitor.Service.Utils.Translate(33220)), + ('random', self.EmbyServer.Utils.Translate(30229)), + ('recommended', self.EmbyServer.Utils.Translate(30230)), + ('years', self.EmbyServer.Utils.Translate(33218)), + ('actors', self.EmbyServer.Utils.Translate(33219)), + ('tags', self.EmbyServer.Utils.Translate(33220)), ('studios', "Studios"), ('recentplayed', 'Recently played'), ('directors', 'Directors'), @@ -64,19 +64,19 @@ def __init__(self, Library): 'musicvideos': [ ('alphabet', None), ('all', None), - ('recent', self.Library.Monitor.Service.Utils.Translate(30256)), - ('years', self.Library.Monitor.Service.Utils.Translate(33218)), + ('recent', self.EmbyServer.Utils.Translate(30256)), + ('years', self.EmbyServer.Utils.Translate(33218)), ('genres', 135), - ('inprogress', self.Library.Monitor.Service.Utils.Translate(30257)), - ('random', self.Library.Monitor.Service.Utils.Translate(30229)), - ('unwatched', self.Library.Monitor.Service.Utils.Translate(30258)), + ('inprogress', self.EmbyServer.Utils.Translate(30257)), + ('random', self.EmbyServer.Utils.Translate(30229)), + ('unwatched', self.EmbyServer.Utils.Translate(30258)), ('artists', "Artists"), ('albums', "Albums"), ('recentplayed', 'Recently played') ], 'music': [ ('alphabet', None), - ('years', self.Library.Monitor.Service.Utils.Translate(33218)), + ('years', self.EmbyServer.Utils.Translate(33218)), ('genres', 135), ('artists', "Artists"), ('albums', "Albums"), @@ -141,11 +141,11 @@ def node_recentaddedalbums(self, root): #Make sure we have the kodi default folder in place def verify_kodi_defaults(self): - node_path = self.Library.Monitor.Service.Utils.translatePath("special://profile/library/video") + node_path = self.EmbyServer.Utils.translatePath("special://profile/library/video") if not xbmcvfs.exists(node_path): try: - shutil.copytree(src=self.Library.Monitor.Service.Utils.translatePath("special://xbmc/system/library/video"), dst=self.Library.Monitor.Service.Utils.translatePath("special://profile/library/video")) + shutil.copytree(src=self.EmbyServer.Utils.translatePath("special://xbmc/system/library/video"), dst=self.EmbyServer.Utils.translatePath("special://profile/library/video")) except Exception as error: xbmcvfs.mkdir(node_path) @@ -160,22 +160,22 @@ def verify_kodi_defaults(self): continue xmlData.set('order', str(17 + index)) - self.Library.Monitor.Service.Utils.indent(xmlData, 0) - self.Library.Monitor.Service.Utils.write_xml(xml.etree.ElementTree.tostring(xmlData, 'UTF-8'), filename) + self.EmbyServer.Utils.indent(xmlData, 0) + self.EmbyServer.Utils.write_xml(xml.etree.ElementTree.tostring(xmlData, 'UTF-8'), filename) - playlist_path = self.Library.Monitor.Service.Utils.translatePath("special://profile/playlists/video") + playlist_path = self.EmbyServer.Utils.translatePath("special://profile/playlists/video") if not xbmcvfs.exists(playlist_path): xbmcvfs.mkdirs(playlist_path) #Add entry to view table in emby database def add_library(self, view): - with database.database.Database(self.Library.Monitor.Service.Utils, 'emby', True) as embydb: + with database.database.Database(self.EmbyServer.Utils, 'emby', True) as embydb: database.emby_db.EmbyDatabase(embydb.cursor).add_view(view['Id'], view['Name'], view['Media']) #Remove entry from view table in emby database def remove_library(self, view_id): - with database.database.Database(self.Library.Monitor.Service.Utils, 'emby', True) as embydb: + with database.database.Database(self.EmbyServer.Utils, 'emby', True) as embydb: database.emby_db.EmbyDatabase(embydb.cursor).remove_view(view_id) self.delete_playlist_by_id(view_id) @@ -183,11 +183,11 @@ def remove_library(self, view_id): def get_libraries(self): try: - if not self.Library.Monitor.EmbyServer[self.Library.server_id].logged_in: + if not self.EmbyServer.logged_in: return False - libraries = self.Library.Monitor.EmbyServer[self.Library.server_id].API.get_media_folders()['Items'] - views = self.Library.Monitor.EmbyServer[self.Library.server_id].API.get_views()['Items'] + libraries = self.EmbyServer.API.get_media_folders()['Items'] + views = self.EmbyServer.API.get_views()['Items'] except: return False @@ -202,7 +202,7 @@ def get_views(self): self.LOG.error("Unable to retrieve libraries") return - self.SyncData['SortedViews'] = [x['Id'] for x in libraries] + self.EmbyServer.Utils.SyncData['SortedViews'] = [x['Id'] for x in libraries] for library in libraries: if library['Type'] == 'Channel': @@ -212,10 +212,10 @@ def get_views(self): self.add_library(library) - with database.database.Database(self.Library.Monitor.Service.Utils, 'emby', True) as embydb: + with database.database.Database(self.EmbyServer.Utils, 'emby', True) as embydb: views = database.emby_db.EmbyDatabase(embydb.cursor).get_views() - sorted_views = self.SyncData['SortedViews'] - whitelist = self.SyncData['Whitelist'] + sorted_views = self.EmbyServer.Utils.SyncData['SortedViews'] + whitelist = self.EmbyServer.Utils.SyncData['Whitelist'] removed = [] for view in views: @@ -223,7 +223,7 @@ def get_views(self): removed.append(view[0]) if removed: - self.Library.Monitor.Service.Utils.event('RemoveLibrary', {'Id': ','.join(removed)}) + self.EmbyServer.Utils.event('RemoveLibrary', {'Id': ','.join(removed)}) for library_id in removed: if library_id in sorted_views: @@ -232,16 +232,16 @@ def get_views(self): if library_id in whitelist: whitelist.remove(library_id) - self.Library.Monitor.Service.Utils.save_sync(self.SyncData) + self.EmbyServer.Utils.save_sync(self.EmbyServer.Utils.SyncData) #Set up playlists, video nodes, window prop def get_nodes(self): index = 0 - with database.database.Database(self.Library.Monitor.Service.Utils, 'emby', True) as embydb: + with database.database.Database(self.EmbyServer.Utils, 'emby', True) as embydb: db = database.emby_db.EmbyDatabase(embydb.cursor) - for library in self.SyncData['Whitelist']: + for library in self.EmbyServer.Utils.SyncData['Whitelist']: library = library.replace('Mixed:', "") view = db.get_view(library) @@ -249,11 +249,11 @@ def get_nodes(self): view = {'Id': library, 'Name': view[0], 'Tag': view[0], 'Media': view[1]} if view['Media'] == 'music': - node_path = self.Library.Monitor.Service.Utils.translatePath("special://profile/library/music") - playlist_path = self.Library.Monitor.Service.Utils.translatePath("special://profile/playlists/music") + node_path = self.EmbyServer.Utils.translatePath("special://profile/library/music") + playlist_path = self.EmbyServer.Utils.translatePath("special://profile/playlists/music") else: - node_path = self.Library.Monitor.Service.Utils.translatePath("special://profile/library/video") - playlist_path = self.Library.Monitor.Service.Utils.translatePath("special://profile/playlists/video") + node_path = self.EmbyServer.Utils.translatePath("special://profile/library/video") + playlist_path = self.EmbyServer.Utils.translatePath("special://profile/playlists/video") if view['Media'] == 'mixed': for media in ('movies', 'tvshows'): @@ -271,10 +271,10 @@ def get_nodes(self): index += 1 - node_path = self.Library.Monitor.Service.Utils.translatePath("special://profile/library/video") - playlist_path = self.Library.Monitor.Service.Utils.translatePath("special://profile/playlists/video") + node_path = self.EmbyServer.Utils.translatePath("special://profile/library/video") + playlist_path = self.EmbyServer.Utils.translatePath("special://profile/playlists/video") - for single in [{'Name': self.Library.Monitor.Service.Utils.Translate('fav_movies'), 'Tag': "Favorite movies", 'Media': "movies"}, {'Name': self.Library.Monitor.Service.Utils.Translate('fav_tvshows'), 'Tag': "Favorite tvshows", 'Media': "tvshows"}, {'Name': self.Library.Monitor.Service.Utils.Translate('fav_episodes'), 'Tag': "Favorite episodes", 'Media': "episodes"}]: + for single in [{'Name': self.EmbyServer.Utils.Translate('fav_movies'), 'Tag': "Favorite movies", 'Media': "movies"}, {'Name': self.EmbyServer.Utils.Translate('fav_tvshows'), 'Tag': "Favorite tvshows", 'Media': "tvshows"}, {'Name': self.EmbyServer.Utils.Translate('fav_episodes'), 'Tag': "Favorite episodes", 'Media': "episodes"}]: self.add_single_node(node_path, index, "favorites", single) index += 1 @@ -303,8 +303,8 @@ def add_playlist(self, path, view, mixed): rule = xml.etree.ElementTree.SubElement(xmlData, 'rule', {'field': "tag", 'operator': "is"}) xml.etree.ElementTree.SubElement(rule, 'value').text = view['Tag'] - self.Library.Monitor.Service.Utils.indent(xmlData, 0) - self.Library.Monitor.Service.Utils.write_xml(xml.etree.ElementTree.tostring(xmlData, 'UTF-8'), filepath) + self.EmbyServer.Utils.indent(xmlData, 0) + self.EmbyServer.Utils.write_xml(xml.etree.ElementTree.tostring(xmlData, 'UTF-8'), filepath) #Create or update the video node file def add_nodes(self, path, view, mixed): @@ -352,8 +352,8 @@ def add_single_node(self, path, index, item_type, view): else: self.node_all(xmlData) - self.Library.Monitor.Service.Utils.indent(xmlData, 0) - self.Library.Monitor.Service.Utils.write_xml(xml.etree.ElementTree.tostring(xmlData, 'UTF-8'), filepath) + self.EmbyServer.Utils.indent(xmlData, 0) + self.EmbyServer.Utils.write_xml(xml.etree.ElementTree.tostring(xmlData, 'UTF-8'), filepath) #Create the root element def node_root(self, root, index): @@ -369,7 +369,7 @@ def node_root(self, root, index): def node_index(self, folder, view, mixed): filepath = os.path.join(folder, "index.xml") - index = self.SyncData['SortedViews'].index(view['Id']) + index = self.EmbyServer.Utils.SyncData['SortedViews'].index(view['Id']) try: xmlData = xml.etree.ElementTree.parse(filepath).getroot() @@ -379,9 +379,9 @@ def node_index(self, folder, view, mixed): xml.etree.ElementTree.SubElement(xmlData, 'label') label = xmlData.find('label') - label.text = view['Name'] if not mixed else "%s (%s)" % (view['Name'], self.Library.Monitor.Service.Utils.Translate(view['Media'])) - self.Library.Monitor.Service.Utils.indent(xmlData, 0) - self.Library.Monitor.Service.Utils.write_xml(xml.etree.ElementTree.tostring(xmlData, 'UTF-8'), filepath) + label.text = view['Name'] if not mixed else "%s (%s)" % (view['Name'], self.EmbyServer.Utils.Translate(view['Media'])) + self.EmbyServer.Utils.indent(xmlData, 0) + self.EmbyServer.Utils.write_xml(xml.etree.ElementTree.tostring(xmlData, 'UTF-8'), filepath) def node(self, folder, view): for node in self.NODES[view['Media']]: @@ -413,8 +413,8 @@ def node_alphabet(self, FolderPath, View, SortObject, Content): xmlData.set('type', "folder") xmlLabel = xml.etree.ElementTree.SubElement(xmlData, "label").text = "Alphabet" xmlIcon = xml.etree.ElementTree.SubElement(xmlData, 'icon').text = "special://home/addons/plugin.video.emby-next-gen/resources/icon.png" - self.Library.Monitor.Service.Utils.indent(xmlData, 0) - self.Library.Monitor.Service.Utils.write_xml(xml.etree.ElementTree.tostring(xmlData, 'UTF-8'), FileName) + self.EmbyServer.Utils.indent(xmlData, 0) + self.EmbyServer.Utils.write_xml(xml.etree.ElementTree.tostring(xmlData, 'UTF-8'), FileName) Counter = 1 FileName = os.path.join(FolderPath, "0-9.xml") @@ -454,36 +454,36 @@ def node_alphabet(self, FolderPath, View, SortObject, Content): xml.etree.ElementTree.SubElement(xmlRule, "value").text = "7" xml.etree.ElementTree.SubElement(xmlRule, "value").text = "8" xml.etree.ElementTree.SubElement(xmlRule, "value").text = "9" - xml.etree.ElementTree.SubElement(xmlRule, "value").text = self.Library.Monitor.Service.Utils.StringDecode("&") - xml.etree.ElementTree.SubElement(xmlRule, "value").text = self.Library.Monitor.Service.Utils.StringDecode("Ä") - xml.etree.ElementTree.SubElement(xmlRule, "value").text = self.Library.Monitor.Service.Utils.StringDecode("Ö") - xml.etree.ElementTree.SubElement(xmlRule, "value").text = self.Library.Monitor.Service.Utils.StringDecode("Ü") - xml.etree.ElementTree.SubElement(xmlRule, "value").text = self.Library.Monitor.Service.Utils.StringDecode("!") - xml.etree.ElementTree.SubElement(xmlRule, "value").text = self.Library.Monitor.Service.Utils.StringDecode("(") - xml.etree.ElementTree.SubElement(xmlRule, "value").text = self.Library.Monitor.Service.Utils.StringDecode(")") - xml.etree.ElementTree.SubElement(xmlRule, "value").text = self.Library.Monitor.Service.Utils.StringDecode("@") - xml.etree.ElementTree.SubElement(xmlRule, "value").text = self.Library.Monitor.Service.Utils.StringDecode("#") - xml.etree.ElementTree.SubElement(xmlRule, "value").text = self.Library.Monitor.Service.Utils.StringDecode("$") - xml.etree.ElementTree.SubElement(xmlRule, "value").text = self.Library.Monitor.Service.Utils.StringDecode("^") - xml.etree.ElementTree.SubElement(xmlRule, "value").text = self.Library.Monitor.Service.Utils.StringDecode("*") - xml.etree.ElementTree.SubElement(xmlRule, "value").text = self.Library.Monitor.Service.Utils.StringDecode("-") - xml.etree.ElementTree.SubElement(xmlRule, "value").text = self.Library.Monitor.Service.Utils.StringDecode("=") - xml.etree.ElementTree.SubElement(xmlRule, "value").text = self.Library.Monitor.Service.Utils.StringDecode("+") - xml.etree.ElementTree.SubElement(xmlRule, "value").text = self.Library.Monitor.Service.Utils.StringDecode("{") - xml.etree.ElementTree.SubElement(xmlRule, "value").text = self.Library.Monitor.Service.Utils.StringDecode("}") - xml.etree.ElementTree.SubElement(xmlRule, "value").text = self.Library.Monitor.Service.Utils.StringDecode("[") - xml.etree.ElementTree.SubElement(xmlRule, "value").text = self.Library.Monitor.Service.Utils.StringDecode("]") - xml.etree.ElementTree.SubElement(xmlRule, "value").text = self.Library.Monitor.Service.Utils.StringDecode("?") - xml.etree.ElementTree.SubElement(xmlRule, "value").text = self.Library.Monitor.Service.Utils.StringDecode(":") - xml.etree.ElementTree.SubElement(xmlRule, "value").text = self.Library.Monitor.Service.Utils.StringDecode(";") - xml.etree.ElementTree.SubElement(xmlRule, "value").text = self.Library.Monitor.Service.Utils.StringDecode("'") - xml.etree.ElementTree.SubElement(xmlRule, "value").text = self.Library.Monitor.Service.Utils.StringDecode(",") - xml.etree.ElementTree.SubElement(xmlRule, "value").text = self.Library.Monitor.Service.Utils.StringDecode(".") - xml.etree.ElementTree.SubElement(xmlRule, "value").text = self.Library.Monitor.Service.Utils.StringDecode("<") - xml.etree.ElementTree.SubElement(xmlRule, "value").text = self.Library.Monitor.Service.Utils.StringDecode(">") - xml.etree.ElementTree.SubElement(xmlRule, "value").text = self.Library.Monitor.Service.Utils.StringDecode("~") - self.Library.Monitor.Service.Utils.indent(xmlData, 0) - self.Library.Monitor.Service.Utils.write_xml(xml.etree.ElementTree.tostring(xmlData, 'UTF-8'), FileName) + xml.etree.ElementTree.SubElement(xmlRule, "value").text = self.EmbyServer.Utils.StringDecode("&") + xml.etree.ElementTree.SubElement(xmlRule, "value").text = self.EmbyServer.Utils.StringDecode("Ä") + xml.etree.ElementTree.SubElement(xmlRule, "value").text = self.EmbyServer.Utils.StringDecode("Ö") + xml.etree.ElementTree.SubElement(xmlRule, "value").text = self.EmbyServer.Utils.StringDecode("Ü") + xml.etree.ElementTree.SubElement(xmlRule, "value").text = self.EmbyServer.Utils.StringDecode("!") + xml.etree.ElementTree.SubElement(xmlRule, "value").text = self.EmbyServer.Utils.StringDecode("(") + xml.etree.ElementTree.SubElement(xmlRule, "value").text = self.EmbyServer.Utils.StringDecode(")") + xml.etree.ElementTree.SubElement(xmlRule, "value").text = self.EmbyServer.Utils.StringDecode("@") + xml.etree.ElementTree.SubElement(xmlRule, "value").text = self.EmbyServer.Utils.StringDecode("#") + xml.etree.ElementTree.SubElement(xmlRule, "value").text = self.EmbyServer.Utils.StringDecode("$") + xml.etree.ElementTree.SubElement(xmlRule, "value").text = self.EmbyServer.Utils.StringDecode("^") + xml.etree.ElementTree.SubElement(xmlRule, "value").text = self.EmbyServer.Utils.StringDecode("*") + xml.etree.ElementTree.SubElement(xmlRule, "value").text = self.EmbyServer.Utils.StringDecode("-") + xml.etree.ElementTree.SubElement(xmlRule, "value").text = self.EmbyServer.Utils.StringDecode("=") + xml.etree.ElementTree.SubElement(xmlRule, "value").text = self.EmbyServer.Utils.StringDecode("+") + xml.etree.ElementTree.SubElement(xmlRule, "value").text = self.EmbyServer.Utils.StringDecode("{") + xml.etree.ElementTree.SubElement(xmlRule, "value").text = self.EmbyServer.Utils.StringDecode("}") + xml.etree.ElementTree.SubElement(xmlRule, "value").text = self.EmbyServer.Utils.StringDecode("[") + xml.etree.ElementTree.SubElement(xmlRule, "value").text = self.EmbyServer.Utils.StringDecode("]") + xml.etree.ElementTree.SubElement(xmlRule, "value").text = self.EmbyServer.Utils.StringDecode("?") + xml.etree.ElementTree.SubElement(xmlRule, "value").text = self.EmbyServer.Utils.StringDecode(":") + xml.etree.ElementTree.SubElement(xmlRule, "value").text = self.EmbyServer.Utils.StringDecode(";") + xml.etree.ElementTree.SubElement(xmlRule, "value").text = self.EmbyServer.Utils.StringDecode("'") + xml.etree.ElementTree.SubElement(xmlRule, "value").text = self.EmbyServer.Utils.StringDecode(",") + xml.etree.ElementTree.SubElement(xmlRule, "value").text = self.EmbyServer.Utils.StringDecode(".") + xml.etree.ElementTree.SubElement(xmlRule, "value").text = self.EmbyServer.Utils.StringDecode("<") + xml.etree.ElementTree.SubElement(xmlRule, "value").text = self.EmbyServer.Utils.StringDecode(">") + xml.etree.ElementTree.SubElement(xmlRule, "value").text = self.EmbyServer.Utils.StringDecode("~") + self.EmbyServer.Utils.indent(xmlData, 0) + self.EmbyServer.Utils.write_xml(xml.etree.ElementTree.tostring(xmlData, 'UTF-8'), FileName) FileNames = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"] for FileID in FileNames: @@ -512,8 +512,8 @@ def node_alphabet(self, FolderPath, View, SortObject, Content): xmlRule.text = FileID xmlRule.set('field', SortObject) xmlRule.set('operator', "startswith") - self.Library.Monitor.Service.Utils.indent(xmlData, 0) - self.Library.Monitor.Service.Utils.write_xml(xml.etree.ElementTree.tostring(xmlData, 'UTF-8'), FileName) + self.EmbyServer.Utils.indent(xmlData, 0) + self.EmbyServer.Utils.write_xml(xml.etree.ElementTree.tostring(xmlData, 'UTF-8'), FileName) def node_tvshow(self, folder, view): for node in self.NODES[view['Media']]: @@ -568,8 +568,8 @@ def add_node(self, index, filepath, view, node, name): xml.etree.ElementTree.SubElement(rule, 'value').text = view['Tag'] getattr(self, 'node_' + node)(xmlData) # get node function based on node type - self.Library.Monitor.Service.Utils.indent(xmlData, 0) - self.Library.Monitor.Service.Utils.write_xml(xml.etree.ElementTree.tostring(xmlData, 'UTF-8'), filepath) + self.EmbyServer.Utils.indent(xmlData, 0) + self.EmbyServer.Utils.write_xml(xml.etree.ElementTree.tostring(xmlData, 'UTF-8'), filepath) def add_dynamic_node(self, index, filepath, node, name, path): try: @@ -582,8 +582,8 @@ def add_dynamic_node(self, index, filepath, node, name, path): label = xmlData.find('label') label.text = name getattr(self, 'node_' + node)(xmlData, path) - self.Library.Monitor.Service.Utils.indent(xmlData, 0) - self.Library.Monitor.Service.Utils.write_xml(xml.etree.ElementTree.tostring(xmlData, 'UTF-8'), filepath) + self.EmbyServer.Utils.indent(xmlData, 0) + self.EmbyServer.Utils.write_xml(xml.etree.ElementTree.tostring(xmlData, 'UTF-8'), filepath) def node_all(self, root): for rule in root.findall('.//order'): @@ -900,7 +900,7 @@ def order_media_folders(self, folders): if not folders: return folders - sorted_views = list(self.SyncData['SortedViews']) + sorted_views = list(self.EmbyServer.Utils.SyncData['SortedViews']) unordered = [x[0] for x in folders] grouped = [x for x in unordered if x not in sorted_views] @@ -916,7 +916,7 @@ def window_nodes(self): self.window_clear('Emby.nodes') self.window_clear('Emby.wnodes') - with database.database.Database(self.Library.Monitor.Service.Utils, 'emby', True) as embydb: + with database.database.Database(self.EmbyServer.Utils, 'emby', True) as embydb: libraries = database.emby_db.EmbyDatabase(embydb.cursor).get_views() libraries = self.order_media_folders(libraries or []) @@ -930,7 +930,7 @@ def window_nodes(self): for library in (libraries or []): view = {'Id': library[0], 'Name': library[1], 'Tag': library[1], 'Media': library[2]} - if library[0] in [x.replace('Mixed:', "") for x in self.SyncData['Whitelist']]: # Synced libraries + if library[0] in [x.replace('Mixed:', "") for x in self.EmbyServer.Utils.SyncData['Whitelist']]: # Synced libraries if view['Media'] in ('movies', 'tvshows', 'musicvideos', 'mixed'): if view['Media'] == 'mixed': for media in ('movies', 'tvshows'): @@ -938,7 +938,7 @@ def window_nodes(self): temp_view = dict(view) temp_view['Media'] = media temp_view['CleanName'] = view['Name'] - temp_view['Name'] = "%s (%s)" % (view['Name'], self.Library.Monitor.Service.Utils.Translate(media)) + temp_view['Name'] = "%s (%s)" % (view['Name'], self.EmbyServer.Utils.Translate(media)) self.window_node(index, temp_view, *node) self.window_wnode(windex, temp_view, *node) @@ -966,11 +966,11 @@ def window_nodes(self): index += 1 - for single in [{'Name': self.Library.Monitor.Service.Utils.Translate('fav_movies'), 'Tag': "Favorite movies", 'Media': "movies"}, {'Name': self.Library.Monitor.Service.Utils.Translate('fav_tvshows'), 'Tag': "Favorite tvshows", 'Media': "tvshows"}, {'Name': self.Library.Monitor.Service.Utils.Translate('fav_episodes'), 'Tag': "Favorite episodes", 'Media': "episodes"}]: + for single in [{'Name': self.EmbyServer.Utils.Translate('fav_movies'), 'Tag': "Favorite movies", 'Media': "movies"}, {'Name': self.EmbyServer.Utils.Translate('fav_tvshows'), 'Tag': "Favorite tvshows", 'Media': "tvshows"}, {'Name': self.EmbyServer.Utils.Translate('fav_episodes'), 'Tag': "Favorite episodes", 'Media': "episodes"}]: self.window_single_node(index, "favorites", single) index += 1 - self.Library.Monitor.Service.Utils.window('emby.nodes.total', str(index)) + self.EmbyServer.Utils.window('emby.nodes.total', str(index)) #Leads to another listing of nodes def window_node(self, index, view, node, node_label): @@ -992,25 +992,25 @@ def window_node(self, index, view, node, node_label): else: window_path = "ActivateWindow(Videos,%s,return)" % path - node_label = self.Library.Monitor.Service.Utils.Translate(node_label) if isinstance(node_label, int) else node_label + node_label = self.EmbyServer.Utils.Translate(node_label) if isinstance(node_label, int) else node_label node_label = node_label or view['Name'] if node in ('all', 'music'): window_prop = "Emby.nodes.%s" % index - self.Library.Monitor.Service.Utils.window('%s.index' % window_prop, path.replace('all.xml', "")) # dir - self.Library.Monitor.Service.Utils.window('%s.title' % window_prop, view['Name'].encode('utf-8')) - self.Library.Monitor.Service.Utils.window('%s.content' % window_prop, path) + self.EmbyServer.Utils.window('%s.index' % window_prop, path.replace('all.xml', "")) # dir + self.EmbyServer.Utils.window('%s.title' % window_prop, view['Name'].encode('utf-8')) + self.EmbyServer.Utils.window('%s.content' % window_prop, path) elif node == 'browse': window_prop = "Emby.nodes.%s" % index - self.Library.Monitor.Service.Utils.window('%s.title' % window_prop, view['Name'].encode('utf-8')) + self.EmbyServer.Utils.window('%s.title' % window_prop, view['Name'].encode('utf-8')) else: window_prop = "Emby.nodes.%s.%s" % (index, node) - self.Library.Monitor.Service.Utils.window('%s.title' % window_prop, node_label.encode('utf-8')) - self.Library.Monitor.Service.Utils.window('%s.content' % window_prop, path) + self.EmbyServer.Utils.window('%s.title' % window_prop, node_label.encode('utf-8')) + self.EmbyServer.Utils.window('%s.content' % window_prop, path) - self.Library.Monitor.Service.Utils.window('%s.id' % window_prop, view['Id']) - self.Library.Monitor.Service.Utils.window('%s.path' % window_prop, window_path) - self.Library.Monitor.Service.Utils.window('%s.type' % window_prop, view['Media']) + self.EmbyServer.Utils.window('%s.id' % window_prop, view['Id']) + self.EmbyServer.Utils.window('%s.path' % window_prop, window_path) + self.EmbyServer.Utils.window('%s.type' % window_prop, view['Media']) self.window_artwork(window_prop, view['Id']) #Single destination node @@ -1018,10 +1018,10 @@ def window_single_node(self, index, item_type, view): path = "library://video/emby_%s.xml" % view['Tag'].replace(" ", "") window_path = "ActivateWindow(Videos,%s,return)" % path window_prop = "Emby.nodes.%s" % index - self.Library.Monitor.Service.Utils.window('%s.title' % window_prop, view['Name']) - self.Library.Monitor.Service.Utils.window('%s.path' % window_prop, window_path) - self.Library.Monitor.Service.Utils.window('%s.content' % window_prop, path) - self.Library.Monitor.Service.Utils.window('%s.type' % window_prop, item_type) + self.EmbyServer.Utils.window('%s.title' % window_prop, view['Name']) + self.EmbyServer.Utils.window('%s.path' % window_prop, window_path) + self.EmbyServer.Utils.window('%s.content' % window_prop, path) + self.EmbyServer.Utils.window('%s.type' % window_prop, item_type) #Similar to window_node, but does not contain music, musicvideos. #Contains books, audiobooks @@ -1036,44 +1036,44 @@ def window_wnode(self, index, view, node, node_label): else: window_path = "ActivateWindow(Videos,%s,return)" % path - node_label = self.Library.Monitor.Service.Utils.Translate(node_label) if isinstance(node_label, int) else node_label + node_label = self.EmbyServer.Utils.Translate(node_label) if isinstance(node_label, int) else node_label node_label = node_label or view['Name'] clean_title = view.get('CleanName', node_label) if node == 'all': window_prop = "Emby.wnodes.%s" % index - self.Library.Monitor.Service.Utils.window('%s.index' % window_prop, path.replace('all.xml', "")) # dir - self.Library.Monitor.Service.Utils.window('%s.title' % window_prop, view['Name'].encode('utf-8')) - self.Library.Monitor.Service.Utils.window('%s.cleantitle' % window_prop, clean_title.encode('utf-8')) - self.Library.Monitor.Service.Utils.window('%s.content' % window_prop, path) + self.EmbyServer.Utils.window('%s.index' % window_prop, path.replace('all.xml', "")) # dir + self.EmbyServer.Utils.window('%s.title' % window_prop, view['Name'].encode('utf-8')) + self.EmbyServer.Utils.window('%s.cleantitle' % window_prop, clean_title.encode('utf-8')) + self.EmbyServer.Utils.window('%s.content' % window_prop, path) elif node == 'browse': window_prop = "Emby.wnodes.%s" % index - self.Library.Monitor.Service.Utils.window('%s.title' % window_prop, view['Name'].encode('utf-8')) - self.Library.Monitor.Service.Utils.window('%s.cleantitle' % window_prop, clean_title.encode('utf-8')) - self.Library.Monitor.Service.Utils.window('%s.content' % window_prop, path) + self.EmbyServer.Utils.window('%s.title' % window_prop, view['Name'].encode('utf-8')) + self.EmbyServer.Utils.window('%s.cleantitle' % window_prop, clean_title.encode('utf-8')) + self.EmbyServer.Utils.window('%s.content' % window_prop, path) else: window_prop = "Emby.wnodes.%s.%s" % (index, node) - self.Library.Monitor.Service.Utils.window('%s.title' % window_prop, node_label.encode('utf-8')) - self.Library.Monitor.Service.Utils.window('%s.cleantitle' % window_prop, clean_title.encode('utf-8')) - self.Library.Monitor.Service.Utils.window('%s.content' % window_prop, path) + self.EmbyServer.Utils.window('%s.title' % window_prop, node_label.encode('utf-8')) + self.EmbyServer.Utils.window('%s.cleantitle' % window_prop, clean_title.encode('utf-8')) + self.EmbyServer.Utils.window('%s.content' % window_prop, path) - self.Library.Monitor.Service.Utils.window('%s.id' % window_prop, view['Id']) - self.Library.Monitor.Service.Utils.window('%s.path' % window_prop, window_path) - self.Library.Monitor.Service.Utils.window('%s.type' % window_prop, view['Media']) + self.EmbyServer.Utils.window('%s.id' % window_prop, view['Id']) + self.EmbyServer.Utils.window('%s.path' % window_prop, window_path) + self.EmbyServer.Utils.window('%s.type' % window_prop, view['Media']) self.window_artwork(window_prop, view['Id']) - self.LOG.debug("--[ wnode/%s/%s ] %s" % (index, self.Library.Monitor.Service.Utils.window('%s.title' % window_prop), self.Library.Monitor.Service.Utils.window('%s.artwork' % window_prop))) + self.LOG.debug("--[ wnode/%s/%s ] %s" % (index, self.EmbyServer.Utils.window('%s.title' % window_prop), self.EmbyServer.Utils.window('%s.artwork' % window_prop))) def window_artwork(self, prop, view_id): - if not self.Library.Monitor.EmbyServer[self.Library.server_id].logged_in: - self.Library.Monitor.Service.Utils.window('%s.artwork' % prop, clear=True) - elif self.Library.Monitor.EmbyServer[self.Library.server_id].logged_in and self.media_folders: + if not self.EmbyServer.logged_in: + self.EmbyServer.Utils.window('%s.artwork' % prop, clear=True) + elif self.EmbyServer.logged_in and self.media_folders: for library in self.media_folders: if library['Id'] == view_id and 'Primary' in library.get('ImageTags', {}): - artwork = helper.api.API(None, self.Library.Monitor.Service.Utils, self.Library.Monitor.EmbyServer[self.Library.server_id].auth.get_serveraddress()).get_artwork(view_id, 'Primary', None, None) - self.Library.Monitor.Service.Utils.window('%s.artwork' % prop, artwork) + artwork = self.APIHelper.get_artwork(view_id, 'Primary', None, None) + self.EmbyServer.Utils.window('%s.artwork' % prop, artwork) break else: - self.Library.Monitor.Service.Utils.window('%s.artwork' % prop, clear=True) + self.EmbyServer.Utils.window('%s.artwork' % prop, clear=True) def window_path(self, view, node): return "library://video/emby%s%s/%s.xml" % (view['Media'], view['Id'], node) @@ -1105,9 +1105,8 @@ def window_browse(self, view, node): #Clearing window prop setup for Views def window_clear(self, name): - total = int(self.Library.Monitor.Service.Utils.window(name + '.total') or 0) + total = int(self.EmbyServer.Utils.window(name + '.total') or 0) props = [ - "index", "id", "path", "artwork", "title", "cleantitle", "content", "type" "inprogress.content", "inprogress.title", "inprogress.content", "inprogress.path", @@ -1122,10 +1121,10 @@ def window_clear(self, name): for i in range(total): for prop in props: - self.Library.Monitor.Service.Utils.window(name + '.%s.%s' % (str(i), prop), clear=True) + self.EmbyServer.Utils.window(name + '.%s.%s' % (str(i), prop), clear=True) for prop in props: - self.Library.Monitor.Service.Utils.window(name + '.%s' % prop, clear=True) + self.EmbyServer.Utils.window(name + '.%s' % prop, clear=True) def delete_playlist(self, path): xbmcvfs.delete(path) @@ -1133,7 +1132,7 @@ def delete_playlist(self, path): #Remove all emby playlists def delete_playlists(self): - path = self.Library.Monitor.Service.Utils.translatePath("special://profile/playlists/video/") + path = self.EmbyServer.Utils.translatePath("special://profile/playlists/video/") _, files = xbmcvfs.listdir(path) for filename in files: @@ -1142,7 +1141,7 @@ def delete_playlists(self): #Remove playlist based based on view_id def delete_playlist_by_id(self, view_id): - path = self.Library.Monitor.Service.Utils.translatePath("special://profile/playlists/video/") + path = self.EmbyServer.Utils.translatePath("special://profile/playlists/video/") _, files = xbmcvfs.listdir(path) for filename in files: @@ -1155,7 +1154,7 @@ def delete_node(self, path): #Remove node and children files def delete_nodes(self): - path = self.Library.Monitor.Service.Utils.translatePath("special://profile/library/video/") + path = self.EmbyServer.Utils.translatePath("special://profile/library/video/") dirs, files = xbmcvfs.listdir(path) for filename in files: @@ -1173,7 +1172,7 @@ def delete_nodes(self): #Remove node and children files based on view_id def delete_node_by_id(self, view_id): - path = self.Library.Monitor.Service.Utils.translatePath("special://profile/library/video/") + path = self.EmbyServer.Utils.translatePath("special://profile/library/video/") dirs, files = xbmcvfs.listdir(path) for directory in dirs: diff --git a/events.py b/events.py index bc2d82d51..5d743b147 100644 --- a/events.py +++ b/events.py @@ -13,18 +13,14 @@ import xbmcvfs import xbmcgui import xbmcplugin -import xbmcaddon import core.obj_ops import core.listitem -import core.artwork import emby.main -import emby.downloader import database.database import database.emby_db import helper.utils import helper.api -import helper.xmls import helper.loghandler import context @@ -32,8 +28,42 @@ class Events(): #Parse the parameters. Reroute to our service.py #where user is fully identified already def __init__(self, Parameter): - self.LOG = helper.loghandler.LOG('EMBY.Events') self.Utils = helper.utils.Utils() + params = dict(parse_qsl(Parameter[2][1:])) + Handle = int(Parameter[1]) + mode = params.get('mode') + self.server_id = params.get('server') + + #Simple commands + if mode == 'deviceid': + self.Utils.reset_device_id() + return + elif mode == 'reset': + self.Utils.event('DatabaseReset', {}) + return + elif mode == 'login': + self.Utils.event('ServerConnect', {'ServerId': None}) + return + elif mode == 'backup': + self.backup() + return + elif mode == 'changelog': + #self.changelog() #EVENT!!!!!!!!!!!!!!!!!! + return + elif mode == 'restartservice': + self.Utils.window('emby.restart.bool', True) + return + elif mode == 'patchmusic': + self.Utils.event('PatchMusic', {'Notification': True, 'ServerId': None}) + return + elif mode == 'settings': + xbmc.executebuiltin('Addon.OpenSettings(plugin.video.emby-next-gen)') + return + elif mode == 'texturecache': + self.Utils.event('TextureCache', {}) + return + + self.LOG = helper.loghandler.LOG('EMBY.Events') self.EMBY = None self.DYNNODES = { 'tvshows': [ @@ -90,25 +120,10 @@ def __init__(self, Parameter): ] } - if len(Parameter) >= 2: - params = dict(parse_qsl(Parameter[2][1:])) - else: - params = {} - - Handle = int(Parameter[1]) - mode = params.get('mode') - self.server_id = params.get('server') - - - if not self.set_server(): return - - - - - self.Downloader = emby.downloader.Downloader(self.Utils, self.EmbyServer[self.server_id]) + self.APIHelper = helper.api.API(self.Utils, self.EmbyServer[self.server_id].Data['auth.ssl']) self.LOG.warning("path: %s params: %s" % (Parameter[2], json.dumps(params, indent=4))) # if '/extrafanart' in Parameter[0]: @@ -121,20 +136,16 @@ def __init__(self, Parameter): # self.get_video_extras(emby_id, emby_path, server) if mode == 'photoviewer': xbmc.executebuiltin('ShowPicture(%s/emby/Items/%s/Images/Primary)' % (self.EmbyServer[self.server_id].auth.get_serveraddress(), params['id'])) - elif mode == 'deviceid': - self.Utils.reset_device_id() - elif mode == 'reset': - database.database.reset(self.Utils, False) elif mode == 'delete': - context.Context(delete=True) + context.Context(delete=True) #EVENT!!!!!!!!!!!!!!!!!! elif mode == 'refreshboxsets': - self.Utils.event('SyncLibrary', {'Id': "Boxsets: Refresh", 'ServerId': self.server_id}) + self.Utils.event('SyncLibrary', {'Id': "Boxsets: Refresh", 'Update': False, 'ServerId': self.server_id}) elif mode == 'nextepisodes': self.get_next_episodes(Handle, params['id'], params['limit']) elif mode == 'browse': self.browse(Handle, params.get('type'), params.get('id'), params.get('folder')) elif mode == 'synclib': - self.Utils.event('SyncLibrary', {'Id': params.get('id'), 'ServerId': self.server_id}) + self.Utils.event('SyncLibrary', {'Id': params.get('id'), 'Update': False, 'ServerId': self.server_id}) elif mode == 'updatelib': self.Utils.event('SyncLibrary', {'Id': params.get('id'), 'Update': True, 'ServerId': self.server_id}) elif mode == 'repairlib': @@ -149,37 +160,16 @@ def __init__(self, Parameter): self.Utils.event('RemoveLibrarySelection', {'ServerId': self.server_id}) elif mode == 'addlibs': self.Utils.event('AddLibrarySelection', {'ServerId': self.server_id}) - elif mode == 'connect': - self.Utils.event('EmbyConnect', {'ServerId': self.server_id}) elif mode == 'addserver': self.Utils.event('AddServer', {'ServerId': self.server_id}) - elif mode == 'login': - self.Utils.event('ServerConnect', {'ServerId': self.server_id}) elif mode == 'removeserver': self.Utils.event('RemoveServer', {'ServerId': self.server_id}) - elif mode == 'settings': - xbmc.executebuiltin('Addon.OpenSettings(plugin.video.emby-next-gen)') elif mode == 'adduser': - self.add_user(params.get('permanent') == 'true') - elif mode == 'resetupdate': - self.Utils.event('ResetUpdate', {'ServerId': self.server_id}) - elif mode == 'updateserver': - self.Utils.event('UpdateServer', {'ServerId': self.server_id}) + self.add_user(params.get('permanent') == 'true') #EVENT!!!!!!!!!!!!!!!!!! elif mode == 'thememedia': - self.get_themes() + self.Utils.event('SyncThemes', {'ServerId': self.server_id}) elif mode == 'managelibs': self.manage_libraries(Handle) - elif mode == 'texturecache': - self.cache_artwork() - elif mode == 'backup': - self.backup() - elif mode == 'restartservice': - self.Utils.window('emby.restart.bool', True) - elif mode == 'patchmusic': - self.Utils.event('PatchMusic', {'Notification': True, 'ServerId': self.server_id}) - elif mode == 'changelog': - return - #self.changelog() elif mode == 'setssl': self.Utils.event('SetServerSSL', {'ServerId': self.server_id}) else: @@ -195,17 +185,14 @@ def set_server(self): ServerOnline = False self.EmbyServer = {} - self.EmbyServerName = {} server_ids = self.Utils.window('emby.servers.json') for server_id in server_ids: for _ in range(60): if self.Utils.window('emby.server.%s.online.bool' % server_id): ServerOnline = True - self.EmbyServer[server_id] = emby.main.Emby(server_id) - ServerData = self.Utils.window('emby.server.%s.state.json' % server_id) - self.EmbyServer[server_id].set_state(ServerData) - self.EmbyServerName[server_id] = ServerData['config']['auth.server-name'] + self.EmbyServer[server_id] = emby.main.Emby(self.Utils, server_id) + self.EmbyServer[server_id].set_state() break xbmc.sleep(500) @@ -215,8 +202,7 @@ def set_server(self): #Display all emby nodes and dynamic entries when appropriate def listing(self, Handle): total = int(self.Utils.window('emby.nodes.total') or 0) - sync = self.Utils.get_sync() - whitelist = [x.replace('Mixed:', "") for x in sync['Whitelist']] + whitelist = [x.replace('Mixed:', "") for x in self.Utils.SyncData['Whitelist']] for i in range(total): window_prop = "Emby.nodes.%s" % i @@ -225,7 +211,7 @@ def listing(self, Handle): if not path: path = self.Utils.window('%s.content' % window_prop) or self.Utils.window('%s.path' % window_prop) - label = self.Utils.window('%s.title' % window_prop) + " (" + self.EmbyServerName[self.server_id] + ")" + label = self.Utils.window('%s.title' % window_prop) + " (" + self.EmbyServer[self.server_id].Data['auth.server-name'] + ")" node = self.Utils.window('%s.type' % window_prop) artwork = self.Utils.window('%s.artwork' % window_prop) view_id = self.Utils.window('%s.id' % window_prop) @@ -268,7 +254,7 @@ def listing(self, Handle): self.directory(Handle, self.Utils.Translate(33194), "plugin://plugin.video.emby-next-gen/?mode=managelibs", True, None, None, None) self.directory(Handle, self.Utils.Translate(33134), "plugin://plugin.video.emby-next-gen/?mode=addserver", False, None, None, None) - self.directory(Handle, "%s (%s)" % (self.Utils.Translate(33054), self.EmbyServerName[self.server_id]), "plugin://plugin.video.emby-next-gen/?mode=adduser&server=%s" % self.server_id, False, None, None, None) + self.directory(Handle, "%s (%s)" % (self.Utils.Translate(33054), self.EmbyServer[self.server_id].Data['auth.server-name']), "plugin://plugin.video.emby-next-gen/?mode=adduser&server=%s" % self.server_id, False, None, None, None) self.directory(Handle, self.Utils.Translate(5), "plugin://plugin.video.emby-next-gen/?mode=settings", False, None, None, None) self.directory(Handle, self.Utils.Translate(33059), "plugin://plugin.video.emby-next-gen/?mode=texturecache", False, None, None, None) self.directory(Handle, self.Utils.Translate(33058), "plugin://plugin.video.emby-next-gen/?mode=reset", False, None, None, None) @@ -300,12 +286,12 @@ def dir_listitem(self, label, path, artwork, fanart): return li def manage_libraries(self, Handle): - self.directory(Handle, "%s (%s)" % (self.Utils.Translate(33098), self.EmbyServerName[self.server_id]), "plugin://plugin.video.emby-next-gen/?mode=refreshboxsets&server=%s" % self.server_id, False, None, None, None) - self.directory(Handle, "%s (%s)" % (self.Utils.Translate(33154), self.EmbyServerName[self.server_id]), "plugin://plugin.video.emby-next-gen/?mode=addlibs&server=%s" % self.server_id, False, None, None, None) - self.directory(Handle, "%s (%s)" % (self.Utils.Translate(33139), self.EmbyServerName[self.server_id]), "plugin://plugin.video.emby-next-gen/?mode=updatelibs&server=%s" % self.server_id, False, None, None, None) - self.directory(Handle, "%s (%s)" % (self.Utils.Translate(33140), self.EmbyServerName[self.server_id]), "plugin://plugin.video.emby-next-gen/?mode=repairlibs&server=%s" % self.server_id, False, None, None, None) - self.directory(Handle, "%s (%s)" % (self.Utils.Translate(33184), self.EmbyServerName[self.server_id]), "plugin://plugin.video.emby-next-gen/?mode=removelibs&server=%s" % self.server_id, False, None, None, None) - self.directory(Handle, "%s (%s)" % (self.Utils.Translate(33060), self.EmbyServerName[self.server_id]), "plugin://plugin.video.emby-next-gen/?mode=thememedia&server=%s" % self.server_id, False, None, None, None) + self.directory(Handle, "%s (%s)" % (self.Utils.Translate(33098), self.EmbyServer[self.server_id].Data['auth.server-name']), "plugin://plugin.video.emby-next-gen/?mode=refreshboxsets&server=%s" % self.server_id, False, None, None, None) + self.directory(Handle, "%s (%s)" % (self.Utils.Translate(33154), self.EmbyServer[self.server_id].Data['auth.server-name']), "plugin://plugin.video.emby-next-gen/?mode=addlibs&server=%s" % self.server_id, False, None, None, None) + self.directory(Handle, "%s (%s)" % (self.Utils.Translate(33139), self.EmbyServer[self.server_id].Data['auth.server-name']), "plugin://plugin.video.emby-next-gen/?mode=updatelibs&server=%s" % self.server_id, False, None, None, None) + self.directory(Handle, "%s (%s)" % (self.Utils.Translate(33140), self.EmbyServer[self.server_id].Data['auth.server-name']), "plugin://plugin.video.emby-next-gen/?mode=repairlibs&server=%s" % self.server_id, False, None, None, None) + self.directory(Handle, "%s (%s)" % (self.Utils.Translate(33184), self.EmbyServer[self.server_id].Data['auth.server-name']), "plugin://plugin.video.emby-next-gen/?mode=removelibs&server=%s" % self.server_id, False, None, None, None) + self.directory(Handle, "%s (%s)" % (self.Utils.Translate(33060), self.EmbyServer[self.server_id].Data['auth.server-name']), "plugin://plugin.video.emby-next-gen/?mode=thememedia&server=%s" % self.server_id, False, None, None, None) self.directory(Handle, self.Utils.Translate(33202), "plugin://plugin.video.emby-next-gen/?mode=patchmusic", False, None, None, None) xbmcplugin.setContent(Handle, 'files') xbmcplugin.endOfDirectory(Handle) @@ -342,6 +328,7 @@ def browse(self, Handle, media, view_id, folder): content_type = "videos" elif media == 'music': content_type = "artists" + if folder == 'recentlyadded': listing = self.EmbyServer[self.server_id].API.get_recently_added(None, view_id, None) elif folder == 'genres': @@ -349,44 +336,44 @@ def browse(self, Handle, media, view_id, folder): elif media == 'livetv': listing = self.EmbyServer[self.server_id].API.get_channels() elif folder == 'unwatched': - listing = self.Downloader.get_filtered_section(view_id, None, None, None, None, None, ['IsUnplayed'], None, False) + listing = self.EmbyServer[self.server_id].API.get_filtered_section(view_id, None, None, None, None, None, ['IsUnplayed'], None, False) elif folder == 'favorite': - listing = self.Downloader.get_filtered_section(view_id, None, None, None, None, None, ['IsFavorite'], None, False) + listing = self.EmbyServer[self.server_id].API.get_filtered_section(view_id, None, None, None, None, None, ['IsFavorite'], None, False) elif folder == 'inprogress': - listing = self.Downloader.get_filtered_section(view_id, None, None, None, None, None, ['IsResumable'], None, False) + listing = self.EmbyServer[self.server_id].API.get_filtered_section(view_id, None, None, None, None, None, ['IsResumable'], None, False) elif folder == 'boxsets': - listing = self.Downloader.get_filtered_section(view_id, self.get_media_type('boxsets'), None, True, None, None, None, None, False) + listing = self.EmbyServer[self.server_id].API.get_filtered_section(view_id, self.get_media_type('boxsets'), None, True, None, None, None, None, False) elif folder == 'random': - listing = self.Downloader.get_filtered_section(view_id, self.get_media_type(content_type), 25, True, "Random", None, None, None, False) + listing = self.EmbyServer[self.server_id].API.get_filtered_section(view_id, self.get_media_type(content_type), 25, True, "Random", None, None, None, False) elif (folder or "").startswith('firstletter-'): - listing = self.Downloader.get_filtered_section(view_id, self.get_media_type(content_type), None, None, None, None, None, {'NameStartsWith': folder.split('-')[1]}, False) + listing = self.EmbyServer[self.server_id].API.get_filtered_section(view_id, self.get_media_type(content_type), None, None, None, None, None, {'NameStartsWith': folder.split('-')[1]}, False) elif (folder or "").startswith('genres-'): - listing = self.Downloader.get_filtered_section(view_id, self.get_media_type(content_type), None, None, None, None, None, {'GenreIds': folder.split('-')[1]}, False) + listing = self.EmbyServer[self.server_id].API.get_filtered_section(view_id, self.get_media_type(content_type), None, None, None, None, None, {'GenreIds': folder.split('-')[1]}, False) elif folder == 'favepisodes': - listing = self.Downloader.get_filtered_section(None, self.get_media_type(content_type), 25, None, None, None, ['IsFavorite'], None, False) + listing = self.EmbyServer[self.server_id].API.get_filtered_section(None, self.get_media_type(content_type), 25, None, None, None, ['IsFavorite'], None, False) elif media == 'homevideos': - listing = self.Downloader.get_filtered_section(folder or view_id, self.get_media_type(content_type), None, False, None, None, None, None, False) + listing = self.EmbyServer[self.server_id].API.get_filtered_section(folder or view_id, self.get_media_type(content_type), None, False, None, None, None, None, False) elif media == 'movies': - listing = self.Downloader.get_filtered_section(folder or view_id, self.get_media_type(content_type), None, True, None, None, None, None, False) + listing = self.EmbyServer[self.server_id].API.get_filtered_section(folder or view_id, self.get_media_type(content_type), None, True, None, None, None, None, False) elif media in ('boxset', 'library'): - listing = self.Downloader.get_filtered_section(folder or view_id, None, None, True, None, None, None, None, False) + listing = self.EmbyServer[self.server_id].API.get_filtered_section(folder or view_id, None, None, True, None, None, None, None, False) elif media == 'episodes': - listing = self.Downloader.get_filtered_section(folder or view_id, self.get_media_type(content_type), None, True, None, None, None, None, False) + listing = self.EmbyServer[self.server_id].API.get_filtered_section(folder or view_id, self.get_media_type(content_type), None, True, None, None, None, None, False) elif media == 'boxsets': - listing = self.Downloader.get_filtered_section(folder or view_id, None, None, False, None, None, ['Boxsets'], None, False) + listing = self.EmbyServer[self.server_id].API.get_filtered_section(folder or view_id, None, None, False, None, None, ['Boxsets'], None, False) elif media == 'tvshows': - listing = self.Downloader.get_filtered_section(folder or view_id, self.get_media_type(content_type), None, True, None, None, None, None, False) + listing = self.EmbyServer[self.server_id].API.get_filtered_section(folder or view_id, self.get_media_type(content_type), None, True, None, None, None, None, False) elif media == 'seasons': listing = self.EmbyServer[self.server_id].API.get_seasons(folder) elif media == 'playlists': - listing = self.Downloader.get_filtered_section(folder or view_id, None, None, False, None, None, None, None, True) + listing = self.EmbyServer[self.server_id].API.get_filtered_section(folder or view_id, None, None, False, None, None, None, None, True) elif media != 'files': - listing = self.Downloader.get_filtered_section(folder or view_id, self.get_media_type(content_type), None, False, None, None, None, None, False) + listing = self.EmbyServer[self.server_id].API.get_filtered_section(folder or view_id, self.get_media_type(content_type), None, False, None, None, None, None, False) else: - listing = self.Downloader.get_filtered_section(folder or view_id, None, None, False, None, None, None, None, False) + listing = self.EmbyServer[self.server_id].API.get_filtered_section(folder or view_id, None, None, False, None, None, None, None, False) if listing: - listitems = core.listitem.ListItem(self.EmbyServer[self.server_id].auth.get_serveraddress(), self.Utils) + listitems = core.listitem.ListItem(self.EmbyServer[self.server_id].Data['auth.ssl'], self.Utils) list_li = [] listing = listing if isinstance(listing, list) else listing.get('Items', []) @@ -397,7 +384,7 @@ def browse(self, Handle, media, view_id, folder): li = xbmcgui.ListItem() li.setProperty('embyid', item['Id']) li.setProperty('embyserver', self.server_id) - li = listitems.set(item, li, None, False, None) + li = listitems.set(item, li, None, None) if item.get('IsFolder'): params = { @@ -464,8 +451,7 @@ def browse(self, Handle, media, view_id, folder): else: path = "http://127.0.0.1:57578/%s/%s-%s-stream-%s" % (Type, item['Id'], item['MediaSources'][0]['Id'], FilenameURL) - self.Utils.window('emby.DynamicItem_' + path, item['Id']) - + self.Utils.window('emby.DynamicItem_' + self.Utils.ReplaceSpecialCharecters(li.getLabel()), item['Id']) li.setProperty('path', path) contextData = [(self.Utils.Translate(13412), "RunPlugin(plugin://plugin.video.emby-next-gen/?mode=playlist&id=%s&server=%s)" % (item['Id'], self.server_id))] @@ -610,10 +596,9 @@ def get_fanart(self, Handle, item_id, path): xbmcvfs.mkdirs(directory) item = self.EmbyServer[self.server_id].API.get_item(item_id) obj = objects.map(item, 'Artwork') - backdrops = helper.api.API(item, self.Utils, self.EmbyServer[self.server_id].auth.get_serveraddress()).get_all_artwork(obj) tags = obj['BackdropTags'] - for index, backdrop in enumerate(backdrops): + for index, backdrop in enumerate(self.APIHelper.get_all_artwork(obj)): tag = tags[index] fanart = os.path.join(directory, "fanart%s.jpg" % tag) li = xbmcgui.ListItem(tag, path=fanart) @@ -795,10 +780,7 @@ def create_listitem(self, item): #Add or remove users from the default server session #permanent=True from the add-on settings def add_user(self, permanent): -# if not self.Utils.window('emby.online.bool'): -# return - - session = self.EmbyServer[self.server_id].API.get_device(self.EmbyServer[self.server_id]['config/app.device_id']) + session = self.EmbyServer[self.server_id].API.get_device() hidden = None if self.Utils.settings('addUsersHidden.bool') else False users = self.EmbyServer[self.server_id].API.get_users(False, hidden) @@ -808,7 +790,7 @@ def add_user(self, permanent): break while True: - session = self.EmbyServer[self.server_id].API.get_device(self.EmbyServer[self.server_id]['config/app.device_id']) + session = self.EmbyServer[self.server_id].API.get_device() additional = current = session[0]['AdditionalUsers'] add_session = True @@ -864,67 +846,6 @@ def add_user(self, permanent): self.Utils.dialog("notification", heading="{emby}", message="%s %s" % (self.Utils.Translate(33066), user['UserName']), icon="{emby}", time=1000, sound=False) - #Add theme media locally, via strm. This is only for tv tunes. - #If another script is used, adjust this code - def get_themes(self): - xmls = helper.xmls.Xmls(self.Utils) - library = self.Utils.translatePath("special://profile/addon_data/plugin.video.emby-next-gen/library") - play = self.Utils.settings('useDirectPaths') == "1" - - if not xbmcvfs.exists(library + '/'): - xbmcvfs.mkdir(library) - - if xbmc.getCondVisibility('System.HasAddon(script.tvtunes)'): - tvtunes = xbmcaddon.Addon(id="script.tvtunes") - tvtunes.setSetting('custom_path_enable', "true") - tvtunes.setSetting('custom_path', library) - self.LOG.info("TV Tunes custom path is enabled and set.") - elif xbmc.getCondVisibility('System.HasAddon(service.tvtunes)'): - tvtunes = xbmcaddon.Addon(id="service.tvtunes") - tvtunes.setSetting('custom_path_enable', "true") - tvtunes.setSetting('custom_path', library) - self.LOG.info("TV Tunes custom path is enabled and set.") - else: - self.Utils.dialog("ok", heading="{emby}", line1=self.Utils.Translate(33152)) - return - - with database.database.Database(self.Utils, 'emby', False) as embydb: - all_views = database.emby_db.EmbyDatabase(embydb.cursor).get_views() - views = [x[0] for x in all_views if x[2] in ('movies', 'tvshows', 'mixed')] - - items = {} - - for view in views: - for result in self.Downloader.get_items(view, None, False, {'HasThemeVideo': True}): - for item in result['Items']: - folder = self.Utils.normalize_string(item['Name']) - items[item['Id']] = folder - - for result in self.Downloader.get_items(view, None, False, {'HasThemeSong': True}): - for item in result['Items']: - folder = self.Utils.normalize_string(item['Name']) - items[item['Id']] = folder - - for item in items: - nfo_path = os.path.join(library, items[item]) - nfo_file = os.path.join(nfo_path, "tvtunes.nfo") - - if not xbmcvfs.exists(nfo_path): - xbmcvfs.mkdir(nfo_path) - - themes = self.EmbyServer[self.server_id].API.get_themes(item) - paths = [] - - for theme in themes['ThemeVideosResult']['Items'] + themes['ThemeSongsResult']['Items']: - if play: - paths.append(theme['MediaSources'][0]['Path']) - else: - paths.append(self.Utils.direct_url(theme)) - - xmls.tvtunes_nfo(nfo_file, paths) - - self.Utils.dialog("notification", heading="{emby}", message=self.Utils.Translate(33153), icon="{emby}", time=1000, sound=False) - #Emby backup def backup(self): path = self.Utils.settings('backupPath') @@ -969,8 +890,5 @@ def backup(self): self.LOG.info("backup completed") self.Utils.dialog("ok", heading="{emby}", line1="%s %s" % (self.Utils.Translate(33091), backup)) - def cache_artwork(self): - core.artwork.Artwork(None, self.Utils).cache_textures() - if __name__ == "__main__": Events(sys.argv) diff --git a/helper/api.py b/helper/api.py index dfbe234ef..07b0e3cfc 100644 --- a/helper/api.py +++ b/helper/api.py @@ -5,25 +5,20 @@ from urllib.parse import urlencode class API(): - def __init__(self, item, Utils, server): + def __init__(self, Utils, ssl): self.Utils = Utils - self.item = item - self.server = server - self.verify_ssl = True - - if server and server.startswith('https') and not self.Utils.settings('sslverify.bool'): - self.verify_ssl = False + self.verify_ssl = ssl def get_playcount(self, played, playcount): return (playcount or 1) if played else None - def get_actors(self): + def get_actors(self, item): cast = [] - if 'People' in self.item: - self.get_people_artwork(self.item['People']) + if 'People' in item: + self.get_people_artwork(item['People']) - for person in self.item['People']: + for person in item['People']: if person['Type'] == "Actor": cast.append({ 'name': person['Name'], @@ -41,7 +36,7 @@ def media_streams(self, video, audio, subtitles): 'subtitle': subtitles or [] } - def video_streams(self, tracks, container): + def video_streams(self, tracks, container, item): if container: container = container.split(',')[0] @@ -51,7 +46,7 @@ def video_streams(self, tracks, container): 'profile': track.get('Profile', "").lower(), 'height': track.get('Height'), 'width': track.get('Width'), - '3d': self.item.get('Video3DFormat'), + '3d': item.get('Video3DFormat'), 'aspect': 1.85 }) @@ -66,14 +61,14 @@ def video_streams(self, tracks, container): track['codec'] = "avc1" try: - width, height = self.item.get('AspectRatio', track.get('AspectRatio', "0")).split(':') + width, height = item.get('AspectRatio', track.get('AspectRatio', "0")).split(':') track['aspect'] = round(float(width) / float(height), 6) except (ValueError, ZeroDivisionError): if track['width'] and track['height']: track['aspect'] = round(float(track['width'] / track['height']), 6) - track['duration'] = self.get_runtime() + track['duration'] = self.get_runtime(item) return tracks @@ -93,21 +88,20 @@ def audio_streams(self, tracks): return tracks - def get_runtime(self): + def get_runtime(self, item): try: - runtime = self.item['RunTimeTicks'] / 10000000.0 + runtime = item['RunTimeTicks'] / 10000000.0 except KeyError: - runtime = self.item.get('CumulativeRunTimeTicks', 0) / 10000000.0 + runtime = item.get('CumulativeRunTimeTicks', 0) / 10000000.0 return runtime - @classmethod - def adjust_resume(cls, resume_seconds, Utils): + def adjust_resume(self, resume_seconds): resume = 0 if resume_seconds: resume = round(float(resume_seconds), 6) - jumpback = int(Utils.settings('resumeJumpBack')) + jumpback = int(self.Utils.settings('resumeJumpBack')) if resume > jumpback: # To avoid negative bookmark @@ -129,8 +123,8 @@ def validate_studio(self, studio_name): } return studios.get(studio_name.lower(), studio_name) - def get_overview(self, overview): - overview = overview or self.item.get('Overview') + def get_overview(self, overview, item): + overview = overview or item.get('Overview') if not overview: return @@ -141,8 +135,8 @@ def get_overview(self, overview): overview = overview.replace("
", "[CR]") return overview - def get_mpaa(self, rating): - mpaa = rating or self.item.get('OfficialRating', "") + def get_mpaa(self, rating, item): + mpaa = rating or item.get('OfficialRating', "") if mpaa in ("NR", "UR"): # Kodi seems to not like NR, but will accept Not Rated @@ -153,9 +147,9 @@ def get_mpaa(self, rating): return mpaa - def get_file_path(self, path): + def get_file_path(self, path, item): if path is None: - path = self.item.get('Path') + path = item.get('Path') path = self.Utils.StringMod(path) @@ -163,9 +157,9 @@ def get_file_path(self, path): if path.endswith('.strm'): path = path.replace('.strm', "") - if 'Container' in self.item: - if not path.endswith(self.Utils.StringMod(self.item['Container'])): - path = path + "." + self.Utils.StringMod(self.item['Container']) + if 'Container' in item: + if not path.endswith(self.Utils.StringMod(item['Container'])): + path = path + "." + self.Utils.StringMod(item['Container']) if not path: return "" @@ -173,10 +167,10 @@ def get_file_path(self, path): if path.startswith('\\\\'): path = path.replace('\\\\', "smb://", 1).replace('\\\\', "\\").replace('\\', "/") - if 'Container' in self.item: - if self.item['Container'] == 'dvd': + if 'Container' in item: + if item['Container'] == 'dvd': path = "%s/VIDEO_TS/VIDEO_TS.IFO" % path - elif self.item['Container'] == 'bluray': + elif item['Container'] == 'bluray': path = "%s/BDMV/index.bdmv" % path path = path.replace('\\\\', "\\") @@ -190,10 +184,6 @@ def get_file_path(self, path): return path - #Get emby user profile picture. - def get_user_artwork(self, user_id): - return "%s/emby/Users/%s/Images/Primary?Format=original" % (self.server, user_id) - #Get people (actor, director, etc) artwork. def get_people_artwork(self, people): for person in people: diff --git a/helper/loghandler.py b/helper/loghandler.py index 49267198d..b5dc67df0 100644 --- a/helper/loghandler.py +++ b/helper/loghandler.py @@ -1,23 +1,12 @@ # -*- coding: utf-8 -*- import xbmc -import xbmcaddon class LOG(): def __init__(self, Prefix): self.Prefix = Prefix self.KodiVersion = int(xbmc.getInfoLabel('System.BuildVersion')[:2]) - try: - self.log_level = int(xbmcaddon.Addon("plugin.video.emby-next-gen").getSetting('logLevel')) - except ValueError: - self.log_level = 1 - - - def debug(self, msg): - if self.log_level != 2: #Debug - return - msg = "DEBUG: %s: %s" % (self.Prefix, msg) if self.KodiVersion >= 19: @@ -26,9 +15,6 @@ def debug(self, msg): xbmc.log(msg.encode('utf-8'), xbmc.LOGDEBUG) def info(self, msg): - if self.log_level == 0: #Disabled - return - msg = "INFO: %s: %s" % (self.Prefix, msg) if self.KodiVersion >= 19: @@ -37,9 +23,6 @@ def info(self, msg): xbmc.log(msg.encode('utf-8'), xbmc.LOGNOTICE) def warning(self, msg): - if self.log_level == 0: #Disabled - return - msg = "WARNING: %s: %s" % (self.Prefix, msg) if self.KodiVersion >= 19: @@ -48,9 +31,6 @@ def warning(self, msg): xbmc.log(msg.encode('utf-8'), xbmc.LOGWARNING) def error(self, msg): - if self.log_level == 0: #Disabled - return - msg = "ERROR: %s: %s" % (self.Prefix, msg) if self.KodiVersion >= 19: diff --git a/helper/setup.py b/helper/setup.py index 951c47bc6..e5b789d18 100644 --- a/helper/setup.py +++ b/helper/setup.py @@ -6,96 +6,85 @@ from . import loghandler class Setup(): - def __init__(self, Service): - self.Service = Service + def __init__(self, Utils): + self.Utils = Utils self.LOG = loghandler.LOG('EMBY.helper.setup') self.LOG.info("---<[ setup ]") #Setup playback mode. If native mode selected, check network credentials def _is_mode(self): - value = self.Service.Utils.dialog("yesno", heading=self.Service.Utils.Translate('playback_mode'), line1=self.Service.Utils.Translate(33035), nolabel=self.Service.Utils.Translate('addon_mode'), yeslabel=self.Service.Utils.Translate('native_mode')) - self.Service.Utils.settings('useDirectPaths', value="1" if value else "0") + value = self.Utils.dialog("yesno", heading=self.Utils.Translate('playback_mode'), line1=self.Utils.Translate(33035), nolabel=self.Utils.Translate('addon_mode'), yeslabel=self.Utils.Translate('native_mode')) if value: - self.Service.Utils.dialog("ok", heading="{emby}", line1=self.Service.Utils.Translate(33145)) + self.Utils.settings('useDirectPaths', "1") + self.Utils.direct_path = True + self.Utils.dialog("ok", heading="{emby}", line1=self.Utils.Translate(33145)) + else: + self.Utils.settings('useDirectPaths', "0") + self.Utils.direct_path = False def Migrate(self): Done = True - if not self.Service.Utils.settings('Migrate.bool'): - Source = self.Service.Utils.translatePath("special://profile/addon_data/plugin.video.emby/") + if not self.Utils.settings('Migrate.bool'): + Source = self.Utils.translatePath("special://profile/addon_data/plugin.video.emby/") if xbmcvfs.exists(Source): - if self.Service.Utils.dialog("yesno", heading="{emby}", line1="Emby for Kodi 4.X version detected. Do you start the migration? (THIS CANNOT BE UNDONE, MAKE SURE YOU HAVE A BACKUP)"): + if self.Utils.dialog("yesno", heading="{emby}", line1="Emby for Kodi 4.X version detected. Do you start the migration? (THIS CANNOT BE UNDONE, MAKE SURE YOU HAVE A BACKUP)"): xbmc.executeJSONRPC('{"jsonrpc": "2.0", "id":1, "method": "Addons.SetAddonEnabled", "params": { "addonid": "plugin.video.emby", "enabled": false }}') - Dest = self.Service.Utils.translatePath("special://profile/addon_data/plugin.video.emby-next-gen/data.json") - Source = self.Service.Utils.translatePath("special://profile/addon_data/plugin.video.emby/data.json") + Dest = self.Utils.translatePath("special://profile/addon_data/plugin.video.emby-next-gen/data.json") + Source = self.Utils.translatePath("special://profile/addon_data/plugin.video.emby/data.json") if xbmcvfs.exists(Source): - self.Service.Utils.copy_file(Source, Dest) + self.Utils.copy_file(Source, Dest) - Dest = self.Service.Utils.translatePath("special://profile/addon_data/plugin.video.emby-next-gen/emby_guid") - Source = self.Service.Utils.translatePath("special://profile/addon_data/plugin.video.emby/emby_guid") + Dest = self.Utils.translatePath("special://profile/addon_data/plugin.video.emby-next-gen/emby_guid") + Source = self.Utils.translatePath("special://profile/addon_data/plugin.video.emby/emby_guid") if xbmcvfs.exists(Source): - self.Service.Utils.copy_file(Source, Dest) + self.Utils.copy_file(Source, Dest) - Dest = self.Service.Utils.translatePath("special://profile/addon_data/plugin.video.emby-next-gen/settings.xml") - Source = self.Service.Utils.translatePath("special://profile/addon_data/plugin.video.emby/settings.xml") + Dest = self.Utils.translatePath("special://profile/addon_data/plugin.video.emby-next-gen/settings.xml") + Source = self.Utils.translatePath("special://profile/addon_data/plugin.video.emby/settings.xml") if xbmcvfs.exists(Source): - self.Service.Utils.copy_file(Source, Dest) + self.Utils.copy_file(Source, Dest) - Dest = self.Service.Utils.translatePath("special://profile/addon_data/plugin.video.emby-next-gen/sync.json") - Source = self.Service.Utils.translatePath("special://profile/addon_data/plugin.video.emby/sync.json") + Dest = self.Utils.translatePath("special://profile/addon_data/plugin.video.emby-next-gen/sync.json") + Source = self.Utils.translatePath("special://profile/addon_data/plugin.video.emby/sync.json") if xbmcvfs.exists(Source): - self.Service.Utils.copy_file(Source, Dest) + self.Utils.copy_file(Source, Dest) - self.Service.Utils.settings('Migrate.bool', True) + self.Utils.settings('Migrate.bool', True) Done = False else: xbmc.executeJSONRPC('{"jsonrpc": "2.0", "id":1, "method": "Addons.SetAddonEnabled", "params": {"addonid": "plugin.video.emby-next-gen", "enabled": false}}') - self.Service.Utils.settings('Migrate.bool', False) + self.Utils.settings('Migrate.bool', False) Done = False else: - self.Service.Utils.settings('Migrate.bool', True) + self.Utils.settings('Migrate.bool', True) return Done def setup(self): minimum = "5.0.0" - cached = self.Service.Utils.settings('MinimumSetup') + cached = self.Utils.settings('MinimumSetup') if cached == minimum: return - self.Service.ReloadSkin = False + ReloadSkin = False if not cached: self._is_mode() - self.LOG.info("Add-on playback: %s" % self.Service.Utils.settings('useDirectPaths') == "0") - self._is_empty_shows() - self.LOG.info("Sync empty shows: %s" % str(self.Service.Utils.settings('syncEmptyShows.bool'))) - self._is_multiep() - self.LOG.info("Enable multi episode label: %s" % self.Service.Utils.settings('displayMultiEpLabel.bool')) - self.Service.ReloadSkin = True + self.LOG.info("Add-on playback: %s" % self.Utils.settings('useDirectPaths') == "0") + ReloadSkin = True else: - self.Service.Utils.dialog("notification", heading="{emby}", message="Database reset required, please be patient!", icon="{emby}", time=15000, sound=True) - database.database.reset(self.Service.Utils, True) - self.Service.ReloadSkin = True + self.Utils.dialog("notification", heading="{emby}", message="Database reset required, please be patient!", icon="{emby}", time=15000, sound=True) + database.database.reset(self.Utils, True) + ReloadSkin = True #Setup completed - self.Service.Utils.settings('MinimumSetup', minimum) - - def _is_empty_shows(self): - value = self.Service.Utils.dialog("yesno", heading="{emby}", line1=self.Service.Utils.Translate(33100)) - self.Service.Utils.settings('syncEmptyShows.bool', value) - - def _is_music(self): - value = self.Service.Utils.dialog("yesno", heading="{emby}", line1=self.Service.Utils.Translate(33039)) - self.Service.Utils.settings('enableMusic.bool', value=value) - - def _is_multiep(self): - value = self.Service.Utils.dialog("yesno", heading="{emby}", line1=self.Service.Utils.Translate(33213)) - self.Service.Utils.settings('displayMultiEpLabel.bool', value=value) + self.Utils.settings('MinimumSetup', minimum) + return ReloadSkin diff --git a/helper/utils.py b/helper/utils.py index 3af44eb30..9f9c4ce2c 100644 --- a/helper/utils.py +++ b/helper/utils.py @@ -5,7 +5,7 @@ import unicodedata import uuid import _strptime # Workaround for threads using datetime: _striptime is locked -import datetime +from datetime import datetime, timedelta from dateutil import tz, parser try: @@ -19,6 +19,7 @@ import xbmcgui import xbmcvfs +import helper.xmls from . import loghandler class Utils(): @@ -31,6 +32,8 @@ def __init__(self): self.PathVerified = False self.VideoBitrateOptions = [664000, 996000, 1320000, 2000000, 3200000, 4700000, 6200000, 7700000, 9200000, 10700000, 12200000, 13700000, 15200000, 16700000, 18200000, 20000000, 25000000, 30000000, 35000000, 40000000, 100000000, 1000000000] self.AudioBitrateOptions = [64000, 96000, 128000, 192000, 256000, 320000, 384000, 448000, 512000] + self.VideoCodecOptions = ["h264", "hevc"] + self.AudioCodecOptions = ["aac", "ac3"] self.STRINGS = { 'addon_name': 29999, 'playback_mode': 30511, @@ -58,42 +61,89 @@ def __init__(self): self.addon_name = xbmcaddon.Addon("plugin.video.emby-next-gen").getAddonInfo('name').upper() self.addon_version = xbmcaddon.Addon("plugin.video.emby-next-gen").getAddonInfo('version') self.device_name = self.get_device_name() + self.direct_path = self.settings('useDirectPaths') == "1" self.device_id = self.get_device_id(False) self.device_info = {'DeviceName': self.device_name, 'Version': self.addon_version, 'DeviceId': self.device_id} self.Screensaver = None + self.SyncTimestampLast = datetime.fromtimestamp(0) + self.SyncData = self.load_sync() + self.DefaultVideoSettings = self.load_defaultvideosettings() + self.DatabaseFiles = self.load_DatabaseFiles() + + def load_DatabaseFiles(self): + DatabaseFiles = self.window('emby.DatabaseFiles.json') + + if not DatabaseFiles: #load from file + DatabaseFiles = { + 'emby': self.translatePath("special://database/") + "emby.db", + 'texture': "", + 'texture-version': 0, + 'music': "", + 'music-version': 0, + 'video': "", + 'video-version': 0 + } + + folder = self.translatePath("special://database/") + _, files = xbmcvfs.listdir(folder) + for Filename in files: + if not Filename.endswith('-wal') and not Filename.endswith('-shm') and not Filename.endswith('db-journal'): + if Filename.startswith('Textures'): + Version = int(''.join(i for i in Filename if i.isdigit())) + + if Version > DatabaseFiles['texture-version']: + DatabaseFiles['texture'] = os.path.join(folder, Filename) + DatabaseFiles['texture-version'] = Version + elif Filename.startswith('MyMusic'): + Version = int(''.join(i for i in Filename if i.isdigit())) + + if Version > DatabaseFiles['music-version']: + DatabaseFiles['music'] = os.path.join(folder, Filename) + DatabaseFiles['music-version'] = Version + elif Filename.startswith('MyVideos'): + Version = int(''.join(i for i in Filename if i.isdigit())) + if Version > DatabaseFiles['video-version']: + DatabaseFiles['video'] = os.path.join(folder, Filename) + DatabaseFiles['video-version'] = Version - self.SyncTimestampLast = datetime.datetime.fromtimestamp(0) - self.SyncData = {} - self.SyncData = self.get_sync() + return DatabaseFiles - def get_sync(self): - if not self.SyncData: #load from xbmc - self.SyncData = self.window('emby.servers.sync.json') + def load_defaultvideosettings(self): + DefaultVideoSettings = self.window('emby.kodi.get_defaultvideosettings.json') - if not self.SyncData: #load from file - path = self.translatePath("special://profile/addon_data/plugin.video.emby-next-gen/") + if not DefaultVideoSettings: #load from file + DefaultVideoSettings = helper.xmls.Xmls(self).load_defaultvideosettings() + self.window('emby.kodi.get_defaultvideosettings.json', DefaultVideoSettings) - if not xbmcvfs.exists(path): - xbmcvfs.mkdirs(path) + return DefaultVideoSettings - if xbmcvfs.exists(os.path.join(path, "sync.json")): - with open(os.path.join(path, 'sync.json'), 'rb') as infile: - self.SyncData = json.load(infile) - else: - self.SyncData = {} + def load_sync(self): + SyncData = self.window('emby.servers.sync.json') - self.SyncData['Libraries'] = self.SyncData.get('Libraries', []) - self.SyncData['RestorePoint'] = self.SyncData.get('RestorePoint', {}) - self.SyncData['Whitelist'] = list(set(self.SyncData.get('Whitelist', []))) - self.SyncData['SortedViews'] = self.SyncData.get('SortedViews', []) - self.window('emby.servers.sync.json', self.SyncData) + if not SyncData: #load from file + path = self.translatePath("special://profile/addon_data/plugin.video.emby-next-gen/") + + if not xbmcvfs.exists(path): + xbmcvfs.mkdirs(path) + + if xbmcvfs.exists(os.path.join(path, "sync.json")): + with open(os.path.join(path, 'sync.json'), 'rb') as infile: + SyncData = json.load(infile) + else: + SyncData = {} - return self.SyncData + SyncData['Libraries'] = SyncData.get('Libraries', []) + SyncData['RestorePoint'] = SyncData.get('RestorePoint', {}) + SyncData['Whitelist'] = list(set(SyncData.get('Whitelist', []))) + SyncData['SortedViews'] = SyncData.get('SortedViews', []) + self.window('emby.servers.sync.json', SyncData) + + return SyncData def save_sync(self, Data, ForceSave=False): - CurrentDate = datetime.datetime.utcnow() + CurrentDate = datetime.utcnow() if not ForceSave: if (CurrentDate - self.SyncTimestampLast).seconds <= 30: #save every 30 seconds on sync progress @@ -113,11 +163,34 @@ def save_sync(self, Data, ForceSave=False): self.window('emby.servers.sync.json', Data) self.SyncData = Data + def save_last_sync(self): + time_now = datetime.utcnow() - timedelta(minutes=2) + last_sync = time_now.strftime('%Y-%m-%dT%H:%M:%Sz') + self.settings('LastIncrementalSync', value=last_sync) + self.LOG.info("--[ sync/%s ]" % last_sync) + def InitSettings(self): self.KodiVersion = int(xbmc.getInfoLabel('System.BuildVersion')[:2]) self.Addon = xbmcaddon.Addon("plugin.video.emby-next-gen") self.VideoBitrate = self.VideoBitrateOptions[int(self.settings('videoBitrate'))] self.AudioBitrate = self.AudioBitrateOptions[int(self.settings('audioBitrate'))] + + + + + self.TranscodeH265 = self.settings('transcode_h265.bool') + self.TranscodeDivx = self.settings('transcodeDivx.bool') + self.TranscodeXvid = self.settings('transcodeXvid.bool') + self.TranscodeMpeg2 = self.settings('transcodeMpeg2.bool') + self.EnableCinema = self.settings('enableCinema.bool') + self.AskCinema = self.settings('askCinema.bool') + + + self.VideoCodecID = self.VideoCodecOptions[int(self.settings('TranscodeFormatVideo'))] + self.AudioCodecID = self.AudioCodecOptions[int(self.settings('TranscodeFormatAudio'))] + + + self.Screensaver = self.get_screensaver() self.WebserverData = self.get_web_server_data() self.GroupedSet = self.get_grouped_set() @@ -275,6 +348,17 @@ def translatePath(self, Data): return xbmc.translatePath(Data) + def ReplaceSpecialCharecters(self, Data): + if self.KodiVersion <= 18: + Data = unicode(Data, 'utf-8') + Data = Data.encode('utf-8') + Data = quote(Data, safe=u':/'.encode('utf-8')) + else: + Data = quote(Data) + + Data = Data.replace("%", "") + return Data + def PathToFilenameReplaceSpecialCharecters(self, Path): Temp = Path Pos = Temp.rfind("/") @@ -358,11 +442,10 @@ def find(self, dictData, item, beta): return self.find(dictData, item.replace('beta-', ""), False) #Data is a dictionary - def event(self, method, data, sender="plugin.video.emby-next-gen"): - #data = data or {"ServerId" : "default"} + def event(self, method, data): data = '"[%s]"' % json.dumps(data).replace('"', '\\"') - xbmc.executebuiltin('NotifyAll(%s, %s, %s)' % (sender, method, data)) - self.LOG.debug("---[ event: %s/%s ] %s" % (sender, method, data)) + xbmc.executebuiltin('NotifyAll(plugin.video.emby-next-gen, %s, %s)' % (method, data)) + self.LOG.debug("---[ event: plugin.video.emby-next-gen/%s ] %s" % (method, data)) def dialog(self, dialog_type, *args, **kwargs): if "icon" in kwargs: @@ -630,7 +713,7 @@ def convert_to_local(self, date): -#datetime.datetime.now().strftime('%Y-%m-%dT%H:%M:%SZ') +#datetime.now().strftime('%Y-%m-%dT%H:%M:%SZ') except Exception as error: diff --git a/helper/xmls.py b/helper/xmls.py index 5b6963282..a8b7dd642 100644 --- a/helper/xmls.py +++ b/helper/xmls.py @@ -83,10 +83,38 @@ def tvtunes_nfo(self, path, urls): self.Utils.indent(xmlData, 0) self.Utils.write_xml(xml.etree.ElementTree.tostring(xmlData, 'UTF-8'), path) + #Settings table for audio and subtitle tracks. + def load_defaultvideosettings(self): + path = xbmc.translatePath('special://profile/') + FilePath = os.path.join(path, 'guisettings.xml') + xmlData = xml.etree.ElementTree.parse(FilePath).getroot() + default = xmlData.find('defaultvideosettings') + return { + 'Deinterlace': default.find('interlacemethod').text, + 'ViewMode': default.find('viewmode').text, + 'ZoomAmount': default.find('zoomamount').text, + 'PixelRatio': default.find('pixelratio').text, + 'VerticalShift': default.find('verticalshift').text, + 'SubtitleDelay': default.find('subtitledelay').text, + 'ShowSubtitles': default.find('showsubtitles').text == 'true', + 'Brightness': default.find('brightness').text, + 'Contrast': default.find('contrast').text, + 'Gamma': default.find('gamma').text, + 'VolumeAmplification': default.find('volumeamplification').text, + 'AudioDelay': default.find('audiodelay').text, + 'Sharpness': default.find('sharpness').text, + 'NoiseReduction': default.find('noisereduction').text, + 'NonLinStretch': int(default.find('nonlinstretch').text == 'true'), + 'PostProcess': int(default.find('postprocess').text == 'true'), + 'ScalingMethod': default.find('scalingmethod').text, + 'StereoMode': default.find('stereomode').text, + 'CenterMixLevel': default.find('centermixlevel').text + } + #Track the existence of true #It is incompatible with plugin paths. def advanced_settings(self): - if self.Utils.settings('useDirectPaths') != "0": + if self.Utils.direct_path: return path = self.Utils.translatePath('special://profile/') diff --git a/hooks/monitor.py b/hooks/monitor.py index d8627ad83..cea427483 100644 --- a/hooks/monitor.py +++ b/hooks/monitor.py @@ -1,19 +1,21 @@ # -*- coding: utf-8 -*- import json import threading -import uuid +import os import xbmc import xbmcgui +import xbmcvfs +import xbmcaddon -import helper.api import helper.loghandler +import helper.xmls import database.database import database.library import emby.connect -import emby.downloader import hooks.webservice import core.listitem +import core.artwork from . import player try: @@ -35,21 +37,10 @@ def __init__(self, Service): self.WebserviceEventOut = Queue.Queue() self.WebserviceEventIn = Queue.Queue() self.Service = Service - self.ProgressThread = None - self.player = player.PlayerEvents(monitor=self) - self.ItemSkipUpdate = [] - self.ItemSkipUpdateAfterStop = [] - self.ItemSkipUpdateReset = False - self.PlaySessionIdLast = "" - self.PlaySessionId = "" - self.MediasourceID = "" - self.Trailer = False - self.PlayerReloadIndex = "-1" - self.PlayerLastItem = "" - self.PlayerLastItemID = "-1" + self.player = player.PlayerEvents() self.PlayWebsocketPreviousCommand = "" #Propably an issue from Emby Server -> Same command send twice - self.device_id = self.Service.Utils.get_device_id(False) - self.connect = emby.connect.Connect(self) #multipe servers here + self.Xmls = helper.xmls.Xmls(self.Service.Utils) + self.connect = emby.connect.Connect(self.Service.Utils) #multipe servers here!!!!!!!!!!!!!!!!!!!!!!!!!!! def EmbyServer_ReconnectAll(self): for server_id in self.EmbyServer: @@ -74,26 +65,89 @@ def EmbyServer_Connect(self): else: self.EmbyServer[server_id] = EmbyServer self.EmbyServer[server_id].start() - #self.ServerOnline({'ServerId': server_id}) - self.LoadServer({'ServerId': server_id}) + self.ServerOnline({'ServerId': server_id}) return server_id - def Monitor_waitForAbort(self, Data): - self.waitForAbort(Data) + #Add theme media locally, via strm. This is only for tv tunes. + #If another script is used, adjust this code + def SyncThemes(self, data): + library = self.Service.Utils.translatePath("special://profile/addon_data/plugin.video.emby-next-gen/library") + + if not xbmcvfs.exists(library + '/'): + xbmcvfs.mkdir(library) + + if xbmc.getCondVisibility('System.HasAddon(script.tvtunes)'): + tvtunes = xbmcaddon.Addon(id="script.tvtunes") + tvtunes.setSetting('custom_path_enable', "true") + tvtunes.setSetting('custom_path', library) + self.LOG.info("TV Tunes custom path is enabled and set.") + elif xbmc.getCondVisibility('System.HasAddon(service.tvtunes)'): + tvtunes = xbmcaddon.Addon(id="service.tvtunes") + tvtunes.setSetting('custom_path_enable', "true") + tvtunes.setSetting('custom_path', library) + self.LOG.info("TV Tunes custom path is enabled and set.") + else: + self.Service.Utils.dialog("ok", heading="{emby}", line1=self.Service.Utils.Translate(33152)) + return + + with database.database.Database(self.Service.Utils, 'emby', False) as embydb: + all_views = database.emby_db.EmbyDatabase(embydb.cursor).get_views() + views = [x[0] for x in all_views if x[2] in ('movies', 'tvshows', 'mixed')] + + items = {} + + for view in views: + for result in self.EmbyServer[data['ServerId']].API.get_itemsSync(view, None, False, {'HasThemeVideo': True}): + for item in result['Items']: + folder = self.Service.Utils.normalize_string(item['Name']) + items[item['Id']] = folder + + for result in self.EmbyServer[data['ServerId']].API.get_itemsSync(view, None, False, {'HasThemeSong': True}): + for item in result['Items']: + folder = self.Service.Utils.normalize_string(item['Name']) + items[item['Id']] = folder + + for item in items: + nfo_path = os.path.join(library, items[item]) + nfo_file = os.path.join(nfo_path, "tvtunes.nfo") + + if not xbmcvfs.exists(nfo_path): + xbmcvfs.mkdir(nfo_path) + + themes = self.EmbyServer[data['ServerId']].API.get_themes(item) + paths = [] + + for theme in themes['ThemeVideosResult']['Items'] + themes['ThemeSongsResult']['Items']: + if self.Service.Utils.direct_path: + paths.append(theme['MediaSources'][0]['Path']) + else: + paths.append(self.Service.Utils.direct_url(theme)) + + self.Xmls.tvtunes_nfo(nfo_file, paths) + + self.Service.Utils.dialog("notification", heading="{emby}", message=self.Service.Utils.Translate(33153), icon="{emby}", time=1000, sound=False) + + def DatabaseReset(self): + database.database.reset(self.Service.Utils, False) + + def TextureCache(self): + core.artwork.Artwork(None, self.Service.Utils).cache_textures() def LibraryStopAll(self): for server_id in self.library: - self.library[server_id].stop_client() + self.library[server_id].stop_thread = True + + self.library = {} def LibraryStop(self, server_id): if server_id in self.library: - self.library[server_id].stop_client() + self.library[server_id].stop_thread = True del self.library[server_id] def LibraryLoad(self, server_id): if not server_id in self.library: self.ServerOnline({'ServerId': server_id}) - self.library[server_id] = database.library.Library(self, server_id) + self.library[server_id] = database.library.Library(self.player, self.EmbyServer[server_id]) def onScanStarted(self, library): self.LOG.info("-->[ kodi scan/%s ]" % library) @@ -106,7 +160,7 @@ def onSettingsChanged(self): new_thread.start() def onNotification(self, sender, method, data): - if sender.lower() not in ('plugin.video.emby-next-gen', 'xbmc', 'upnextprovider.signal'): + if sender.lower() not in ('plugin.video.emby-next-gen', 'plugin.video.emby', 'xbmc', 'upnextprovider.signal'): return if self.sleep: @@ -116,67 +170,6 @@ def onNotification(self, sender, method, data): new_thread = MonitorWorker(self, sender, method, data) new_thread.start() - def server_instance(self, server_id): - if not self.post_capabilities(server_id): - return False - - if self.Service.Utils.settings('addUsers'): - users = self.Service.Utils.settings('addUsers').split(',') - hidden = None if self.Service.Utils.settings('addUsersHidden.bool') else False - all_users = self.EmbyServer[server_id].API.get_users(hidden=hidden) - - for additional in users: - for user in all_users: - if user['Id'] == additional: - self.EmbyServer[server_id].API.session_add_user(self.EmbyServer[server_id].Data['app.session'], user['Id']) - - self.additional_users(server_id) - - self.ServerOnline({'ServerId': server_id}) - return True - - def post_capabilities(self, server_id): - self.LOG.info("--[ post capabilities/%s ]" % self.EmbyServer[server_id].server_id) - self.EmbyServer[server_id].API.post_capabilities({ - 'PlayableMediaTypes': "Audio,Video", - 'SupportsMediaControl': True, - 'SupportedCommands': ( - "MoveUp,MoveDown,MoveLeft,MoveRight,Select," - "Back,ToggleContextMenu,ToggleFullscreen,ToggleOsdMenu," - "GoHome,PageUp,NextLetter,GoToSearch," - "GoToSettings,PageDown,PreviousLetter,TakeScreenshot," - "VolumeUp,VolumeDown,ToggleMute,SendString,DisplayMessage," - "SetAudioStreamIndex,SetSubtitleStreamIndex," - "SetRepeatMode," - "Mute,Unmute,SetVolume," - "Play,Playstate,PlayNext,PlayMediaSource" - ), - 'IconUrl': "https://raw.githubusercontent.com/MediaBrowser/plugin.video.emby/master/kodi_icon.png" - }) - session = self.EmbyServer[server_id].API.get_device(self.device_id) - - if session: - self.EmbyServer[server_id].Data['app.session'] = session[0]['Id'] - return True - - return False - - def additional_users(self, server_id): - for i in range(10): - self.Service.Utils.window('emby.AdditionalUserImage.%s' % i, clear=True) - - try: - session = self.EmbyServer[server_id].API.get_device(self.device_id) - except Exception as error: - self.LOG.error(error) - return - - for index, user in enumerate(session[0]['AdditionalUsers']): - info = self.EmbyServer[server_id].API.get_user(user['UserId']) - image = helper.api.API(info, self.Service.Utils, self.EmbyServer[server_id].Data['auth.server']).get_user_artwork(user['UserId']) - self.Service.Utils.window('emby.AdditionalUserImage.%s' % index, image) - self.Service.Utils.window('emby.AdditionalUserPosition.%s' % user['UserId'], str(index)) - #Emby playstate updates. def Playstate(self, data): command = data['Command'] @@ -257,15 +250,6 @@ def GeneralCommand(self, data): if command in builtin: xbmc.executebuiltin(builtin[command]) - def LoadServer(self, data): - if not self.server_instance(data['ServerId']): - return False - - self.Service.Utils.window('emby.server.%s.state.json' % data['ServerId'], self.EmbyServer[data['ServerId']].get_state()) - self.Service.Utils.window('emby.servers.json', {data['ServerId'] : 'online'}) - server_ids = self.Service.Utils.window('emby.servers.json') - return True - def StopServer(self, data): self.Service.Utils.window('emby.server.%s.state' % data['ServerId'], clear=True) @@ -273,99 +257,25 @@ def Player_OnAVChange(self, *args, **kwargs): self.ReportProgressRequested(*args, **kwargs) def ReportProgressRequested(self, data): - if not self.Trailer: + if not self.player.Trailer: self.player.report_playback() def Player_OnStop(self, data): for server_id in self.EmbyServer: ######################## WORKAROUND!!!!!!!!!!! break - if self.ProgressThread: - self.ProgressThread.Stop() - self.ProgressThread = None - - self.EmbyServer[server_id].API.close_transcode(self.device_id) - self.Service.SyncPause = False + self.player.OnStop(self.EmbyServer[server_id]) def Player_OnPlay(self, data): - self.Service.SyncPause = True - current_file = self.player.get_playing_file() - for server_id in self.EmbyServer: ######################## WORKAROUND!!!!!!!!!!! break - if not "id" in data['item']: - if 'title' in data['item']: - DynamicItemId = self.Service.Utils.window('emby.DynamicItem_' + current_file) + self.player.OnPlay(data, self.EmbyServer[server_id]) - if not DynamicItemId: - return - else: - return - if self.ProgressThread: - self.ProgressThread.Stop() - self.ProgressThread = None - - if not self.Trailer: - CurrentItem = None - - if current_file: - if not "id" in data['item']: - CurrentItem = dict([ - ('Type', data['item']['type']), - ('Id', DynamicItemId), - ('Path', current_file), - ('MediaSourceId', self.MediasourceID), - ('ServerId', None), - ('Server', self.EmbyServer[server_id]), - ('Paused', False), - ('PlaySessionId', self.PlaySessionId), - ('RunTime', -1), - ('CurrentPosition', -1), - ('DeviceId', self.Service.Utils.get_device_id(False)) - ]) - else: - kodi_id = data['item']['id'] - media_type = data['item']['type'] - item = database.database.get_item(self.Service.Utils, kodi_id, media_type) - - if item: - CurrentItem = dict([ - ('Type', media_type), - ('Id', item[0]), - ('Path', current_file), - ('MediaSourceId', self.MediasourceID), - ('ServerId', None), - ('Server', self.EmbyServer[server_id]), - ('Paused', False), - ('PlaySessionId', self.PlaySessionId), - ('RunTime', -1), - ('CurrentPosition', -1), - ('DeviceId', self.Service.Utils.get_device_id(False)) - ]) - - if CurrentItem: #else native Kodi - #native mode - if not "127.0.0.1" in current_file: - CurrentItem['PlaySessionId'] = str(uuid.uuid4()).replace("-", "") - else: - if self.PlaySessionIdLast == CurrentItem['PlaySessionId']: - for _ in range(60): - xbmc.sleep(500) - if self.PlaySessionIdLast != self.PlaySessionId: - break - CurrentItem['PlaySessionId'] = self.PlaySessionId - CurrentItem['MediaSourceId'] = self.MediasourceID - self.PlaySessionIdLast = CurrentItem['PlaySessionId'] - self.player.set_item(CurrentItem) - - if not self.ProgressThread: - self.ProgressThread = player.ProgressUpdates(self) - self.ProgressThread.start() def AddPlaylistItem(self, Position, EmbyID, server_id, Offset): Data = database.database.get_kodiID(self.Service.Utils, str(EmbyID)) @@ -381,10 +291,10 @@ def AddPlaylistItem(self, Position, EmbyID, server_id, Offset): Pos = self.GetPlaylistPos(Position, playlist, Offset) helper.utils.JSONRPC('Playlist.Insert').execute({'playlistid': playlistID, 'position': Pos, 'item': {'%sid' % Data[0][1]: int(Data[0][0])}}) else: - listitems = core.listitem.ListItem(self.EmbyServer[server_id].auth.get_serveraddress(), self.Service.Utils) + listitems = core.listitem.ListItem(self.EmbyServer[server_id].Data['auth.ssl'], self.Service.Utils) item = self.EmbyServer[server_id].API.get_item(EmbyID) li = xbmcgui.ListItem() - li = listitems.set(item, li, None, False, None) + li = listitems.set(item, li, None, None) path = "" if item['Type'] == "MusicVideo": @@ -422,7 +332,7 @@ def AddPlaylistItem(self, Position, EmbyID, server_id, Offset): playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO) Pos = self.GetPlaylistPos(Position, playlist, Offset) - self.Service.Utils.window('emby.DynamicItem_' + path, item['Id']) + self.Service.Utils.window('emby.DynamicItem_' + self.Service.Utils.ReplaceSpecialCharecters(li.getLabel()), item['Id']) playlist.add(path, li, index=Pos) return playlist @@ -506,17 +416,12 @@ def ServerConnect(self, data): self.EmbyServer_Connect() xbmc.executebuiltin("Container.Refresh") - def EmbyConnect(self, data): - self.connect.setup_login_connect() - def RemoveServer(self, data): + self.EmbyServer[data['ServerId']].close() self.connect.remove_server(data['ServerId']) xbmc.executebuiltin("Container.Refresh") def UserDataChanged(self, data): - if not self.library[data['ServerId']].started: - return - if data.get('UserId') != self.EmbyServer[data['ServerId']].auth.get_server_info()['UserId']: return @@ -524,13 +429,13 @@ def UserDataChanged(self, data): UpdateData = [] for ItemData in data['UserDataList']: - if not ItemData['ItemId'] in self.ItemSkipUpdate: #Check EmbyID + if not ItemData['ItemId'] in self.player.ItemSkipUpdate: #Check EmbyID item = database.database.get_Presentationkey(self.Service.Utils, ItemData['ItemId']) if item: PresentationKey = item.split("-") - if not PresentationKey[0] in self.ItemSkipUpdate: #Check PresentationKey + if not PresentationKey[0] in self.player.ItemSkipUpdate: #Check PresentationKey UpdateData.append(ItemData) else: self.LOG.info("[ skip update/%s ]" % ItemData['ItemId']) @@ -542,9 +447,9 @@ def UserDataChanged(self, data): if UpdateData: self.library[data['ServerId']].userdata(UpdateData) - if self.ItemSkipUpdateReset: - self.ItemSkipUpdateReset = False - self.ItemSkipUpdate = [] + if self.player.ItemSkipUpdateReset: + self.player.ItemSkipUpdateReset = False + self.player.ItemSkipUpdate = [] self.LOG.info("[ skip reset ]") def LibraryChanged(self, data): @@ -553,13 +458,6 @@ def LibraryChanged(self, data): self.library[data['ServerId']].removed(data['ItemsRemoved']) self.library[data['ServerId']].delay_verify(data.get('ItemsVerify', [])) - def RefreshProgress(self, data): - pass - #dialog = xbmcgui.DialogProgressBG() - #dialog.create(self.library.Monitor.Service.Utils.Translate('addon_name'), "%s %s" % (self.library.Monitor.Service.Utils.Translate('gathering'), "Movies")) - #dialog.update(int((float(start_index + index) / TotalRecords) * 100), heading="%s: %s" % (self.library.Monitor.Service.Utils.Translate('addon_name'), library['Name']), message=movie['Name']) - #dialog.close() - def WebSocketRestarting(self, data): self.library[data['ServerId']].get_fast_sync() @@ -596,17 +494,9 @@ def ServerShuttingDown(self, data): if self.Service.ServerReconnectingInProgress(data['ServerId']): return - - - - - self.Service.Utils.dialog("notification", heading="{emby}", message=self.Service.Utils.Translate(33146)) #MSG WRONG!!!! + self.Service.Utils.dialog("notification", heading="{emby}", message="Enable server shutdown") self.Service.Utils.window('emby.server.%s.online.bool' % data['ServerId'], False) - - - - - self.Service.ServerReconnect(data['ServerId']) #CRASH!!!!!!!!!!!!!! + self.Service.ServerReconnect(data['ServerId']) def UserConfigurationUpdated(self, data): self.Service.Views.get_views() @@ -615,15 +505,9 @@ def UserPolicyUpdated(self, data): self.Service.Views.get_views() def SyncLibrary(self, data): - if not data.get('Id'): - return - - self.library[data['ServerId']].add_library(data['Id'], data.get('Update', False)) + self.library[data['ServerId']].add_library(data['Id'], data['Update']) def RepairLibrary(self, data): - if not data.get('Id'): - return - libraries = data['Id'].split(',') for lib in libraries: @@ -655,7 +539,8 @@ def System_OnQuit(self): self.Server = None for server_id in self.EmbyServer: - self.EmbyServer[server_id].API.close_transcode(self.device_id) + if self.player.Transcoding: + self.EmbyServer[server_id].API.close_transcode() self.Service.ShouldStop = True @@ -680,7 +565,7 @@ def WebserviceUpdateInfo(self, server): self.WebserviceOnPlayThread.Stop() self.WebserviceOnPlayThread = None - self.WebserviceOnPlayThread = player.WebserviceOnPlay(self, server) + self.WebserviceOnPlayThread = player.WebserviceOnPlay(self.player, server, self.WebserviceEventIn, self.WebserviceEventOut) self.WebserviceOnPlayThread.start() if self.WebServiceThread: @@ -698,9 +583,9 @@ def QuitThreads(self): self.WebserviceOnPlayThread.Stop() self.WebserviceOnPlayThread = None - if self.ProgressThread: - self.ProgressThread.Stop() - self.ProgressThread = None + if self.player.ProgressThread: + self.player.ProgressThread.Stop() + self.player.ProgressThread = None if self.WebServiceThread: self.WebServiceThread.stop() @@ -708,11 +593,8 @@ def QuitThreads(self): def AddServer(self, data): # self.connect.setup_manual_server() - xbmc.executebuiltin("Container.Refresh") - - def UpdateServer(self, data): - self.Service.Utils.dialog("ok", heading="{emby}", line1=self.Service.Utils.Translate(33151)) - self.connect.setup_manual_server() +# xbmc.executebuiltin("Container.Refresh") + self.EmbyServer_Connect() def SetServerSSL(self, data): self.connect.set_ssl(data['ServerId']) @@ -734,11 +616,11 @@ def System_OnWake(self): self.LOG.info("--<[ sleep ]") self.sleep = False self.EmbyServer_ReconnectAll() - self.Service.SyncPause = False + self.player.SyncPause = False def System_OnSleep(self): self.LOG.info("-->[ sleep ]") - self.Service.SyncPause = True + self.player.SyncPause = True self.QuitThreads() self.EmbyServer_DisconnectAll() self.LibraryStopAll() @@ -760,18 +642,12 @@ def ServerOnline(self, data): self.Service.ReloadSkin = False if self.Service.Utils.settings('connectMsg.bool'): - users = self.EmbyServer[data['ServerId']].API.get_device(self.Service.Utils.get_device_id(False))[0]['AdditionalUsers'] - users = [user['UserName'] for user in users] - users.insert(0, self.Service.Utils.settings('username')) - self.Service.Utils.dialog("notification", heading="{emby}", message="%s %s" % (self.Service.Utils.Translate(33000), ", ".join(users)), icon="{emby}", time=1500, sound=False) - - def AddSkipItem(self, ID): - self.ItemSkipUpdate.append(ID) - self.ItemSkipUpdateAfterStop.append(ID) - - def SetSkipItemAfterStop(self): - self.ItemSkipUpdate = self.ItemSkipUpdateAfterStop - self.ItemSkipUpdateReset = True + users = self.EmbyServer[data['ServerId']].API.get_device()[0] # ['AdditionalUsers'] + users = users['UserName'] +# users = [user['UserName'] for user in users['AdditionalUsers']] +# users.insert(0, self.Service.Utils.settings('username')) +# self.Service.Utils.dialog("notification", heading="{emby}", message="%s %s" % (self.Service.Utils.Translate(33000), ", ".join(users)), icon="{emby}", time=1500, sound=False) + self.Service.Utils.dialog("notification", heading="{emby}", message="%s %s" % (self.Service.Utils.Translate(33000), self.Service.Utils.StringMod(users)), icon="{emby}", time=1500, sound=False) #Mark as watched/unwatched updates def VideoLibrary_OnUpdate(self, data): @@ -790,15 +666,15 @@ def VideoLibrary_OnUpdate(self, data): items = database.database.get_ItemsByPresentationkey(self.Service.Utils, PresentationKey[0]) for item2 in items: - self.ItemSkipUpdate.append(item2[0]) + self.player.ItemSkipUpdate.append(item2[0]) self.EmbyServer[server_id].API.item_played(item2[0], bool(data['playcount'])) return - self.ItemSkipUpdate.append(item[0]) + self.player.ItemSkipUpdate.append(item[0]) self.EmbyServer[server_id].API.item_played(item[0], bool(data['playcount'])) - self.ItemSkipUpdateReset = True + self.player.ItemSkipUpdateReset = True #Thread the monitor so that we can do whatever we need without blocking onNotification. class MonitorWorker(threading.Thread): @@ -826,10 +702,18 @@ def run(self): self.monitor.settingschanged() return + if self.method == 'Other.DatabaseReset': + self.monitor.DatabaseReset() + return + + if self.method == 'Other.TextureCache': + self.monitor.TextureCache() + return + if self.sender == 'plugin.video.emby-next-gen': self.method = self.method.split('.')[1] - if self.method not in ('ReportProgressRequested', 'LoadServer', 'Play', 'Playstate', 'GeneralCommand', 'StopServer', 'RegisterServer', 'ServerOnline', 'ServerConnect', 'EmbyConnect', 'AddServer', 'RemoveServer', 'UpdateServer', 'SetServerSSL', 'UserDataChanged', 'LibraryChanged', 'WebSocketRestarting', 'SyncLibrarySelection', 'RepairLibrarySelection', 'AddLibrarySelection', 'RemoveLibrarySelection', 'SyncLibrary', 'RepairLibrary', 'RemoveLibrary', 'GUI.OnScreensaverDeactivated', 'PatchMusic', 'UserConfigurationUpdated', 'UserPolicyUpdated', 'ServerUnreachable', 'ServerShuttingDown', 'RefreshItem', 'AddFavItem', 'RemoveFavItem', 'ServerRestarting', 'Unauthorized'): + if self.method not in ('ReportProgressRequested', 'Play', 'Playstate', 'GeneralCommand', 'StopServer', 'RegisterServer', 'ServerOnline', 'ServerConnect', 'AddServer', 'RemoveServer', 'SetServerSSL', 'UserDataChanged', 'LibraryChanged', 'WebSocketRestarting', 'SyncLibrarySelection', 'RepairLibrarySelection', 'AddLibrarySelection', 'RemoveLibrarySelection', 'SyncLibrary', 'RepairLibrary', 'RemoveLibrary', 'GUI.OnScreensaverDeactivated', 'PatchMusic', 'UserConfigurationUpdated', 'UserPolicyUpdated', 'ServerUnreachable', 'ServerShuttingDown', 'RefreshItem', 'AddFavItem', 'RemoveFavItem', 'ServerRestarting', 'Unauthorized', 'SyncThemes'): return self.data = json.loads(self.data)[0] diff --git a/hooks/player.py b/hooks/player.py index b787733f8..1c8cea998 100644 --- a/hooks/player.py +++ b/hooks/player.py @@ -8,12 +8,13 @@ import database.database import database.emby_db +import core.queries_videos import helper.utils import helper.loghandler class ProgressUpdates(threading.Thread): - def __init__(self, Monitor): - self.Monitor = Monitor + def __init__(self, Player): + self.Player = Player self.Exit = False threading.Thread.__init__(self) @@ -21,83 +22,184 @@ def Stop(self): self.Exit = True def run(self): - while not self.Exit: - if not self.Monitor.player.report_playback(): - break + while True: + if xbmc.Monitor().waitForAbort(5): + return + + if not self.Exit: + self.Player.report_playback(True) + else: + return - if self.Monitor.waitForAbort(4): - break -#Basic Player class to track progress of Emby content. class PlayerEvents(xbmc.Player): - def __init__(self, monitor): - self.Monitor = monitor - self.Monitor.CurrentlyPlaying = {} + def __init__(self): + self.CurrentlyPlaying = {} self.LOG = helper.loghandler.LOG('EMBY.hooks.player.Player') -# xbmc.Player.__init__(self) + self.Trailer = False + self.PlayerReloadIndex = "-1" + self.PlayerLastItem = "" + self.PlayerLastItemID = "-1" + self.ItemSkipUpdate = [] + self.ItemSkipUpdateAfterStop = [] + self.ItemSkipUpdateReset = False + self.SyncPause = False + self.ProgressThread = None + self.PlaySessionId = "" + self.MediasourceID = "" + self.Transcoding = False + self.CurrentItem = {} + self.SkipUpdate = False + self.PlaySessionIdLast = "" + + #Threaded by Monitor + def OnStop(self, EmbyServer): + if self.ProgressThread: + self.ProgressThread.Stop() + self.ProgressThread = None + + if self.Transcoding: + EmbyServer.API.close_transcode() + + self.SyncPause = False + + #Threaded by Monitor + def OnPlay(self, data, EmbyServer): + self.LOG.info("[ OnPlay ] %s " % data) + + if self.ProgressThread: + self.ProgressThread.Stop() + self.ProgressThread = None + + self.SyncPause = True + + if not self.Trailer: + if not "id" in data['item']: + self.CurrentItem['Id'] = EmbyServer.Utils.window('emby.DynamicItem_' + EmbyServer.Utils.ReplaceSpecialCharecters(data['item']['title'])) + + if not self.CurrentItem['Id']: + self.CurrentItem['Tracking'] = False + return + else: + kodi_id = data['item']['id'] + media_type = data['item']['type'] + item = database.database.get_item(EmbyServer.Utils, kodi_id, media_type) + + if item: + self.CurrentItem['Id'] = item[0] + else: + self.CurrentItem['Tracking'] = False + return #Kodi internal Source + + if EmbyServer.Utils.direct_path: #native mode + self.PlaySessionId = str(uuid.uuid4()).replace("-", "") + + self.CurrentItem['Tracking'] = True + self.CurrentItem['Type'] = data['item']['type'] + self.CurrentItem['Volume'], self.CurrentItem['Muted'] = self.get_volume() + self.CurrentItem['MediaSourceId'] = self.MediasourceID + self.CurrentItem['EmbyServer'] = EmbyServer + self.CurrentItem['RunTime'] = 0 + self.CurrentItem['CurrentPosition'] = 0 + self.CurrentItem['Paused'] = False + self.CurrentItem['MediaSourceId'] = self.MediasourceID + self.CurrentItem['Volume'], self.CurrentItem['Muted'] = self.get_volume() + + def onAVStarted(self): + self.LOG.info("[ onAVStarted ]") + new_thread = PlayerWorker(self, "ThreadAVStarted") + new_thread.start() - #Call when playback start to setup play entry in player tracker. - def set_item(self, PlayItem): + def ThreadAVStarted(self): + self.LOG.info("[ ThreadAVStarted ]") self.stop_playback(True) - PlayItem['Volume'], PlayItem['Muted'] = self.get_volume() - self.Monitor.CurrentlyPlaying = PlayItem - self.LOG.info("-->[ play/%s ] %s" % (PlayItem['Id'], PlayItem)) + + while not self.CurrentItem: #wait for OnPlay + if xbmc.Monitor().waitForAbort(1): + return + + if not self.CurrentItem['Tracking']: + self.CurrentItem = {} + return + + if not self.set_CurrentPosition(): #Stopped directly after started playing + self.LOG.info("[ fast stop detected ]") + return + + self.CurrentItem['PlaySessionId'] = self.PlaySessionId + self.CurrentlyPlaying = self.CurrentItem + self.CurrentItem = {} + self.LOG.info("-->[ play/%s ] %s" % (self.CurrentlyPlaying['Id'], self.CurrentlyPlaying)) data = { - 'ItemId': PlayItem['Id'], - 'MediaSourceId': PlayItem['MediaSourceId'], - 'PlaySessionId': PlayItem['PlaySessionId'] + 'ItemId': self.CurrentlyPlaying['Id'], + 'MediaSourceId': self.CurrentlyPlaying['MediaSourceId'], + 'PlaySessionId': self.CurrentlyPlaying['PlaySessionId'] } #Init session - PlayItem['Server'].API.session_playing(data) - self.report_playback() + self.CurrentlyPlaying['EmbyServer'].API.session_playing(data) + self.SkipUpdate = False + self.report_playback(False) + + if not self.ProgressThread: + self.ProgressThread = ProgressUpdates(self) + self.ProgressThread.start() def SETVolume(self, Volume, Mute): - if not self.Monitor.CurrentlyPlaying: + if not self.CurrentlyPlaying: return - self.Monitor.CurrentlyPlaying['Volume'] = Volume - self.Monitor.CurrentlyPlaying['Muted'] = Mute - self.report_playback() + self.CurrentlyPlaying['Volume'] = Volume + self.CurrentlyPlaying['Muted'] = Mute + self.report_playback(False) - #Report playback progress to emby server. - def report_playback(self): - if not self.Monitor.CurrentlyPlaying: - return True + def set_CurrentPosition(self): + try: + CurrentPosition = int(self.getTime() * 10000000) - if self.Monitor.Trailer: - return True + if CurrentPosition < 0: + CurrentPosition = 0 - if not self.isPlayingVideo(): + self.CurrentlyPlaying['CurrentPosition'] = CurrentPosition + return True + except: return False + def set_Runtime(self): try: - current_time = int(self.getTime()) - TotalTime = int(self.getTotalTime()) + self.CurrentlyPlaying['RunTime'] = int(self.getTotalTime() * 10000000) + return bool(self.CurrentlyPlaying['RunTime']) except: - return False #not playing any file + return False - self.Monitor.CurrentlyPlaying['CurrentPosition'] = current_time * 10000000 + #Report playback progress to emby server. + def report_playback(self, UpdatePosition=True): + if not self.CurrentlyPlaying or self.Trailer or self.SkipUpdate: + self.SkipUpdate = False + return - if self.Monitor.CurrentlyPlaying['RunTime'] == -1: - self.Monitor.CurrentlyPlaying['RunTime'] = TotalTime * 10000000 + if not self.CurrentlyPlaying['RunTime']: + if not self.set_Runtime(): + self.LOG.info("[ skip progress update, no runtime info ]") + return + + if UpdatePosition: + if not self.set_CurrentPosition(): + self.LOG.info("[ skip progress update, no position info ]") + return data = { - 'ItemId': self.Monitor.CurrentlyPlaying['Id'], - 'MediaSourceId': self.Monitor.CurrentlyPlaying['MediaSourceId'], - 'PositionTicks': self.Monitor.CurrentlyPlaying['CurrentPosition'], - 'RunTimeTicks': self.Monitor.CurrentlyPlaying['RunTime'], + 'ItemId': self.CurrentlyPlaying['Id'], + 'MediaSourceId': self.CurrentlyPlaying['MediaSourceId'], + 'PositionTicks': self.CurrentlyPlaying['CurrentPosition'], + 'RunTimeTicks': self.CurrentlyPlaying['RunTime'], 'CanSeek': True, 'QueueableMediaTypes': "Video,Audio", - 'VolumeLevel': self.Monitor.CurrentlyPlaying['Volume'], - 'IsPaused': self.Monitor.CurrentlyPlaying['Paused'], - 'IsMuted': self.Monitor.CurrentlyPlaying['Muted'], - 'PlaySessionId': self.Monitor.CurrentlyPlaying['PlaySessionId'] + 'VolumeLevel': self.CurrentlyPlaying['Volume'], + 'IsPaused': self.CurrentlyPlaying['Paused'], + 'IsMuted': self.CurrentlyPlaying['Muted'], + 'PlaySessionId': self.CurrentlyPlaying['PlaySessionId'] } - self.Monitor.CurrentlyPlaying['Server'].API.session_progress(data) - return True - - def onAVStarted(self): - self.LOG.info("[ onAVStarted ]") + self.CurrentlyPlaying['EmbyServer'].API.session_progress(data) def onAVChange(self): self.LOG.info("[ onAVChange ]") @@ -114,21 +216,21 @@ def onPlayBackStarted(self): def onPlayBackPaused(self): self.LOG.info("[ onPlayBackPaused ]") - if not self.Monitor.CurrentlyPlaying: + if not self.CurrentlyPlaying: return - self.Monitor.CurrentlyPlaying['Paused'] = True + self.CurrentlyPlaying['Paused'] = True self.report_playback() self.LOG.debug("-->[ paused ]") def onPlayBackResumed(self): self.LOG.info("[ onPlayBackResumed ]") - if not self.Monitor.CurrentlyPlaying: + if not self.CurrentlyPlaying: return - self.Monitor.CurrentlyPlaying['Paused'] = False - self.report_playback() + self.CurrentlyPlaying['Paused'] = False + self.report_playback(False) self.LOG.debug("--<[ paused ]") def onPlayBackStopped(self): @@ -137,29 +239,34 @@ def onPlayBackStopped(self): if self.ReloadStream():#Media reload (3D Movie) return - self.Monitor.PlayerLastItemID = "-1" - self.Monitor.PlayerLastItem = "" - self.Monitor.Trailer = False - self.Monitor.Service.SyncPause = True + self.PlayerLastItemID = "-1" + self.PlayerLastItem = "" + self.Trailer = False + self.SyncPause = True self.stop_playback(False) self.LOG.info("--<[ playback ]") def onPlayBackSeek(self, time, seekOffset): self.LOG.info("[ onPlayBackSeek ]") - self.report_playback() + SeekPosition = int(time * 10000) + + if self.CurrentlyPlaying['RunTime']: + if SeekPosition > self.CurrentlyPlaying['RunTime']: + SeekPosition = self.CurrentlyPlaying['RunTime'] + + self.CurrentlyPlaying['CurrentPosition'] = SeekPosition + self.report_playback(False) + self.SkipUpdate = True #Pause progress updates for one cycle -> new seek position def onPlayBackEnded(self): self.LOG.info("[ onPlayBackEnded ]") - if self.Monitor.Trailer: - return - - if self.ReloadStream():#Media reload (3D Movie) + if self.Trailer or self.ReloadStream(): return - self.Monitor.PlayerLastItemID = "-1" - self.Monitor.PlayerLastItem = "" - self.Monitor.Service.SyncPause = True + self.PlayerLastItemID = "-1" + self.PlayerLastItem = "" + self.SyncPause = True self.stop_playback(False) self.LOG.info("--<<[ playback ]") @@ -174,46 +281,57 @@ def onPlayBackError(self): self.LOG.warning("Playback error occured") self.stop_playback(False) - def get_playing_file(self): - if self.isPlaying(): - return self.getPlayingFile() - - return None - def ReloadStream(self): #Media has changed -> reload - if self.Monitor.PlayerReloadIndex != "-1": + if self.PlayerReloadIndex != "-1": playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO) - self.play(item=playlist, startpos=int(self.Monitor.PlayerReloadIndex)) - self.Monitor.PlayerReloadIndex = "-1" + self.play(item=playlist, startpos=int(self.PlayerReloadIndex)) + self.PlayerReloadIndex = "-1" return True return False def stop_playback(self, Init): - if self.Monitor.CurrentlyPlaying: - self.LOG.debug("[ played info ] %s" % self.Monitor.CurrentlyPlaying) + if self.CurrentlyPlaying: + self.LOG.debug("[ played info ] %s" % self.CurrentlyPlaying) data = { - 'ItemId': self.Monitor.CurrentlyPlaying['Id'], - 'MediaSourceId': self.Monitor.CurrentlyPlaying['MediaSourceId'], - 'PositionTicks': self.Monitor.CurrentlyPlaying['CurrentPosition'], - 'PlaySessionId': self.Monitor.CurrentlyPlaying['PlaySessionId'] + 'ItemId': self.CurrentlyPlaying['Id'], + 'MediaSourceId': self.CurrentlyPlaying['MediaSourceId'], + 'PositionTicks': self.CurrentlyPlaying['CurrentPosition'], + + 'PlaySessionId': self.CurrentlyPlaying['PlaySessionId'] } + self.CurrentlyPlaying['EmbyServer'].API.session_stop(data) + + if self.Transcoding: + self.CurrentlyPlaying['EmbyServer'].API.close_transcode() - self.Monitor.CurrentlyPlaying['Server'].API.close_transcode(self.Monitor.CurrentlyPlaying['DeviceId']) - self.Monitor.CurrentlyPlaying['Server'].API.session_stop(data) - self.Monitor.CurrentlyPlaying = {} + self.CurrentlyPlaying = {} if not Init: - self.Monitor.SetSkipItemAfterStop() - self.Monitor.Service.SyncPause = False + self.ItemSkipUpdate = self.ItemSkipUpdateAfterStop + self.ItemSkipUpdateReset = True + self.SyncPause = False + +class PlayerWorker(threading.Thread): + def __init__(self, Player, method): + self.method = method + self.Player = Player + threading.Thread.__init__(self) + + def run(self): + if self.method == 'ThreadAVStarted': + self.Player.ThreadAVStarted() + return #Call from WebSocket to manipulate playing URL class WebserviceOnPlay(threading.Thread): - def __init__(self, Monitor, EmbyServer): + def __init__(self, Player, EmbyServer, WebserviceEventIn, WebserviceEventOut): self.LOG = helper.loghandler.LOG('EMBY.hooks.player.WebserviceOnPlay') - self.Monitor = Monitor self.EmbyServer = EmbyServer + self.WebserviceEventIn = WebserviceEventIn + self.WebserviceEventOut = WebserviceEventOut + self.Player = Player self.Intros = None self.IntrosIndex = 0 self.Exit = False @@ -223,33 +341,22 @@ def __init__(self, Monitor, EmbyServer): self.URLQuery = "" self.Type = "" self.KodiID = -1 + self.KodiFileID = -1 self.Force = False self.Filename = "" self.MediaSources = [] self.TranscodeReasons = "" self.TargetVideoBitrate = 0 self.TargetAudioBitrate = 0 - Codec = ["h264", "hevc"] - ID = self.Monitor.Service.Utils.settings('TranscodeFormatVideo') - self.VideoCodec = "&VideoCodec=" + Codec[int(ID)] - Codec = ["aac", "ac3"] - ID = self.Monitor.Service.Utils.settings('TranscodeFormatAudio') - self.AudioCodec = "&AudioCodec=" + Codec[int(ID)] - self.TranscodeH265 = self.Monitor.Service.Utils.settings('transcode_h265.bool') - self.TranscodeDivx = self.Monitor.Service.Utils.settings('transcodeDivx.bool') - self.TranscodeXvid = self.Monitor.Service.Utils.settings('transcodeXvid.bool') - self.TranscodeMpeg2 = self.Monitor.Service.Utils.settings('transcodeMpeg2.bool') - self.EnableCinema = self.Monitor.Service.Utils.settings('enableCinema.bool') - self.AskCinema = self.Monitor.Service.Utils.settings('askCinema.bool') threading.Thread.__init__(self) def Stop(self): self.Exit = True - self.Monitor.WebserviceEventOut.put("quit") + self.WebserviceEventOut.put("quit") def run(self): while not self.Exit: - IncommingData = self.Monitor.WebserviceEventOut.get() + IncommingData = self.WebserviceEventOut.get() self.LOG.debug("[ query IncommingData ] %s" % IncommingData) if IncommingData == "quit": @@ -258,11 +365,11 @@ def run(self): self.EmbyID, MediasourceID, self.Type, BitrateFromURL, self.Filename = self.GetParametersFromURLQuery(IncommingData) if 'audio' in IncommingData: - self.Monitor.WebserviceEventIn.put(self.EmbyServer.auth.get_serveraddress() + "/emby/audio/" + self.EmbyID + "/stream?static=true&PlaySessionId=" + self.GETPlaySessionId("") + "&DeviceId=" + self.Monitor.device_id + "&api_key=" + self.EmbyServer.Data['auth.token'] + "&" + self.Filename) + self.WebserviceEventIn.put(self.EmbyServer.auth.get_serveraddress() + "/emby/audio/" + self.EmbyID + "/stream?static=true&PlaySessionId=" + self.GETPlaySessionId("") + "&DeviceId=" + self.EmbyServer.Data['app.device_id'] + "&api_key=" + self.EmbyServer.Data['auth.token'] + "&" + self.Filename) continue if 'livetv' in IncommingData: - self.Monitor.WebserviceEventIn.put(self.EmbyServer.auth.get_serveraddress() + "/emby/videos/" + self.EmbyID + "/stream.ts?PlaySessionId=" + self.GETPlaySessionId("") + "&DeviceId=" + self.Monitor.device_id + "&api_key=" + self.EmbyServer.Data['auth.token'] + "&" + self.Filename) + self.WebserviceEventIn.put(self.EmbyServer.auth.get_serveraddress() + "/emby/videos/" + self.EmbyID + "/stream.ts?PlaySessionId=" + self.GETPlaySessionId("") + "&DeviceId=" + self.EmbyServer.Data['app.device_id'] + "&api_key=" + self.EmbyServer.Data['auth.token'] + "&" + self.Filename) continue if 'main.m3u8' in IncommingData: #Dynamic Transcode query @@ -271,9 +378,13 @@ def run(self): IncommingData = IncommingData.replace("/tvshow/", "/") IncommingData = IncommingData.replace("/video/", "/") IncommingData = IncommingData.replace("/trailer/", "/") - self.Monitor.WebserviceEventIn.put(self.EmbyServer.auth.get_serveraddress() + "/emby/videos/" + self.EmbyIDLast + IncommingData) + self.WebserviceEventIn.put(self.EmbyServer.auth.get_serveraddress() + "/emby/videos/" + self.EmbyIDLast + IncommingData) continue + if self.Player.Transcoding: + self.EmbyServer.API.close_transcode() + + self.Player.Transcoding = False self.URLQuery = "http://127.0.0.1:57578" + IncommingData if self.Type == "movies": @@ -283,90 +394,92 @@ def run(self): elif self.Type == "musicvideos": self.Type = "musicvideo" - self.Monitor.Service.SyncPause = True + self.Player.SyncPause = True #Reload Playlistitem after playlist injection - if self.Monitor.PlayerReloadIndex != "-1": + if self.Player.PlayerReloadIndex != "-1": URL = "RELOAD" - self.Monitor.WebserviceEventIn.put(URL) + self.WebserviceEventIn.put(URL) continue #Todo: SKIP TRAILERS IF MULTIPART! #Trailers - if self.EnableCinema and self.Monitor.PlayerLastItemID != self.EmbyID: + if self.EmbyServer.Utils.EnableCinema and self.Player.PlayerLastItemID != self.EmbyID: PlayTrailer = True - if self.AskCinema: - if not self.Monitor.Trailer: + if self.EmbyServer.Utils.AskCinema: + if not self.Player.Trailer: self.Trailers = False - if not self.Trailers and not self.Monitor.Trailer: + if not self.Trailers and not self.Player.Trailer: self.Trailers = True - PlayTrailer = self.Monitor.Service.Utils.dialog("yesno", heading="{emby}", line1=self.Monitor.Service.Utils.Translate(33016)) + PlayTrailer = self.EmbyServer.Utils.dialog("yesno", heading="{emby}", line1=self.EmbyServer.Utils.Translate(33016)) if PlayTrailer: - if self.Monitor.PlayerLastItem != IncommingData or not self.Monitor.Trailer: + if self.Player.PlayerLastItem != IncommingData or not self.Player.Trailer: xbmc.executeJSONRPC('{ "jsonrpc": "2.0", "method": "Player.SetRepeat", "params": {"playerid": 1, "repeat": "one" }, "id": 1 }') - self.Monitor.PlayerLastItem = IncommingData + self.Player.PlayerLastItem = IncommingData self.IntrosIndex = 0 self.Trailers = False self.Intros = self.EmbyServer.API.get_intros(self.EmbyID) #self.IntrosLocal = self.EmbyServer.API.get_local_trailers(self.EmbyID) - self.Monitor.Trailer = True + self.Player.Trailer = True try: #Play next trailer - self.Monitor.WebserviceEventIn.put(self.Intros['Items'][self.IntrosIndex]['Path']) + self.WebserviceEventIn.put(self.Intros['Items'][self.IntrosIndex]['Path']) self.IntrosIndex += 1 continue except: #No more trailers xbmc.executeJSONRPC('{ "jsonrpc": "2.0", "method": "Player.SetRepeat", "params": {"playerid": 1, "repeat": "off" }, "id": 1 }') self.Force = True - self.Monitor.PlayerLastItem = "" + self.Player.PlayerLastItem = "" self.Intros = None self.IntrosIndex = 0 self.Trailers = False - self.Monitor.Trailer = False + self.Player.Trailer = False else: xbmc.executeJSONRPC('{ "jsonrpc": "2.0", "method": "Player.SetRepeat", "params": {"playerid": 1, "repeat": "off" }, "id": 1 }') #Select mediasources, Audiostreams, Subtitles - if self.Monitor.PlayerLastItemID != self.EmbyID or self.Force: + if self.Player.PlayerLastItemID != self.EmbyID or self.Force: self.Force = False - self.Monitor.PlayerLastItemID = str(self.EmbyID) + self.Player.PlayerLastItemID = str(self.EmbyID) - with database.database.Database(self.Monitor.Service.Utils, 'emby', False) as embydb: + with database.database.Database(self.EmbyServer.Utils, 'emby', False) as embydb: emby_dbT = database.emby_db.EmbyDatabase(embydb.cursor) EmbyDBItem = emby_dbT.get_kodiid(self.EmbyID) if EmbyDBItem: #Item not synced to Kodi DB if EmbyDBItem[1]: PresentationKey = EmbyDBItem[1].split("-") - self.Monitor.AddSkipItem(PresentationKey[0]) + self.Player.ItemSkipUpdate.append(PresentationKey[0]) + self.Player.ItemSkipUpdateAfterStop.append(PresentationKey[0]) self.KodiID = str(EmbyDBItem[0]) + self.KodiFileID = str(EmbyDBItem[2]) else: - self.Monitor.PlayerReloadIndex = "-1" - self.Monitor.PlayerLastItem = "" + self.Player.PlayerReloadIndex = "-1" + self.Player.PlayerLastItem = "" self.Intros = None self.IntrosIndex = 0 self.Trailers = False - self.Monitor.Trailer = False + self.Player.Trailer = False self.SubTitlesAdd(MediasourceID, emby_dbT) - Transcoding = self.IsTranscoding(BitrateFromURL, None) + self.Player.Transcoding = self.IsTranscoding(BitrateFromURL, None) - if Transcoding: + if self.Player.Transcoding: URL = self.GETTranscodeURL(MediasourceID, self.Filename, False, False) else: - URL = self.EmbyServer.auth.get_serveraddress() + "/emby/videos/" + self.EmbyID + "/stream?static=true&MediaSourceId=" + MediasourceID + "&PlaySessionId=" + self.GETPlaySessionId(MediasourceID) + "&DeviceId=" + self.Monitor.device_id + "&api_key=" + self.EmbyServer.Data['auth.token'] + "&" + self.Filename + URL = self.EmbyServer.auth.get_serveraddress() + "/emby/videos/" + self.EmbyID + "/stream?static=true&MediaSourceId=" + MediasourceID + "&PlaySessionId=" + self.GETPlaySessionId(MediasourceID) + "&DeviceId=" + self.EmbyServer.Data['app.device_id'] + "&api_key=" + self.EmbyServer.Data['auth.token'] + "&" + self.Filename - self.Monitor.WebserviceEventIn.put(URL) + self.WebserviceEventIn.put(URL) continue self.MediaSources = emby_dbT.get_mediasource(self.EmbyID) if len(self.MediaSources) == 1: - self.Monitor.PlayerLastItemID = "-1" - self.Monitor.WebserviceEventIn.put(self.LoadData(MediasourceID, emby_dbT, 0)) + self.Player.PlayerLastItemID = "-1" + self.WebserviceEventIn.put(self.LoadData(MediasourceID, emby_dbT, 0)) continue #Multiversion @@ -375,14 +488,14 @@ def run(self): for Data in self.MediaSources: Selection.append(Data[8] + " - " + self.SizeToText(float(Data[7]))) - MediaIndex = self.Monitor.Service.Utils.dialog("select", heading="Select Media Source:", list=Selection) + MediaIndex = self.EmbyServer.Utils.dialog("select", heading="Select Media Source:", list=Selection) if MediaIndex <= 0: MediaIndex = 0 - self.Monitor.PlayerLastItemID = "-1" + self.Player.PlayerLastItemID = "-1" MediasourceID = self.MediaSources[MediaIndex][3] - self.Monitor.WebserviceEventIn.put(self.LoadData(MediasourceID, emby_dbT, MediaIndex)) + self.WebserviceEventIn.put(self.LoadData(MediasourceID, emby_dbT, MediaIndex)) #Load SRT subtitles def SubTitlesAdd(self, MediasourceID, emby_dbT): @@ -396,19 +509,29 @@ def SubTitlesAdd(self, MediasourceID, emby_dbT): if Data[3] == "srt": SubTitleURL = self.EmbyServer.auth.get_serveraddress() + "/emby/videos/" + self.EmbyID + "/" + MediasourceID + "/Subtitles/" + str(Data[18]) + "/stream.srt" + request = {'type': "GET", 'url': SubTitleURL, 'params': {}} + + #Get Subtitle Settings + with database.database.Database(self.EmbyServer.Utils, 'video', False) as videodb: + videodb.cursor.execute(core.queries_videos.get_settings, (self.KodiFileID,)) + FileSettings = videodb.cursor.fetchone() - request = { - 'type': "GET", - 'url': SubTitleURL, - 'params': {} - } + if FileSettings: + EnableSubtitle = bool(FileSettings[9]) + else: + EnableSubtitle = False #Read default value + + if Data[4]: + SubtileLanguage = Data[4] + else: + SubtileLanguage = "unknown" - Filename = self.Monitor.Service.Utils.PathToFilenameReplaceSpecialCharecters(str(CounterSubTitle) + "." + Data[4] + ".srt") - Path = self.Monitor.Service.Utils.download_external_subs(request, Filename, self.EmbyServer) + Filename = self.EmbyServer.Utils.PathToFilenameReplaceSpecialCharecters(str(CounterSubTitle) + "." + SubtileLanguage + ".srt") + Path = self.EmbyServer.Utils.download_external_subs(request, Filename, self.EmbyServer) if Path: - self.Monitor.player.setSubtitles(Path) - self.Monitor.player.showSubtitles(False) + self.Player.setSubtitles(Path) + self.Player.showSubtitles(EnableSubtitle) def LoadData(self, MediasourceID, emby_dbT, MediaIndex): VideoStreams = emby_dbT.get_videostreams(self.EmbyID, MediaIndex) @@ -416,12 +539,12 @@ def LoadData(self, MediasourceID, emby_dbT, MediaIndex): if not VideoStreams: self.LOG.warning("[ VideoStreams not found ] %s" % self.EmbyID) - return self.EmbyServer.auth.get_serveraddress() + "/emby/videos/" + self.EmbyID + "/stream?static=true&MediaSourceId=" + MediasourceID + "&PlaySessionId=" + self.GETPlaySessionId(MediasourceID) + "&DeviceId=" + self.Monitor.device_id + "&api_key=" + self.EmbyServer.Data['auth.token'] + "&" + self.Filename + return self.EmbyServer.auth.get_serveraddress() + "/emby/videos/" + self.EmbyID + "/stream?static=true&MediaSourceId=" + MediasourceID + "&PlaySessionId=" + self.GETPlaySessionId(MediasourceID) + "&DeviceId=" + self.EmbyServer.Data['app.device_id'] + "&api_key=" + self.EmbyServer.Data['auth.token'] + "&" + self.Filename Bitrate = VideoStreams[0][9] - Transcoding = self.IsTranscoding(Bitrate, VideoStreams[0][3]) #add codec from videostreams, Bitrate (from file) + self.Player.Transcoding = self.IsTranscoding(Bitrate, VideoStreams[0][3]) #add codec from videostreams, Bitrate (from file) - if Transcoding: + if self.Player.Transcoding: SubtitleIndex = -1 AudioIndex = -1 Subtitles = [] @@ -433,7 +556,7 @@ def LoadData(self, MediasourceID, emby_dbT, MediaIndex): for Data in AudioStreams: Selection.append(Data[7]) - AudioIndex = self.Monitor.Service.Utils.dialog("select", heading="Select Audio Stream:", list=Selection) + AudioIndex = self.EmbyServer.Utils.dialog("select", heading="Select Audio Stream:", list=Selection) if len(Subtitles) >= 1: Selection = [] @@ -441,7 +564,7 @@ def LoadData(self, MediasourceID, emby_dbT, MediaIndex): for Data in Subtitles: Selection.append(Data[7]) - SubtitleIndex = self.Monitor.Service.Utils.dialog("select", heading="Select Subtitle:", list=Selection) + SubtitleIndex = self.EmbyServer.Utils.dialog("select", heading="Select Subtitle:", list=Selection) if AudioIndex <= 0 and SubtitleIndex < 0 and MediaIndex <= 0: #No change -> resume return self.GETTranscodeURL(MediasourceID, self.Filename, False, False) @@ -454,13 +577,13 @@ def LoadData(self, MediasourceID, emby_dbT, MediaIndex): else: Subtitle = Subtitles[SubtitleIndex] - return self.UpdateItem(MediasourceID, Transcoding, self.MediaSources[MediaIndex], VideoStreams[0], AudioStreams[AudioIndex], emby_dbT, Subtitle) + return self.UpdateItem(MediasourceID, self.MediaSources[MediaIndex], VideoStreams[0], AudioStreams[AudioIndex], emby_dbT, Subtitle) if MediaIndex == 0: self.SubTitlesAdd(MediasourceID, emby_dbT) - return self.EmbyServer.auth.get_serveraddress() + "/emby/videos/" + self.EmbyID + "/stream?static=true&MediaSourceId=" + MediasourceID + "&PlaySessionId=" + self.GETPlaySessionId(MediasourceID) + "&DeviceId=" + self.Monitor.device_id + "&api_key=" + self.EmbyServer.Data['auth.token'] + "&" + self.Filename + return self.EmbyServer.auth.get_serveraddress() + "/emby/videos/" + self.EmbyID + "/stream?static=true&MediaSourceId=" + MediasourceID + "&PlaySessionId=" + self.GETPlaySessionId(MediasourceID) + "&DeviceId=" + self.EmbyServer.Data['app.device_id'] + "&api_key=" + self.EmbyServer.Data['auth.token'] + "&" + self.Filename - return self.UpdateItem(MediasourceID, Transcoding, self.MediaSources[MediaIndex], VideoStreams[0], AudioStreams[0], emby_dbT, False) + return self.UpdateItem(MediasourceID, self.MediaSources[MediaIndex], VideoStreams[0], AudioStreams[0], emby_dbT, False) def GETTranscodeURL(self, MediasourceID, Filename, Audio, Subtitle): TranscodingVideo = "" @@ -485,7 +608,7 @@ def GETTranscodeURL(self, MediasourceID, Filename, Audio, Subtitle): if Filename: Filename = "&" + Filename - return self.EmbyServer.auth.get_serveraddress() + "/emby/videos/" + self.EmbyID + "/master.m3u8?api_key=" + self.EmbyServer.Data['auth.token'] + "&MediaSourceId=" + MediasourceID + "&PlaySessionId=" + self.GETPlaySessionId(MediasourceID) + "&DeviceId=" + self.Monitor.device_id + self.VideoCodec + self.AudioCodec + TranscodingVideo + TranscodingAudio + Audio + Subtitle + "&TranscodeReasons=" + self.TranscodeReasons + Filename + return self.EmbyServer.auth.get_serveraddress() + "/emby/videos/" + self.EmbyID + "/master.m3u8?api_key=" + self.EmbyServer.Data['auth.token'] + "&MediaSourceId=" + MediasourceID + "&PlaySessionId=" + self.GETPlaySessionId(MediasourceID) + "&DeviceId=" + self.EmbyServer.Data['app.device_id'] + "&VideoCodec=" + self.EmbyServer.Utils.VideoCodecID + "&AudioCodec=" + self.EmbyServer.Utils.AudioCodecID + TranscodingVideo + TranscodingAudio + Audio + Subtitle + "&TranscodeReasons=" + self.TranscodeReasons + Filename def SizeToText(self, size): suffixes = ['B', 'KB', 'MB', 'GB', 'TB'] @@ -498,38 +621,38 @@ def SizeToText(self, size): return "%.*f%s" % (2, size, suffixes[suffixIndex]) def GETPlaySessionId(self, MediasourceID): - self.Monitor.PlaySessionId = str(uuid.uuid4()).replace("-", "") - self.Monitor.MediasourceID = MediasourceID - return self.Monitor.PlaySessionId + self.Player.PlaySessionId = str(uuid.uuid4()).replace("-", "") + self.Player.MediasourceID = MediasourceID + return self.Player.PlaySessionId def IsTranscoding(self, Bitrate, Codec): - if self.TranscodeH265: + if self.EmbyServer.Utils.TranscodeH265: if Codec in ("h265", "hevc"): self.IsTranscodingByCodec(Bitrate) return True - elif self.TranscodeDivx: + elif self.EmbyServer.Utils.TranscodeDivx: if Codec == "msmpeg4v3": self.IsTranscodingByCodec(Bitrate) return True - elif self.TranscodeXvid: + elif self.EmbyServer.Utils.TranscodeXvid: if Codec == "mpeg4": self.IsTranscodingByCodec(Bitrate) return True - elif self.TranscodeMpeg2: + elif self.EmbyServer.Utils.TranscodeMpeg2: if Codec == "mpeg2video": self.IsTranscodingByCodec(Bitrate) return True - self.TargetVideoBitrate = self.Monitor.Service.Utils.VideoBitrate - self.TargetAudioBitrate = self.Monitor.Service.Utils.AudioBitrate + self.TargetVideoBitrate = self.EmbyServer.Utils.VideoBitrate + self.TargetAudioBitrate = self.EmbyServer.Utils.AudioBitrate self.TranscodeReasons = "ContainerBitrateExceedsLimit" return Bitrate >= self.TargetVideoBitrate def IsTranscodingByCodec(self, Bitrate): - if Bitrate >= self.Monitor.Service.Utils.VideoBitrate: + if Bitrate >= self.EmbyServer.Utils.VideoBitrate: self.TranscodeReasons = "ContainerBitrateExceedsLimit" - self.TargetVideoBitrate = self.Monitor.Service.Utils.VideoBitrate - self.TargetAudioBitrate = self.Monitor.Service.Utils.AudioBitrate + self.TargetVideoBitrate = self.EmbyServer.Utils.VideoBitrate + self.TargetAudioBitrate = self.EmbyServer.Utils.AudioBitrate else: self.TranscodeReasons = "VideoCodecNotSupported" self.TargetVideoBitrate = 0 @@ -550,13 +673,14 @@ def GetParametersFromURLQuery(self, StreamURL): except: BitrateFromURL = 0 - self.Monitor.Service.SyncPause = True - self.Monitor.AddSkipItem(Data[0]) + self.Player.SyncPause = True + self.Player.ItemSkipUpdate.append(Data[0]) + self.Player.ItemSkipUpdateAfterStop.append(Data[0]) return Data[0], Data[1], Type, BitrateFromURL, Filename return None, None, None, None, None - def UpdateItem(self, MediasourceID, Transcoding, MediaSource, VideoStream, AudioStream, emby_dbT, Subtitle): + def UpdateItem(self, MediasourceID, MediaSource, VideoStream, AudioStream, emby_dbT, Subtitle): if self.Type == "movie": result = xbmc.executeJSONRPC('{"jsonrpc":"2.0", "id":1, "method":"VideoLibrary.GetMovieDetails", "params":{"movieid":' + self.KodiID + ', "properties":["title", "playcount", "plot", "genre", "year", "rating", "director", "trailer", "tagline", "plotoutline", "originaltitle", "writer", "studio", "mpaa", "country", "imdbnumber", "set", "showlink", "top250", "votes", "sorttitle", "dateadded", "tag", "userrating", "cast", "premiered", "setid", "art", "lastplayed", "uniqueid"]}}') Data = json.loads(result) @@ -573,18 +697,17 @@ def UpdateItem(self, MediasourceID, Transcoding, MediaSource, VideoStream, Audio Details['mediatype'] = self.Type playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO) - Index = playlist.getposition() - Filename = self.Monitor.Service.Utils.PathToFilenameReplaceSpecialCharecters(MediaSource[4]) + Filename = self.EmbyServer.Utils.PathToFilenameReplaceSpecialCharecters(MediaSource[4]) if Subtitle: SubtitleStream = str(int(Subtitle[2]) + 2) else: SubtitleStream = "" - if Transcoding: + if self.Player.Transcoding: URL = self.GETTranscodeURL(MediasourceID, Filename, str(int(AudioStream[2]) + 1), SubtitleStream) else: #stream - URL = self.EmbyServer.auth.get_serveraddress() + "/emby/videos/" + self.EmbyID +"/stream?static=true&api_key=" + self.EmbyServer.Data['auth.token'] + "&MediaSourceId=" + MediasourceID + "&PlaySessionId=" + self.GETPlaySessionId("") + "&DeviceId=" + self.Monitor.device_id + "&" + Filename + URL = self.EmbyServer.auth.get_serveraddress() + "/emby/videos/" + self.EmbyID +"/stream?static=true&api_key=" + self.EmbyServer.Data['auth.token'] + "&MediaSourceId=" + MediasourceID + "&PlaySessionId=" + self.GETPlaySessionId("") + "&DeviceId=" + self.EmbyServer.Data['app.device_id'] + "&" + Filename if "3d" in MediaSource[8].lower(): item = xbmcgui.ListItem(Details['title'], path=URL) @@ -618,15 +741,16 @@ def UpdateItem(self, MediasourceID, Transcoding, MediaSource, VideoStream, Audio item.addStreamInfo('subtitle', {'language' : Subtitle[4]}) if "3d" in MediaSource[8].lower(): + Index = playlist.getposition() playlist.add(URL, item, Index) xbmc.executeJSONRPC('{"jsonrpc":"2.0", "method":"Playlist.Remove", "params":{"playlistid":1, "position":' + str(Index + 1) + '}}') - self.Monitor.PlayerReloadIndex = str(Index) - self.Monitor.PlayerLastItemID = str(self.EmbyID) + self.Player.PlayerReloadIndex = str(Index) + self.Player.PlayerLastItemID = str(self.EmbyID) URL = "RELOAD" else: - self.Monitor.player.updateInfoTag(item) + self.Player.updateInfoTag(item) self.SubTitlesAdd(MediasourceID, emby_dbT) - self.Monitor.PlayerReloadIndex = "-1" - self.Monitor.PlayerLastItemID = "-1" + self.Player.PlayerReloadIndex = "-1" + self.Player.PlayerLastItemID = "-1" return URL diff --git a/resources/settings.xml b/resources/settings.xml index ffccb5c55..543cb1f6f 100644 --- a/resources/settings.xml +++ b/resources/settings.xml @@ -4,11 +4,21 @@ + + + + + + - + + + + + @@ -23,15 +33,12 @@ - + - - - @@ -76,7 +83,6 @@ - diff --git a/service.py b/service.py index f5b6a630e..d77a34de5 100644 --- a/service.py +++ b/service.py @@ -13,19 +13,17 @@ def __init__(self): self.LOG = helper.loghandler.LOG('EMBY.entrypoint.Service') self.ShouldStop = False self.ReloadSkin = True - self.SyncPause = False self.Startup() def Startup(self): self.ShouldStop = False self.ReloadSkin = True - self.SyncPause = False self.Utils = helper.utils.Utils() - self.Setup = helper.setup.Setup(self) + self.Setup = helper.setup.Setup(self.Utils) self.Delay = int(self.Utils.settings('startupDelay')) self.LOG.warning("--->>>[ %s ]" % self.Utils.addon_name) self.Monitor = hooks.monitor.Monitor(self) - database.database.test_databases(self.Utils) + database.database.EmbyDatabaseBuild(self.Utils) Xmls = helper.xmls.Xmls(self.Utils) Xmls.advanced_settings_add_timeouts() self.Utils.settings('groupedSets.bool', self.Utils.GroupedSet) @@ -46,20 +44,19 @@ def ServerConnect(self): if not server_id: return False - self.Setup.setup() + self.ReloadSkin = self.Setup.setup() self.Monitor.LibraryLoad(server_id) return True def ServerReconnectingInProgress(self, server_id): if server_id in self.ServerReconnecting: - if self.ServerReconnecting[server_id]: - return True + return self.ServerReconnecting[server_id] return False def ServerReconnect(self, server_id, Terminate=True): self.ServerReconnecting[server_id] = True - self.SyncPause = False + self.Monitor.player.SyncPause = False if Terminate: if server_id in self.Monitor.EmbyServer: @@ -77,7 +74,7 @@ def ServerReconnect(self, server_id, Terminate=True): break self.Monitor.LibraryLoad(server_id) - self.ServerReconnecting[server_id] = True + self.ServerReconnecting[server_id] = False def WatchDog(self): while True: @@ -104,7 +101,7 @@ def WatchDog(self): def shutdown(self): self.LOG.warning("---<[ EXITING ]") - self.SyncPause = True + self.Monitor.player.SyncPause = True self.ShouldStop = True self.Monitor.QuitThreads() self.Monitor.EmbyServer_DisconnectAll() @@ -125,8 +122,9 @@ def restart(self): serviceOBJ = Service() while True: - if not serviceOBJ.ServerConnect(): - break + serviceOBJ.ServerConnect() +# if not serviceOBJ.ServerConnect(): +# break if serviceOBJ.WatchDog(): serviceOBJ.Startup()