def album(self, item, e_item): ''' Update object to kodi. ''' server_address = self.server.auth.get_server_info( self.server.auth.server_id)['address'] API = api.API(item, server_address) obj = self.objects.map(item, 'Album') update = True try: obj['AlbumId'] = e_item[0] except TypeError: update = False obj['AlbumId'] = None LOG.debug("AlbumId %s not found", obj['Id']) else: if self.validate_album( *values(obj, QU.get_album_by_id_obj)) is None: update = False LOG.info("AlbumId %s missing from kodi. repairing the entry.", obj['AlbumId']) obj['Rating'] = 0 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['Artists'] = " / ".join(obj['Artists'] or []) obj['Artwork'] = API.get_all_artwork( self.objects.map(item, 'ArtworkMusic'), True) obj['Thumb'] = obj['Artwork']['Primary'] if obj['Thumb']: obj['Thumb'] = "<thumb>%s</thumb>" % obj['Thumb'] if update: self.album_update(obj) else: self.album_add(obj) self.artist_link(obj) self.artist_discography(obj) self.update_album(*values(obj, QU.update_album_obj)) self.add_genres(*values(obj, QU.add_genres_obj)) self.artwork.add(obj['Artwork'], obj['AlbumId'], "album") self.item_ids.append(obj['Id'])
def next_up(self): item = self.get_file_info(self.get_playing_file()) objects = Objects() if item['Type'] != 'Episode' or not item.get('CurrentEpisode'): return next_items = item['Server'].jellyfin.get_adjacent_episodes( item['CurrentEpisode']['tvshowid'], item['Id']) for index, next_item in enumerate(next_items['Items']): if next_item['Id'] == item['Id']: try: next_item = next_items['Items'][index + 1] except IndexError: LOG.warning("No next up episode.") return break server_address = item['Server'].auth.get_server_info( item['Server'].auth.server_id)['address'] API = api.API(next_item, server_address) data = objects.map(next_item, "UpNext") artwork = API.get_all_artwork(objects.map(next_item, 'ArtworkParent'), True) data['art'] = { 'tvshow.poster': artwork.get('Series.Primary'), 'tvshow.fanart': None, 'thumb': artwork.get('Primary') } if artwork['Backdrop']: data['art']['tvshow.fanart'] = artwork['Backdrop'][0] next_info = { 'play_info': { 'ItemIds': [data['episodeid']], 'ServerId': item['ServerId'], 'PlayCommand': 'PlayNow' }, 'current_episode': item['CurrentEpisode'], 'next_episode': data } LOG.info("--[ next up ] %s", next_info) event("upnext_data", next_info, hexlify=True)
def window_artwork(self, prop, view_id): if not self.server.logged_in: window('%s.artwork' % prop, clear=True) elif self.server.logged_in and self.media_folders is not None: for library in self.media_folders: if library['Id'] == view_id and 'Primary' in library.get('ImageTags', {}): server_address = self.server.auth.get_server_info(self.server.auth.server_id)['address'] artwork = api.API(None, server_address).get_artwork(view_id, 'Primary') window('%s.artwork' % prop, artwork) break else: window('%s.artwork' % prop, clear=True)
def get_user(self, client): ''' Save user info. ''' self.user = client['api'].get_user() self.config = client['api'].get_system_info() settings('username', self.user['Name']) settings('SeasonSpecials.bool', self.config.get('DisplaySpecialsWithinSeasons', True)) if 'PrimaryImageTag' in self.user: window( 'EmbyUserImage', api.API(self.user, client['auth/server-address']).get_user_artwork( self.user['Id']))
def run(self): with self.lock, self.database as kodidb, Database('jellyfin') as jellyfindb: while True: try: item = self.queue.get(timeout=1) except Queue.Empty: break default_args = (self.server, jellyfindb, kodidb, self.direct_path) if item['Type'] == 'Movie': obj = Movies(*default_args).movie elif item['Type'] == 'Boxset': obj = Movies(*default_args).boxset elif item['Type'] == 'Series': obj = TVShows(*default_args).tvshow elif item['Type'] == 'Season': obj = TVShows(*default_args).season elif item['Type'] == 'Episode': obj = TVShows(*default_args).episode elif item['Type'] == 'MusicVideo': obj = MusicVideos(*default_args).musicvideo elif item['Type'] == 'MusicAlbum': obj = Music(*default_args).album elif item['Type'] == 'MusicArtist': obj = Music(*default_args).artist elif item['Type'] == 'AlbumArtist': obj = Music(s*default_args).albumartist elif item['Type'] == 'Audio': obj = Music(*default_args).song try: if obj(item) and self.notify: self.notify_output.put((item['Type'], api.API(item).get_naming())) except LibraryException as error: if error.status == 'StopCalled': break except Exception as error: LOG.exception(error) self.queue.task_done() if window('jellyfin_should_stop.bool'): break LOG.info("--<[ q:updated/%s ]", id(self)) self.is_done = True
def artist(self, item, e_item, library): ''' If item does not exist, entry will be added. If item exists, entry will be updated. ''' server_data = self.server.auth.get_server_info(self.server.auth.server_id) server_address = self.server.auth.get_server_address(server_data, server_data['LastConnectionMode']) API = api.API(item, server_address) obj = self.objects.map(item, 'Artist') update = True try: obj['ArtistId'] = e_item[0] except TypeError: update = False obj['ArtistId'] = None LOG.debug("ArtistId %s not found", obj['Id']) else: if self.validate_artist(*values(obj, QU.get_artist_by_id_obj)) is None: update = False LOG.info("ArtistId %s missing from kodi. repairing the entry.", obj['ArtistId']) obj['LibraryId'] = library['Id'] obj['LibraryName'] = library['Name'] 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['Thumb'] = obj['Artwork']['Primary'] obj['Backdrops'] = obj['Artwork']['Backdrop'] or "" if obj['Thumb']: obj['Thumb'] = "<thumb>%s</thumb>" % obj['Thumb'] if obj['Backdrops']: obj['Backdrops'] = "<fanart>%s</fanart>" % obj['Backdrops'][0] if update: self.artist_update(obj) else: self.artist_add(obj) self.update(obj['Genre'], obj['Bio'], obj['Thumb'], obj['Backdrops'], obj['LastScraped'], obj['ArtistId']) self.artwork.add(obj['Artwork'], obj['ArtistId'], "artist") self.item_ids.append(obj['Id'])
def listitem_channel(self, obj, listitem, item): ''' Set listitem for channel content. ''' API = api.API(item, self.server) obj['Title'] = "%s - %s" % (obj['Title'], obj['ProgramName']) obj['Runtime'] = round(float((obj['Runtime'] or 0) / 10000000.0), 6) obj['PlayCount'] = 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.jellyfin/resources/icon.png" obj['Artwork']['Thumb'] = obj['Artwork']['Thumb'] \ or "special://home/addons/plugin.video.jellyfin/resources/fanart.png" obj['Artwork']['Backdrop'] = obj['Artwork']['Backdrop'] \ or ["special://home/addons/plugin.video.jellyfin/resources/fanart.png"] metadata = { 'title': obj['Title'], 'originaltitle': obj['Title'], 'playcount': obj['PlayCount'], 'overlay': obj['Overlay'] } listitem.setArt({ 'icon': obj['Artwork']['Thumb'], 'thumb': obj['Artwork']['Primary'], }) self.set_artwork(obj['Artwork'], listitem, obj['Type']) if obj['Artwork']['Primary']: listitem.setArt({ 'thumb': obj['Artwork']['Primary'], }) if not obj['Artwork']['Backdrop']: listitem.setArt({'fanart': obj['Artwork']['Primary']}) listitem.setProperty('totaltime', str(obj['Runtime'])) listitem.setProperty('IsPlayable', 'true') listitem.setProperty('IsFolder', 'false') listitem.setLabel(obj['Title']) listitem.setInfo('video', metadata) listitem.setContentLookup(False)
def get_fanart(item_id, path, server_id=None): ''' Get extra fanart for listitems. This is called by skinhelper. Images are stored locally, due to the Kodi caching system. ''' if not item_id and 'plugin.video.emby' in path: item_id = path.split('/')[-2] if not item_id: return LOG.info("[ extra fanart ] %s", item_id) get_server(server_id) objects = objects.Objects() list_li = [] directory = xbmc.translatePath("special://thumbnails/emby/%s/" % item_id).decode('utf-8') if not xbmcvfs.exists(directory): xbmcvfs.mkdirs(directory) item = EMBY['api'].get_item(item_id) obj = objects.map(item, 'Artwork') backdrops = api.API(item, EMBY['auth/server-address']).get_all_artwork(obj) tags = obj['BackdropTags'] for index, backdrop in enumerate(backdrops): tag = tags[index] fanart = os.path.join(directory, "fanart%s.jpg" % tag) li = xbmcgui.ListItem(tag, path=fanart) xbmcvfs.copy(backdrop, fanart) list_li.append((fanart, li, False)) else: LOG.debug("cached backdrop found") dirs, files = xbmcvfs.listdir(directory) for file in files: fanart = os.path.join(directory, file.decode('utf-8')) li = xbmcgui.ListItem(file, path=fanart) list_li.append((fanart, li, False)) xbmcplugin.addDirectoryItems(int(sys.argv[1]), list_li, len(list_li)) xbmcplugin.endOfDirectory(int(sys.argv[1]))
def get_fanart(item_id, path, server_id=None): ''' Get extra fanart for listitems. This is called by skinhelper. Images are stored locally, due to the Kodi caching system. ''' if not item_id and 'plugin.video.jellyfin' in path: item_id = path.split('/')[-2] if not item_id: return LOG.info("[ extra fanart ] %s", item_id) objects = Objects() list_li = [] directory = xbmc.translatePath("special://thumbnails/jellyfin/%s/" % item_id) server = TheVoid('GetServerAddress', {'ServerId': server_id}).get() if not xbmcvfs.exists(directory): xbmcvfs.mkdirs(directory) item = TheVoid('GetItem', {'ServerId': server_id, 'Id': item_id}).get() obj = objects.map(item, 'Artwork') backdrops = api.API(item, server).get_all_artwork(obj) tags = obj['BackdropTags'] for index, backdrop in enumerate(backdrops): tag = tags[index] fanart = os.path.join(directory, "fanart%s.jpg" % tag) li = xbmcgui.ListItem(tag, path=fanart) xbmcvfs.copy(backdrop, fanart) list_li.append((fanart, li, False)) else: LOG.debug("cached backdrop found") dirs, files = xbmcvfs.listdir(directory) for file in files: fanart = os.path.join(directory, file) li = xbmcgui.ListItem(file, path=fanart) list_li.append((fanart, li, False)) xbmcplugin.addDirectoryItems(PROCESS_HANDLE, list_li, len(list_li)) xbmcplugin.endOfDirectory(PROCESS_HANDLE)
def listitem_photo(self, obj, listitem, item): API = api.API(item, self.server) obj['Overview'] = API.get_overview(obj['Overview']) obj['FileDate'] = "%s.%s.%s" % tuple( reversed(obj['FileDate'].split('T')[0].split('-'))) metadata = {'title': obj['Title']} listitem.setProperty('path', obj['Artwork']['Primary']) listitem.setThumbnailImage(obj['Artwork']['Primary']) listitem.setIconImage( obj['Artwork']['Primary'] or "special://home/addons/plugin.video.emby/icon.png") listitem.setArt({ 'fanart': obj['Artwork']['Primary'] or "special://home/addons/plugin.video.emby/fanart.jpg" }) if obj['Type'] == 'Photo': metadata.update({ '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']) }) listitem.setProperty('plot', obj['Overview']) listitem.setProperty('IsFolder', 'false') else: if obj['Artwork']['Backdrop']: listitem.setArt({'fanart': obj['Artwork']['Backdrop'][0]}) listitem.setProperty('IsFolder', 'true') listitem.setProperty('IsPlayable', 'false') listitem.setLabel(obj['Title']) listitem.setInfo('pictures', metadata) listitem.setContentLookup(False)
def window_artwork(self, prop, view_id): if not self.server['connected']: window('%s.artwork' % prop, clear=True) elif self.server['connected'] and self.media_folders is not None: for library in self.media_folders: if library['Id'] == view_id and 'Primary' in library.get( 'ImageTags', {}): artwork = api.API( None, self.server['auth/server-address']).get_artwork( view_id, 'Primary') window('%s.artwork' % prop, artwork) break else: window('%s.artwork' % prop, clear=True)
def boxset(self, item, e_item): ''' If item does not exist, entry will be added. If item exists, entry will be updated. Process movies inside boxset. Process removals from boxset. ''' server_data = self.server.auth.get_server_info( self.server.auth.server_id) server_address = self.server.auth.get_server_address( server_data, server_data['LastConnectionMode']) API = api.API(item, server_address) obj = self.objects.map(item, 'Boxset') obj['Overview'] = API.get_overview(obj['Overview']) try: obj['SetId'] = e_item[0] self.update_boxset(*values(obj, QU.update_set_obj)) except TypeError as error: LOG.debug("SetId %s not found", obj['Id']) obj['SetId'] = self.add_boxset(*values(obj, QU.add_set_obj)) self.boxset_current(obj) obj['Artwork'] = API.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.remove_from_boxset(*values(temp_obj, QU.delete_movie_set_obj)) self.jellyfin_db.update_parent_id( *values(temp_obj, QUEM.delete_parent_boxset_obj)) LOG.info("DELETE from boxset [%s] %s: %s", temp_obj['SetId'], temp_obj['Title'], temp_obj['MovieId']) self.artwork.add(obj['Artwork'], obj['SetId'], "set") self.jellyfin_db.add_reference( *values(obj, QUEM.add_reference_boxset_obj)) LOG.info("UPDATE boxset [%s] %s", obj['SetId'], obj['Title'])
def run(self): with self.lock: with self.database as kodidb: with Database('emby') as embydb: while True: try: item = self.queue.get(timeout=1) except Queue.Empty: break if item['Type'] in ('Series', 'Season', 'Episode'): obj = MEDIA[item['Type']]( self.args[0], embydb, kodidb, self.args[1], verify=True)[item['Type']] else: obj = MEDIA[item['Type']]( self.args[0], embydb, kodidb, self.args[1])[item['Type']] try: if obj(item) and self.notify: self.notify_output.put( (item['Type'], api.API(item).get_naming())) except LibraryException as error: if error.status == 'StopCalled': break except Exception as error: LOG.exception(error) self.queue.task_done() if window('emby_should_stop.bool'): break LOG.info("--<[ q:updated/%s ]", id(self)) self.is_done = True
def additional_users(self, server): ''' Setup additional users images. ''' for i in range(10): window('JellyfinAdditionalUserImage.%s' % i, clear=True) try: session = server.jellyfin.get_device(self.device_id) except Exception as error: LOG.exception(error) return for index, user in enumerate(session[0]['AdditionalUsers']): info = server.jellyfin.get_user(user['UserId']) image = api.API(info, server.config.data['auth.server']).get_user_artwork(user['UserId']) window('JellyfinAdditionalUserImage.%s' % index, image) window('JellyfinAdditionalUserPosition.%s' % user['UserId'], str(index))
def listitem_photo(self, obj, listitem, item): API = api.API(item, self.server) obj['Overview'] = API.get_overview(obj['Overview']) obj['FileDate'] = "%s.%s.%s" % tuple(reversed(obj['FileDate'].split('T')[0].split('-'))) metadata = { 'title': obj['Title'] } listitem.setProperty('path', obj['Artwork']['Primary']) listitem.setArt({ 'thumb': obj['Artwork']['Primary'], }) if obj['Type'] == 'Photo': metadata.update({ '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']) }) listitem.setProperty('plot', obj['Overview']) listitem.setProperty('IsFolder', 'false') listitem.setArt({ 'icon': 'DefaultPicture.png', }) else: listitem.setProperty('IsFolder', 'true') listitem.setArt({ 'icon': 'DefaultFolder.png', }) listitem.setProperty('IsPlayable', 'false') listitem.setLabel(obj['Title']) listitem.setInfo('pictures', metadata) listitem.setContentLookup(False)
def set_playlist(self, item, listitem, db_id=None, transcode=False, *args, **kwargs): ''' Verify seektime, set intros, set main item and set additional parts. Detect the seektime for video type content. Verify the default video action set in Kodi for accurate resume behavior. ''' seektime = window('emby.resume.bool') window('emby.resume', clear=True) if item['MediaType'] in ('Video', 'Audio'): resume = item['UserData'].get('PlaybackPositionTicks') if resume: if get_play_action() == "Resume": seektime = True if transcode and not seektime: choice = self.resume_dialog( api.API(item, self.server).adjust_resume( (resume or 0) / 10000000.0)) if choice is None: raise Exception("User backed out of resume dialog.") seektime = False if not choice else True if settings('enableCinema.bool') and not seektime: self._set_intros(item) self.set_listitem(item, listitem, db_id, seektime) playutils.set_properties(item, item['PlaybackInfo']['Method'], self.server_id) self.stack.append([item['PlaybackInfo']['Path'], listitem]) if item.get('PartCount'): self._set_additional_parts(item['Id'])
def trailer(self, obj): try: if obj['LocalTrailer']: trailer = self.server['api'].get_local_trailers(obj['Id']) API = api.API(trailer, self.server['auth/server-address']) if self.direct_path: obj['Trailer'] = API.get_file_path(trailer[0]['Path']) else: obj['Trailer'] = "plugin://plugin.video.emby/trailer?id=%s&mode=play" % trailer[ 0]['Id'] elif obj['Trailer']: obj['Trailer'] = "plugin://plugin.video.youtube/play/?video_id=%s" % obj[ 'Trailer'].rsplit('=', 1)[1] except Exception as error: LOG.error("Failed to get trailer: %s", error) obj['Trailer'] = None
def run(self): with self.lock: with self.database as kodidb: with Database('emby') as embydb: while True: try: item = self.queue.get(timeout=1) except Queue.Empty: break obj = MEDIA[item['Type']]( self.library.server, embydb, kodidb, self.library.direct_path)['UserData'] self.library.update_progress_dialog( api.API(item).get_naming()) try: obj(item) except LibraryException as error: if error.status in ('StopCalled', 'StopWriteCalled'): self.queue.put(item) break except Exception as error: LOG.exception(error) self.queue.task_done() if window('emby_should_stop.bool'): break LOG.info("--<[ q:userdata/%s ]", id(self)) self.is_done = True
def season(self, item, show_id=None): ''' If item does not exist, entry will be added. If item exists, entry will be updated. If the show is empty, try to remove it. ''' server_data = self.server.auth.get_server_info( self.server.auth.server_id) server_address = self.server.auth.get_server_address( server_data, server_data['LastConnectionMode']) API = api.API(item, server_address) obj = self.objects.map(item, 'Season') obj['ShowId'] = show_id if obj['ShowId'] is None: try: obj['ShowId'] = self.jellyfin_db.get_item_by_id( *values(obj, QUEM.get_item_series_obj))[0] except (KeyError, TypeError): LOG.error("Unable to add series %s", obj['SeriesId']) return False obj['SeasonId'] = self.get_season(*values(obj, QU.get_season_obj)) obj['Artwork'] = API.get_all_artwork(self.objects.map(item, 'Artwork')) if obj['Location'] != "Virtual": self.jellyfin_db.add_reference( *values(obj, QUEM.add_reference_season_obj)) self.item_ids.append(obj['Id']) self.artwork.add(obj['Artwork'], obj['SeasonId'], "season") LOG.info("UPDATE season [%s/%s] %s: %s", obj['ShowId'], obj['SeasonId'], obj['Title'] or obj['Index'], obj['Id'])
def userdata(self, item, e_item): ''' This updates: Favorite, LastPlayedDate, Playcount, PlaybackPositionTicks Poster with progress bar ''' server_data = self.server.auth.get_server_info( self.server.auth.server_id) server_address = self.server.auth.get_server_address( server_data, server_data['LastConnectionMode']) API = api.API(item, server_address) obj = self.objects.map(item, 'MovieUserData') try: obj['MovieId'] = e_item[0] obj['FileId'] = e_item[1] except TypeError: return obj['Resume'] = API.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']) if obj['DatePlayed']: obj['DatePlayed'] = Local(obj['DatePlayed']).split('.')[0].replace( 'T', " ") if obj['Favorite']: self.get_tag(*values(obj, QU.get_tag_movie_obj)) else: self.remove_tag(*values(obj, QU.delete_tag_movie_obj)) LOG.debug("New resume point %s: %s", obj['Id'], obj['Resume']) self.add_playstate(*values(obj, QU.add_bookmark_obj)) self.jellyfin_db.update_reference( *values(obj, QUEM.update_reference_obj)) LOG.info("USERDATA movie [%s/%s] %s: %s", obj['FileId'], obj['MovieId'], obj['Id'], obj['Title'])
def song(self, item, e_item): ''' Update object to kodi. ''' API = api.API(item, self.server['auth/server-address']) obj = self.objects.map(item, 'Song') update = True try: obj['SongId'] = e_item[0] obj['PathId'] = e_item[2] obj['AlbumId'] = e_item[3] except TypeError as error: update = False obj['SongId'] = self.create_entry_song() LOG.debug("SongId %s not found", obj['Id']) else: if self.validate_song(*values(obj, QU.get_song_by_id_obj)) is None: update = False LOG.info("SongId %s missing from kodi. repairing the entry.", obj['SongId']) self.get_song_path_filename(obj, API) obj['Rating'] = 0 obj['Genres'] = obj['Genres'] or [] obj['PlayCount'] = API.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 []) obj['AlbumArtists'] = obj['AlbumArtists'] or [] obj['Index'] = obj['Index'] or 0 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) if obj['DateAdded']: obj['DateAdded'] = Local(obj['DateAdded']).split('.')[0].replace( 'T', " ") if obj['DatePlayed']: obj['DatePlayed'] = Local(obj['DatePlayed']).split('.')[0].replace( 'T', " ") if obj['Disc'] != 1: obj['Index'] = obj['Disc'] * 2**16 + obj['Index'] if update: self.song_update(obj) else: self.song_add(obj) self.link_song_album(*values(obj, QU.update_song_album_obj)) self.add_role(*values(obj, QU.update_role_obj)) # defaultt role self.song_artist_link(obj) self.song_artist_discography(obj) obj['strAlbumArtists'] = " / ".join(obj['AlbumArtists']) self.get_album_artist(*values(obj, QU.get_album_artist_obj)) self.add_genres(*values(obj, QU.update_genre_song_obj)) self.artwork.add(obj['Artwork'], obj['SongId'], "song") self.item_ids.append(obj['Id']) if obj['SongAlbumId'] is None: self.artwork.add(obj['Artwork'], obj['AlbumId'], "album") return not update
def tvshow(self, item, e_item, library): ''' If item does not exist, entry will be added. If item exists, entry will be updated. If the show is empty, try to remove it. Process seasons. Apply series pooling. ''' API = api.API(item, self.server['auth/server-address']) obj = self.objects.map(item, 'Series') update = True if not settings('syncEmptyShows.bool') and not obj['RecursiveCount']: LOG.info("Skipping empty show %s: %s", obj['Title'], obj['Id']) self.remove(obj['Id']) return False try: obj['ShowId'] = e_item[0] obj['PathId'] = e_item[2] except TypeError as error: update = False LOG.debug("ShowId %s not found", obj['Id']) obj['ShowId'] = self.create_entry() else: if self.get(*values(obj, QU.get_tvshow_obj)) is None: update = False LOG.info("ShowId %s missing from kodi. repairing the entry.", obj['ShowId']) obj['Path'] = API.get_file_path(obj['Path']) obj['LibraryId'] = library['Id'] obj['LibraryName'] = library['Name'] 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['Genre'] = " / ".join(obj['Genres']) obj['People'] = API.get_people_artwork(obj['People']) obj['Plot'] = API.get_overview(obj['Plot']) obj['Studio'] = " / ".join(obj['Studios']) obj['Artwork'] = API.get_all_artwork(self.objects.map(item, 'Artwork')) self.get_path_filename(obj) if obj['Premiere']: obj['Premiere'] = str(obj['Premiere']).split('.')[0].replace( 'T', " ") tags = [] tags.extend(obj['Tags'] or []) tags.append(obj['LibraryName']) if obj['Favorite']: tags.append('Favorite tvshows') obj['Tags'] = tags if update: self.tvshow_update(obj) else: self.tvshow_add(obj) self.link(*values(obj, QU.update_tvshow_link_obj)) self.update_path(*values(obj, QU.update_path_tvshow_obj)) self.add_tags(*values(obj, QU.add_tags_tvshow_obj)) self.add_people(*values(obj, QU.add_people_tvshow_obj)) self.add_genres(*values(obj, QU.add_genres_tvshow_obj)) self.add_studios(*values(obj, QU.add_studios_tvshow_obj)) self.artwork.add(obj['Artwork'], obj['ShowId'], "tvshow") self.item_ids.append(obj['Id']) season_episodes = {} for season in self.server['api'].get_seasons(obj['Id'])['Items']: if season['SeriesId'] != obj['Id']: obj['SeriesId'] = season['SeriesId'] self.item_ids.append(season['SeriesId']) try: self.emby_db.get_item_by_id( *values(obj, QUEM.get_item_series_obj))[0] if self.update_library: season_episodes[season['Id']] = season['SeriesId'] except TypeError: self.emby_db.add_reference( *values(obj, QUEM.add_reference_pool_obj)) LOG.info("POOL %s [%s/%s]", obj['Title'], obj['Id'], obj['SeriesId']) season_episodes[season['Id']] = season['SeriesId'] try: self.emby_db.get_item_by_id(season['Id'])[0] self.item_ids.append(season['Id']) except TypeError: self.season(season, obj['ShowId']) else: season_id = self.get_season( *values(obj, QU.get_season_special_obj)) self.artwork.add(obj['Artwork'], season_id, "season") for season in season_episodes: for episodes in server.get_episode_by_season( season_episodes[season], season): for episode in episodes['Items']: self.episode(episode)
def userdata(self, item, e_item): ''' This updates: Favorite, LastPlayedDate, Playcount, PlaybackPositionTicks Poster with progress bar Make sure there's no other bookmarks created by widget. Create additional entry for widgets. This is only required for plugin/episode. ''' API = api.API(item, self.server['auth/server-address']) obj = self.objects.map(item, 'EpisodeUserData') try: obj['KodiId'] = e_item[0] obj['FileId'] = e_item[1] obj['Media'] = e_item[4] except TypeError: return if obj['Media'] == "tvshow": if obj['Favorite']: self.get_tag(*values(obj, QU.get_tag_episode_obj)) else: self.remove_tag(*values(obj, QU.delete_tag_episode_obj)) elif obj['Media'] == "episode": obj['Resume'] = API.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']) if obj['DatePlayed']: obj['DatePlayed'] = obj['DatePlayed'].split('.')[0].replace( 'T', " ") if obj['DateAdded']: obj['DateAdded'] = obj['DateAdded'].split('.')[0].replace( 'T', " ") self.add_playstate(*values(obj, QU.add_bookmark_obj)) if not self.direct_path and not obj['Resume']: temp_obj = dict(obj) temp_obj['Filename'] = self.get_filename( *values(temp_obj, QU.get_file_obj)) temp_obj['Path'] = "plugin://plugin.video.emby.tvshows/" self.remove_file(*values(temp_obj, QU.delete_file_obj)) elif not self.direct_path and obj['Resume']: temp_obj = dict(obj) temp_obj['Filename'] = self.get_filename( *values(temp_obj, QU.get_file_obj)) temp_obj['PathId'] = self.get_path( "plugin://plugin.video.emby.tvshows/") temp_obj['FileId'] = self.add_file( *values(temp_obj, QU.add_file_obj)) self.update_file(*values(temp_obj, QU.update_file_obj)) self.add_playstate(*values(temp_obj, QU.add_bookmark_obj)) self.emby_db.update_reference(*values(obj, QUEM.update_reference_obj)) LOG.info("USERDATA %s [%s/%s] %s: %s", obj['Media'], obj['FileId'], obj['KodiId'], obj['Id'], obj['Title'])
def episode(self, item, e_item): ''' If item does not exist, entry will be added. If item exists, entry will be updated. Create additional entry for widgets. This is only required for plugin/episode. ''' API = api.API(item, self.server['auth/server-address']) obj = self.objects.map(item, 'Episode') update = True if obj['Location'] == "Virtual": LOG.info("Skipping virtual episode %s: %s", obj['Title'], obj['Id']) return elif obj['SeriesId'] is None: LOG.info("Skipping episode %s with missing SeriesId", obj['Id']) return try: obj['EpisodeId'] = e_item[0] obj['FileId'] = e_item[1] obj['PathId'] = e_item[2] except TypeError as error: update = False LOG.debug("EpisodeId %s not found", obj['Id']) obj['EpisodeId'] = self.create_entry_episode() else: if self.get_episode(*values(obj, QU.get_episode_obj)) is None: update = False LOG.info( "EpisodeId %s missing from kodi. repairing the entry.", obj['EpisodeId']) obj['Path'] = API.get_file_path(obj['Path']) 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) obj['Runtime'] = round(float((obj['Runtime'] or 0) / 10000000.0), 6) obj['People'] = API.get_people_artwork(obj['People'] or []) obj['DateAdded'] = obj['DateAdded'].split('.')[0].replace('T', " ") obj['DatePlayed'] = None if not obj['DatePlayed'] else 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']) self.get_episode_path_filename(obj) if obj['Premiere']: obj['Premiere'] = obj['Premiere'].split('.')[0].replace('T', " ") if obj['Season'] is None: if obj['AbsoluteNumber']: obj['Season'] = 1 obj['Index'] = obj['AbsoluteNumber'] else: obj['Season'] = 0 if obj['AirsAfterSeason']: obj['AirsBeforeSeason'] = obj['AirsAfterSeason'] obj['AirsBeforeEpisode'] = 4096 # Kodi default number for afterseason ordering if obj['MultiEpisode']: obj['Title'] = "| %02d | %s" % (obj['MultiEpisode'], obj['Title']) if not self.get_show_id(obj): return False obj['SeasonId'] = self.get_season( *values(obj, QU.get_season_episode_obj)) if update: self.episode_update(obj) else: self.episode_add(obj) self.update_path(*values(obj, QU.update_path_episode_obj)) self.update_file(*values(obj, QU.update_file_obj)) self.add_people(*values(obj, QU.add_people_episode_obj)) self.add_streams(*values(obj, QU.add_streams_obj)) self.add_playstate(*values(obj, QU.add_bookmark_obj)) self.artwork.update(obj['Artwork']['Primary'], obj['EpisodeId'], "episode", "thumb") self.item_ids.append(obj['Id']) if not self.direct_path and obj['Resume']: temp_obj = dict(obj) temp_obj['Path'] = "plugin://plugin.video.emby.tvshows/" temp_obj['PathId'] = self.get_path( *values(temp_obj, QU.get_path_obj)) temp_obj['FileId'] = self.add_file( *values(temp_obj, QU.add_file_obj)) self.update_file(*values(temp_obj, QU.update_file_obj)) self.add_playstate(*values(temp_obj, QU.add_bookmark_obj)) return not update
def musicvideo(self, item, e_item, library): ''' If item does not exist, entry will be added. If item exists, entry will be updated. If we don't get the track number from Emby, see if we can infer it from the sortname attribute. ''' API = api.API(item, self.server['auth/server-address']) obj = self.objects.map(item, 'MusicVideo') update = True try: obj['MvideoId'] = e_item[0] obj['FileId'] = e_item[1] obj['PathId'] = e_item[2] except TypeError as error: update = False LOG.debug("MvideoId for %s not found", obj['Id']) obj['MvideoId'] = self.create_entry() else: if self.get(*values(obj, QU.get_musicvideo_obj)) is None: update = False LOG.info("MvideoId %s missing from kodi. repairing the entry.", obj['MvideoId']) obj['Path'] = API.get_file_path(obj['Path']) 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'] = Local(obj['DateAdded']).split('.')[0].replace( 'T', " ") obj['DatePlayed'] = None if not obj['DatePlayed'] else 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) obj['Runtime'] = round(float((obj['Runtime'] or 0) / 10000000.0), 6) obj['Premiere'] = Local( obj['Premiere']) if obj['Premiere'] else datetime.date( obj['Year'] or 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')) self.get_path_filename(obj) if obj['Premiere']: obj['Premiere'] = str(obj['Premiere']).split('.')[0].replace( 'T', " ") for artist in obj['ArtistItems']: artist['Type'] = "Artist" obj['People'] = obj['People'] or [] + obj['ArtistItems'] obj['People'] = API.get_people_artwork(obj['People']) if obj['Index'] is None and obj['SortTitle'] is not None: search = re.search(r'^\d+\s?', obj['SortTitle']) if search: obj['Index'] = search.group() tags = [] tags.extend(obj['Tags'] or []) tags.append(obj['LibraryName']) if obj['Favorite']: tags.append('Favorite musicvideos') obj['Tags'] = tags if update: self.musicvideo_update(obj) else: self.musicvideo_add(obj) self.update_path(*values(obj, QU.update_path_mvideo_obj)) self.update_file(*values(obj, QU.update_file_obj)) self.add_tags(*values(obj, QU.add_tags_mvideo_obj)) self.add_genres(*values(obj, QU.add_genres_mvideo_obj)) self.add_studios(*values(obj, QU.add_studios_mvideo_obj)) self.add_playstate(*values(obj, QU.add_bookmark_obj)) self.add_people(*values(obj, QU.add_people_mvideo_obj)) self.add_streams(*values(obj, QU.add_streams_obj)) self.artwork.add(obj['Artwork'], obj['MvideoId'], "musicvideo") self.item_ids.append(obj['Id']) return not update
def set_listitem(self, item, listitem, db_id=None, seektime=None, intro=False): objects = Objects() API = api.API(item, self.server) if item['Type'] in ('MusicArtist', 'MusicAlbum', 'Audio'): obj = objects.map(item, 'BrowseAudio') obj['DbId'] = db_id obj['Artwork'] = API.get_all_artwork( objects.map(item, 'ArtworkMusic'), True) self.listitem_music(obj, listitem, item) elif item['Type'] in ('Photo', 'PhotoAlbum'): obj = objects.map(item, 'BrowsePhoto') obj['Artwork'] = API.get_all_artwork(objects.map(item, 'Artwork')) self.listitem_photo(obj, listitem, item) elif item['Type'] in ('TvChannel', ): obj = objects.map(item, 'BrowseChannel') obj['Artwork'] = API.get_all_artwork(objects.map(item, 'Artwork')) self.listitem_channel(obj, listitem, item) else: obj = objects.map(item, 'BrowseVideo') obj['DbId'] = db_id obj['Artwork'] = API.get_all_artwork( objects.map(item, 'ArtworkParent'), True) if intro: obj['Artwork']['Primary'] = "&KodiCinemaMode=true" self.listitem_video(obj, listitem, item, seektime, intro) if 'PlaybackInfo' in item: if seektime: item['PlaybackInfo']['CurrentPosition'] = obj['Resume'] if 'SubtitleUrl' in item['PlaybackInfo']: LOG.info("[ subtitles ] %s", item['PlaybackInfo']['SubtitleUrl']) listitem.setSubtitles( [item['PlaybackInfo']['SubtitleUrl']]) if item['Type'] == 'Episode': item['PlaybackInfo']['CurrentEpisode'] = objects.map( item, "UpNext") item['PlaybackInfo']['CurrentEpisode']['art'] = { 'tvshow.poster': obj['Artwork'].get('Series.Primary'), 'thumb': obj['Artwork'].get('Primary'), 'tvshow.fanart': None } if obj['Artwork']['Backdrop']: item['PlaybackInfo']['CurrentEpisode']['art'][ 'tvshow.fanart'] = obj['Artwork']['Backdrop'][0] listitem.setContentLookup(False)
def listitem_video(self, obj, listitem, item, seektime=None, intro=False): ''' Set listitem for video content. That also include streams. ''' API = api.API(item, self.server) is_video = obj['MediaType'] in ('Video', 'Audio') # audiobook obj['Genres'] = " / ".join(obj['Genres'] or []) obj['Studios'] = [ API.validate_studio(studio) for studio in (obj['Studios'] or []) ] obj['Studios'] = " / ".join(obj['Studios']) obj['Mpaa'] = API.get_mpaa(obj['Mpaa']) 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'] = API.get_overview(obj['Plot']) obj['ShortPlot'] = API.get_overview(obj['ShortPlot']) 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'] = API.adjust_resume((obj['Resume'] or 0) / 10000000.0) obj['PlayCount'] = API.get_playcount(obj['Played'], obj['PlayCount']) or 0 obj['Overlay'] = 7 if obj['Played'] else 6 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['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 "" if not intro and not obj['Type'] == 'Trailer': obj['Artwork']['Primary'] = obj['Artwork']['Primary'] \ or "special://home/addons/plugin.video.jellyfin/resources/icon.png" else: obj['Artwork']['Primary'] = obj['Artwork']['Primary'] \ or obj['Artwork']['Thumb'] \ or (obj['Artwork']['Backdrop'][0] \ if len(obj['Artwork']['Backdrop']) \ else "special://home/addons/plugin.video.jellyfin/resources/fanart.png") obj['Artwork']['Primary'] += "&KodiTrailer=true" \ if obj['Type'] == 'Trailer' else "&KodiCinemaMode=true" obj['Artwork']['Backdrop'] = [obj['Artwork']['Primary']] self.set_artwork(obj['Artwork'], listitem, obj['Type']) if intro or obj['Type'] == 'Trailer': listitem.setArt( {'poster': ""} ) # Clear the poster value for intros / trailers to prevent issues in skins listitem.setIconImage('DefaultVideo.png') listitem.setThumbnailImage(obj['Artwork']['Primary']) if obj['Premiere']: obj['Premiere'] = obj['Premiere'].split('T')[0] if obj['DatePlayed']: obj['DatePlayed'] = obj['DatePlayed'].split('.')[0].replace( 'T', " ") metadata = { 'title': obj['Title'], 'originaltitle': obj['Title'], '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'], 'aired': obj['Year'], 'date': obj['FileDate'], 'dbid': obj['DbId'] } listitem.setCast(API.get_actors()) if obj['Premiere']: metadata['date'] = obj['Premiere'] if obj['Type'] == 'Episode': metadata.update({ 'mediatype': "episode", 'tvshowtitle': obj['SeriesName'], 'season': obj['Season'] or 0, 'sortseason': obj['Season'] or 0, 'episode': obj['Index'] or 0, 'sortepisode': obj['Index'] or 0, 'lastplayed': obj['DatePlayed'], 'duration': obj['Runtime'], 'aired': obj['Premiere'], }) elif obj['Type'] == 'Season': metadata.update({ 'mediatype': "season", 'tvshowtitle': obj['SeriesName'], 'season': obj['Index'] or 0, 'sortseason': obj['Index'] or 0 }) listitem.setProperty('NumEpisodes', str(obj['RecursiveCount'])) listitem.setProperty('WatchedEpisodes', str(obj['RecursiveCount'] - obj['Unwatched'])) listitem.setProperty('UnWatchedEpisodes', str(obj['Unwatched'])) listitem.setProperty('IsFolder', 'true') elif obj['Type'] == 'Series': if obj['Status'] != 'Ended': obj['Status'] = None metadata.update({ 'mediatype': "tvshow", 'tvshowtitle': obj['Title'], 'status': obj['Status'] }) listitem.setProperty('TotalSeasons', str(obj['ChildCount'])) listitem.setProperty('TotalEpisodes', str(obj['RecursiveCount'])) listitem.setProperty('WatchedEpisodes', str(obj['RecursiveCount'] - obj['Unwatched'])) listitem.setProperty('UnWatchedEpisodes', str(obj['Unwatched'])) listitem.setProperty('IsFolder', 'true') elif obj['Type'] == 'Movie': metadata.update({ 'mediatype': "movie", 'imdbnumber': obj['UniqueId'], 'lastplayed': obj['DatePlayed'], 'duration': obj['Runtime'], 'userrating': obj['CriticRating'] }) elif obj['Type'] == 'MusicVideo': metadata.update({ 'mediatype': "musicvideo", 'album': obj['Album'], 'artist': obj['Artists'] or [], 'lastplayed': obj['DatePlayed'], 'duration': obj['Runtime'] }) elif obj['Type'] == 'BoxSet': metadata['mediatype'] = "set" listitem.setProperty('IsFolder', 'true') else: metadata.update({ 'mediatype': "video", 'lastplayed': obj['DatePlayed'], 'year': obj['Year'], 'duration': obj['Runtime'] }) if is_video: listitem.setProperty('totaltime', str(obj['Runtime'])) listitem.setProperty('IsPlayable', 'true') listitem.setProperty('IsFolder', 'false') if obj['Resume'] and seektime != False: listitem.setProperty('resumetime', str(obj['Resume'])) listitem.setProperty( 'StartPercent', str(((obj['Resume'] / obj['Runtime']) * 100) - 0.40)) else: listitem.setProperty('resumetime', '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}) listitem.setLabel(obj['Title']) listitem.setInfo('video', metadata) listitem.setContentLookup(False)
def album(self, item, e_item): ''' Update object to kodi. ''' server_address = self.server.auth.get_server_info( self.server.auth.server_id)['address'] API = api.API(item, server_address) obj = self.objects.map(item, 'Album') update = True try: obj['AlbumId'] = e_item[0] obj['LibraryId'] = e_item[6] obj['LibraryName'] = self.jellyfin_db.get_view_name( obj['LibraryId']) except TypeError: update = False library = self.library or find_library(self.server, item) if not library: # This item doesn't belong to a whitelisted library return obj['AlbumId'] = None obj['LibraryId'] = library['Id'] obj['LibraryName'] = library['Name'] LOG.debug("AlbumId %s not found", obj['Id']) else: if self.validate_album( *values(obj, QU.get_album_by_id_obj)) is None: update = False LOG.info("AlbumId %s missing from kodi. repairing the entry.", obj['AlbumId']) obj['Rating'] = 0 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['Artists'] = " / ".join(obj['Artists'] or []) obj['Artwork'] = API.get_all_artwork( self.objects.map(item, 'ArtworkMusic'), True) obj['Thumb'] = obj['Artwork']['Primary'] obj['DateAdded'] = item.get('DateCreated') if obj['DateAdded']: obj['DateAdded'] = Local(obj['DateAdded']).split('.')[0].replace( 'T', " ") if obj['Thumb']: obj['Thumb'] = "<thumb>%s</thumb>" % obj['Thumb'] if update: self.album_update(obj) else: self.album_add(obj) self.artist_link(obj) self.artist_discography(obj) self.update_album(*values(obj, QU.update_album_obj)) self.add_genres(*values(obj, QU.add_genres_obj)) self.artwork.add(obj['Artwork'], obj['AlbumId'], "album") self.item_ids.append(obj['Id'])
def movie(self, item, e_item, library): ''' If item does not exist, entry will be added. If item exists, entry will be updated. ''' server_data = self.server.auth.get_server_info( self.server.auth.server_id) server_address = self.server.auth.get_server_address( server_data, server_data['LastConnectionMode']) API = api.API(item, server_address) obj = self.objects.map(item, 'Movie') update = True try: obj['MovieId'] = e_item[0] obj['FileId'] = e_item[1] obj['PathId'] = e_item[2] except TypeError: update = False LOG.debug("MovieId %s not found", obj['Id']) obj['MovieId'] = self.create_entry() else: if self.get(*values(obj, QU.get_movie_obj)) is None: update = False LOG.info("MovieId %s missing from kodi. repairing the entry.", obj['MovieId']) if not settings('syncRottenTomatoes.bool'): obj['CriticRating'] = None obj['Path'] = API.get_file_path(obj['Path']) obj['LibraryId'] = library['Id'] obj['LibraryName'] = library['Name'] obj['Genres'] = obj['Genres'] or [] obj['Studios'] = [ API.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) obj['Runtime'] = round(float((obj['Runtime'] or 0) / 10000000.0), 6) obj['People'] = API.get_people_artwork(obj['People']) obj['DateAdded'] = Local(obj['DateAdded']).split('.')[0].replace( 'T', " ") obj['DatePlayed'] = None if not obj['DatePlayed'] else 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']) self.get_path_filename(obj) self.trailer(obj) if obj['Countries']: self.add_countries(*values(obj, QU.update_country_obj)) tags = [] tags.extend(obj['Tags'] or []) tags.append(obj['LibraryName']) if obj['Favorite']: tags.append('Favorite movies') obj['Tags'] = tags if update: self.movie_update(obj) else: self.movie_add(obj) self.update_path(*values(obj, QU.update_path_movie_obj)) self.update_file(*values(obj, QU.update_file_obj)) self.add_tags(*values(obj, QU.add_tags_movie_obj)) self.add_genres(*values(obj, QU.add_genres_movie_obj)) self.add_studios(*values(obj, QU.add_studios_movie_obj)) self.add_playstate(*values(obj, QU.add_bookmark_obj)) self.add_people(*values(obj, QU.add_people_movie_obj)) self.add_streams(*values(obj, QU.add_streams_obj)) self.artwork.add(obj['Artwork'], obj['MovieId'], "movie") self.item_ids.append(obj['Id']) return not update
def tvshow(self, item, e_item): ''' If item does not exist, entry will be added. If item exists, entry will be updated. If the show is empty, try to remove it. Process seasons. Apply series pooling. ''' server_address = self.server.auth.get_server_info( self.server.auth.server_id)['address'] API = api.API(item, server_address) obj = self.objects.map(item, 'Series') update = True try: obj['ShowId'] = e_item[0] obj['PathId'] = e_item[2] obj['LibraryId'] = e_item[6] obj['LibraryName'] = self.jellyfin_db.get_view_name( obj['LibraryId']) except TypeError: update = False LOG.debug("ShowId %s not found", obj['Id']) library = self.library or find_library(self.server, item) if not library: # This item doesn't belong to a whitelisted library return obj['ShowId'] = self.create_entry() obj['LibraryId'] = library['Id'] obj['LibraryName'] = library['Name'] else: if self.get(*values(obj, QU.get_tvshow_obj)) is None: update = False LOG.info("ShowId %s missing from kodi. repairing the entry.", obj['ShowId']) obj['Path'] = API.get_file_path(obj['Path']) 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['Genre'] = " / ".join(obj['Genres']) obj['People'] = API.get_people_artwork(obj['People']) obj['Plot'] = API.get_overview(obj['Plot']) obj['Studio'] = " / ".join(obj['Studios']) obj['Artwork'] = API.get_all_artwork(self.objects.map(item, 'Artwork')) if obj['Status'] != 'Ended': obj['Status'] = None self.get_path_filename(obj) if obj['Premiere']: obj['Premiere'] = str(Local( obj['Premiere'])).split('.')[0].replace('T', " ") tags = [] tags.extend(obj['Tags'] or []) tags.append(obj['LibraryName']) if obj['Favorite']: tags.append('Favorite tvshows') obj['Tags'] = tags if update: self.tvshow_update(obj) else: self.tvshow_add(obj) self.link(*values(obj, QU.update_tvshow_link_obj)) self.update_path(*values(obj, QU.update_path_tvshow_obj)) self.add_tags(*values(obj, QU.add_tags_tvshow_obj)) self.add_people(*values(obj, QU.add_people_tvshow_obj)) self.add_genres(*values(obj, QU.add_genres_tvshow_obj)) self.add_studios(*values(obj, QU.add_studios_tvshow_obj)) self.artwork.add(obj['Artwork'], obj['ShowId'], "tvshow") self.item_ids.append(obj['Id']) season_episodes = {} for season in self.server.jellyfin.get_seasons(obj['Id'])['Items']: if season['SeriesId'] != obj['Id']: obj['SeriesId'] = season['SeriesId'] self.item_ids.append(season['SeriesId']) try: self.jellyfin_db.get_item_by_id( *values(obj, QUEM.get_item_series_obj))[0] if self.update_library: season_episodes[season['Id']] = season['SeriesId'] except TypeError: self.jellyfin_db.add_reference( *values(obj, QUEM.add_reference_pool_obj)) LOG.info("POOL %s [%s/%s]", obj['Title'], obj['Id'], obj['SeriesId']) season_episodes[season['Id']] = season['SeriesId'] try: self.jellyfin_db.get_item_by_id(season['Id'])[0] self.item_ids.append(season['Id']) except TypeError: self.season(season, obj['ShowId']) else: season_id = self.get_season( *values(obj, QU.get_season_special_obj)) self.artwork.add(obj['Artwork'], season_id, "season") for season in season_episodes: for episodes in server.get_episode_by_season( season_episodes[season], season): for episode in episodes['Items']: self.episode(episode)