Пример #1
0
    def __init__(self, server, embydb, musicdb, direct_path):

        self.server = server
        self.emby = embydb
        self.music = musicdb
        self.direct_path = direct_path

        self.emby_db = emby_db.EmbyDatabase(embydb.cursor)
        self.objects = Objects()
        self.item_ids = []

        KodiDb.__init__(self, musicdb.cursor)
Пример #2
0
    def __init__(self, server, jellyfindb, videodb, direct_path):

        self.server = server
        self.jellyfin = jellyfindb
        self.video = videodb
        self.direct_path = direct_path

        self.jellyfin_db = jellyfin_db.JellyfinDatabase(jellyfindb.cursor)
        self.objects = Objects()
        self.item_ids = []

        KodiDb.__init__(self, videodb.cursor)
Пример #3
0
    def __init__(self, server, embydb, videodb, direct_path, *args, **kwargs):

        self.server = server
        self.emby = embydb
        self.video = videodb
        self.direct_path = direct_path

        self.emby_db = emby_db.EmbyDatabase(embydb.cursor)
        self.objects = Objects()
        self.item_ids = []

        KodiDb.__init__(self, videodb.cursor)
Пример #4
0
    def __init__(self, server, embydb, videodb, direct_path, update_library=False):

        self.server = server
        self.emby = embydb
        self.video = videodb
        self.direct_path = direct_path
        self.update_library = update_library

        self.emby_db = emby_db.EmbyDatabase(embydb.cursor)
        self.objects = Objects()
        self.item_ids = []

        KodiDb.__init__(self, videodb.cursor)
Пример #5
0
    def __init__(self, server, embydb, videodb, direct_path, update_library=False, verify=False, *args, **kwargs):

        self.server = server
        self.emby = embydb
        self.video = videodb
        self.direct_path = direct_path
        self.update_library = update_library
        self.verify = verify

        self.emby_db = emby_db.EmbyDatabase(embydb.cursor)
        self.objects = Objects()
        self.item_ids = []
        self.display_specials = settings('SeasonSpecials.bool')

        KodiDb.__init__(self, videodb.cursor)
Пример #6
0
class Movies(KodiDb):
    def __init__(self, server, jellyfindb, videodb, direct_path):

        self.server = server
        self.jellyfin = jellyfindb
        self.video = videodb
        self.direct_path = direct_path

        self.jellyfin_db = jellyfin_db.JellyfinDatabase(jellyfindb.cursor)
        self.objects = Objects()
        self.item_ids = []

        KodiDb.__init__(self, videodb.cursor)

    @stop()
    @jellyfin_item()
    @library_check()
    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 movie_add(self, obj):
        ''' Add object to kodi.
        '''
        obj['RatingId'] = self.create_entry_rating()
        self.add_ratings(*values(obj, QU.add_rating_movie_obj))

        obj['Unique'] = self.create_entry_unique_id()
        self.add_unique_id(*values(obj, QU.add_unique_id_movie_obj))

        obj['PathId'] = self.add_path(*values(obj, QU.add_path_obj))
        obj['FileId'] = self.add_file(*values(obj, QU.add_file_obj))

        self.add(*values(obj, QU.add_movie_obj))
        self.jellyfin_db.add_reference(
            *values(obj, QUEM.add_reference_movie_obj))
        LOG.info("ADD movie [%s/%s/%s] %s: %s", obj['PathId'], obj['FileId'],
                 obj['MovieId'], obj['Id'], obj['Title'])

    def movie_update(self, obj):
        ''' Update object to kodi.
        '''
        obj['RatingId'] = self.get_rating_id(
            *values(obj, QU.get_rating_movie_obj))
        self.update_ratings(*values(obj, QU.update_rating_movie_obj))

        obj['Unique'] = self.get_unique_id(
            *values(obj, QU.get_unique_id_movie_obj))
        self.update_unique_id(*values(obj, QU.update_unique_id_movie_obj))

        self.update(*values(obj, QU.update_movie_obj))
        self.jellyfin_db.update_reference(
            *values(obj, QUEM.update_reference_obj))
        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.server.jellyfin.get_local_trailers(obj['Id'])
                obj['Trailer'] = "plugin://plugin.video.jellyfin/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.exception("Failed to get trailer: %s", error)
            obj['Trailer'] = None

    def get_path_filename(self, obj):
        ''' Get the path and filename and build it into protocol://path
        '''
        obj['Filename'] = obj['Path'].rsplit(
            '\\', 1)[1] if '\\' in obj['Path'] else obj['Path'].rsplit('/',
                                                                       1)[1]

        if self.direct_path:

            if not validate(obj['Path']):
                raise Exception("Failed to validate path. User stopped.")

            obj['Path'] = obj['Path'].replace(obj['Filename'], "")

        else:
            obj['Path'] = "plugin://plugin.video.jellyfin/"
            params = {
                'filename': obj['Filename'].encode('utf-8'),
                'id': obj['Id'],
                'dbid': obj['MovieId'],
                'mode': "play"
            }
            obj['Filename'] = "%s?%s" % (obj['Path'], urllib.urlencode(params))

    @stop()
    @jellyfin_item()
    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:
            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 boxset_current(self, obj):
        ''' Add or removes movies based on the current movies found in the boxset.
        '''
        try:
            current = self.jellyfin_db.get_item_id_by_parent_id(
                *values(obj, QUEM.get_item_id_by_parent_boxset_obj))
            movies = dict(current)
        except ValueError:
            movies = {}

        obj['Current'] = movies

        for all_movies in server.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']

                try:
                    temp_obj['MovieId'] = self.jellyfin_db.get_item_by_id(
                        *values(temp_obj, QUEM.get_item_obj))[0]
                except TypeError:
                    LOG.info("Failed to process %s to boxset.",
                             temp_obj['Title'])

                    continue

                if temp_obj['Id'] not in obj['Current']:

                    self.set_boxset(*values(temp_obj, QU.update_movie_set_obj))
                    self.jellyfin_db.update_parent_id(
                        *values(temp_obj, QUEM.update_parent_movie_obj))
                    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'])

    def boxsets_reset(self):
        ''' Special function to remove all existing boxsets.
        '''
        boxsets = self.jellyfin_db.get_items_by_media('set')
        for boxset in boxsets:
            self.remove(boxset[0])

    @stop()
    @jellyfin_item()
    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'])

    @stop()
    @jellyfin_item()
    def remove(self, item_id, e_item):
        ''' Remove movieid, fileid, jellyfin reference.
            Remove artwork, boxset
        '''
        obj = {'Id': item_id}

        try:
            obj['KodiId'] = e_item[0]
            obj['FileId'] = e_item[1]
            obj['Media'] = e_item[4]
        except TypeError:
            return

        self.artwork.delete(obj['KodiId'], obj['Media'])

        if obj['Media'] == 'movie':
            self.delete(*values(obj, QU.delete_movie_obj))
        elif obj['Media'] == 'set':

            for movie in self.jellyfin_db.get_item_by_parent_id(
                    *values(obj, QUEM.get_item_by_parent_movie_obj)):

                temp_obj = dict(obj)
                temp_obj['MovieId'] = movie[1]
                temp_obj['Movie'] = movie[0]
                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))

            self.delete_boxset(*values(obj, QU.delete_set_obj))

        self.jellyfin_db.remove_item(*values(obj, QUEM.delete_item_obj))
        LOG.info("DELETE %s [%s/%s] %s", obj['Media'], obj['FileId'],
                 obj['KodiId'], obj['Id'])
    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)
Пример #8
0
class Music(KodiDb):
    def __init__(self, server, jellyfindb, musicdb, direct_path):

        self.server = server
        self.jellyfin = jellyfindb
        self.music = musicdb
        self.direct_path = direct_path

        self.jellyfin_db = jellyfin_db.JellyfinDatabase(jellyfindb.cursor)
        self.objects = Objects()
        self.item_ids = []

        KodiDb.__init__(self, musicdb.cursor)

    def __getitem__(self, key):
        LOG.debug("__getitem__(%r)", key)

        if key in ('MusicArtist', 'AlbumArtist'):
            return self.artist
        elif key == 'MusicAlbum':
            return self.album
        elif key == 'Audio':
            return self.song
        elif key == 'UserData':
            return self.userdata
        elif key in 'Removed':
            return self.remove

    @stop()
    @jellyfin_item()
    @library_check()
    def artist(self, item, e_item, library):
        ''' If item does not exist, entry will be added.
            If item exists, entry will be updated.
        '''
        API = api.API(item, self.server['auth/server-address'])
        obj = self.objects.map(item, 'Artist')
        update = True

        try:
            obj['ArtistId'] = e_item[0]
        except TypeError as error:

            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 artist_add(self, obj):
        ''' Add object to kodi.

            safety checks: It looks like Jellyfin supports the same artist multiple times.
            Kodi doesn't allow that. In case that happens we just merge the artist entries.
        '''
        obj['ArtistId'] = self.get(*values(obj, QU.get_artist_obj))
        self.jellyfin_db.add_reference(
            *values(obj, QUEM.add_reference_artist_obj))
        LOG.info("ADD artist [%s] %s: %s", obj['ArtistId'], obj['Name'],
                 obj['Id'])

    def artist_update(self, obj):
        ''' Update object to kodi.
        '''
        self.jellyfin_db.update_reference(
            *values(obj, QUEM.update_reference_obj))
        LOG.info("UPDATE artist [%s] %s: %s", obj['ArtistId'], obj['Name'],
                 obj['Id'])

    @stop()
    @jellyfin_item()
    def album(self, item, e_item):
        ''' Update object to kodi.
        '''
        API = api.API(item, self.server['auth/server-address'])
        obj = self.objects.map(item, 'Album')
        update = True

        try:
            obj['AlbumId'] = e_item[0]
        except TypeError as error:

            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 album_add(self, obj):
        ''' Add object to kodi.
        '''
        obj['AlbumId'] = self.get_album(*values(obj, QU.get_album_obj))
        self.jellyfin_db.add_reference(
            *values(obj, QUEM.add_reference_album_obj))
        LOG.info("ADD album [%s] %s: %s", obj['AlbumId'], obj['Title'],
                 obj['Id'])

    def album_update(self, obj):
        ''' Update object to kodi.
        '''
        self.jellyfin_db.update_reference(
            *values(obj, QUEM.update_reference_obj))
        LOG.info("UPDATE album [%s] %s: %s", obj['AlbumId'], obj['Title'],
                 obj['Id'])

    def artist_discography(self, obj):
        ''' Update the artist's discography.
        '''
        for artist in (obj['ArtistItems'] or []):

            temp_obj = dict(obj)
            temp_obj['Id'] = artist['Id']
            temp_obj['AlbumId'] = obj['Id']

            try:
                temp_obj['ArtistId'] = self.jellyfin_db.get_item_by_id(
                    *values(temp_obj, QUEM.get_item_obj))[0]
            except TypeError:
                continue

            self.add_discography(*values(temp_obj, QU.update_discography_obj))
            self.jellyfin_db.update_parent_id(
                *values(temp_obj, QUEM.update_parent_album_obj))

    def artist_link(self, obj):
        ''' Assign main artists to album.
            Artist does not exist in jellyfin database, create the reference.
        '''
        for artist in (obj['AlbumArtists'] or []):

            temp_obj = dict(obj)
            temp_obj['Name'] = artist['Name']
            temp_obj['Id'] = artist['Id']

            try:
                temp_obj['ArtistId'] = self.jellyfin_db.get_item_by_id(
                    *values(temp_obj, QUEM.get_item_obj))[0]
            except TypeError:

                try:
                    self.artist(self.server['api'].get_item(temp_obj['Id']),
                                library=None)
                    temp_obj['ArtistId'] = self.jellyfin_db.get_item_by_id(
                        *values(temp_obj, QUEM.get_item_obj))[0]
                except Exception as error:
                    LOG.exception(error)
                    continue

            self.update_artist_name(
                *values(temp_obj, QU.update_artist_name_obj))
            self.link(*values(temp_obj, QU.update_link_obj))
            self.item_ids.append(temp_obj['Id'])

    @stop()
    @jellyfin_item()
    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 song_add(self, obj):
        ''' Add object to kodi.

            Verify if there's an album associated.
            If no album found, create a single's album
        '''
        obj['PathId'] = self.add_path(obj['Path'])

        try:
            obj['AlbumId'] = self.jellyfin_db.get_item_by_id(
                *values(obj, QUEM.get_item_song_obj))[0]
        except TypeError:

            try:
                if obj['SongAlbumId'] is None:
                    raise TypeError("No album id found associated?")

                self.album(self.server['api'].get_item(obj['SongAlbumId']))
                obj['AlbumId'] = self.jellyfin_db.get_item_by_id(
                    *values(obj, QUEM.get_item_song_obj))[0]
            except TypeError:
                self.single(obj)

        self.add_song(*values(obj, QU.add_song_obj))
        self.jellyfin_db.add_reference(
            *values(obj, QUEM.add_reference_song_obj))
        LOG.debug("ADD song [%s/%s/%s] %s: %s", obj['PathId'], obj['AlbumId'],
                  obj['SongId'], obj['Id'], obj['Title'])

    def song_update(self, obj):
        ''' Update object to kodi.
        '''
        self.update_path(*values(obj, QU.update_path_obj))

        self.update_song(*values(obj, QU.update_song_obj))
        self.jellyfin_db.update_reference(
            *values(obj, QUEM.update_reference_obj))
        LOG.info("UPDATE song [%s/%s/%s] %s: %s", obj['PathId'],
                 obj['AlbumId'], obj['SongId'], obj['Id'], obj['Title'])

    def get_song_path_filename(self, obj, api):
        ''' Get the path and filename and build it into protocol://path
        '''
        obj['Path'] = api.get_file_path(obj['Path'])
        obj['Filename'] = obj['Path'].rsplit(
            '\\', 1)[1] if '\\' in obj['Path'] else obj['Path'].rsplit('/',
                                                                       1)[1]

        if self.direct_path:

            if not validate(obj['Path']):
                raise Exception("Failed to validate path. User stopped.")

            obj['Path'] = obj['Path'].replace(obj['Filename'], "")

        else:
            obj['Path'] = "%s/emby/Audio/%s/" % (
                self.server['auth/server-address'], obj['Id'])
            obj['Filename'] = "stream.%s?static=true" % obj['Container']

    def song_artist_discography(self, obj):
        ''' Update the artist's discography.
        '''
        artists = []
        for artist in (obj['AlbumArtists'] or []):

            temp_obj = dict(obj)
            temp_obj['Name'] = artist['Name']
            temp_obj['Id'] = artist['Id']

            artists.append(temp_obj['Name'])

            try:
                temp_obj['ArtistId'] = self.jellyfin_db.get_item_by_id(
                    *values(temp_obj, QUEM.get_item_obj))[0]
            except TypeError:

                try:
                    self.artist(self.server['api'].get_item(temp_obj['Id']),
                                library=None)
                    temp_obj['ArtistId'] = self.jellyfin_db.get_item_by_id(
                        *values(temp_obj, QUEM.get_item_obj))[0]
                except Exception as error:
                    LOG.exception(error)
                    continue

            self.link(*values(temp_obj, QU.update_link_obj))
            self.item_ids.append(temp_obj['Id'])

            if obj['Album']:

                temp_obj['Title'] = obj['Album']
                temp_obj['Year'] = 0
                self.add_discography(
                    *values(temp_obj, QU.update_discography_obj))

        obj['AlbumArtists'] = artists

    def song_artist_link(self, obj):
        ''' Assign main artists to song.
            Artist does not exist in jellyfin database, create the reference.
        '''
        for index, artist in enumerate(obj['ArtistItems'] or []):

            temp_obj = dict(obj)
            temp_obj['Name'] = artist['Name']
            temp_obj['Id'] = artist['Id']
            temp_obj['Index'] = index

            try:
                temp_obj['ArtistId'] = self.jellyfin_db.get_item_by_id(
                    *values(temp_obj, QUEM.get_item_obj))[0]
            except TypeError:

                try:
                    self.artist(self.server['api'].get_item(temp_obj['Id']),
                                library=None)
                    temp_obj['ArtistId'] = self.jellyfin_db.get_item_by_id(
                        *values(temp_obj, QUEM.get_item_obj))[0]
                except Exception as error:
                    LOG.exception(error)
                    continue

            self.link_song_artist(*values(temp_obj, QU.update_song_artist_obj))
            self.item_ids.append(temp_obj['Id'])

    def single(self, obj):

        obj['AlbumId'] = self.create_entry_album()
        self.add_single(*values(obj, QU.add_single_obj))

    @stop()
    @jellyfin_item()
    def userdata(self, item, e_item):
        ''' This updates: Favorite, LastPlayedDate, Playcount, PlaybackPositionTicks
            Poster with progress bar
        '''
        API = api.API(item, self.server['auth/server-address'])
        obj = self.objects.map(item, 'SongUserData')

        try:
            obj['KodiId'] = e_item[0]
            obj['Media'] = e_item[4]
        except TypeError:
            return

        obj['Rating'] = 0

        if obj['Media'] == 'song':

            if obj['DatePlayed']:
                obj['DatePlayed'] = Local(
                    obj['DatePlayed']).split('.')[0].replace('T', " ")

            self.rate_song(*values(obj, QU.update_song_rating_obj))

        self.jellyfin_db.update_reference(
            *values(obj, QUEM.update_reference_obj))
        LOG.info("USERDATA %s [%s] %s: %s", obj['Media'], obj['KodiId'],
                 obj['Id'], obj['Title'])

    @stop()
    @jellyfin_item()
    def remove(self, item_id, e_item):
        ''' This updates: Favorite, LastPlayedDate, Playcount, PlaybackPositionTicks
            Poster with progress bar

            This should address single song scenario, where server doesn't actually
            create an album for the song.
        '''
        obj = {'Id': item_id}

        try:
            obj['KodiId'] = e_item[0]
            obj['Media'] = e_item[4]
        except TypeError:
            return

        if obj['Media'] == 'song':

            self.remove_song(obj['KodiId'], obj['Id'])
            self.jellyfin_db.remove_wild_item(obj['id'])

            for item in self.jellyfin_db.get_item_by_wild_id(
                    *values(obj, QUEM.get_item_by_wild_obj)):
                if item[1] == 'album':

                    temp_obj = dict(obj)
                    temp_obj['ParentId'] = item[0]

                    if not self.jellyfin_db.get_item_by_parent_id(*values(
                            temp_obj, QUEM.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.jellyfin_db.get_item_by_parent_id(
                    *values(obj, QUEM.get_item_by_parent_song_obj)):
                self.remove_song(song[1], obj['Id'])
            else:
                self.jellyfin_db.remove_items_by_parent_id(
                    *values(obj, QUEM.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.jellyfin_db.get_item_by_parent_id(
                    *values(obj, QUEM.get_item_by_parent_album_obj)):

                temp_obj = dict(obj)
                temp_obj['ParentId'] = album[1]

                for song in self.jellyfin_db.get_item_by_parent_id(
                        *values(temp_obj, QUEM.get_item_by_parent_song_obj)):
                    self.remove_song(song[1], obj['Id'])
                else:
                    self.jellyfin_db.remove_items_by_parent_id(
                        *values(temp_obj, QUEM.delete_item_by_parent_song_obj))
                    self.jellyfin_db.remove_items_by_parent_id(*values(
                        temp_obj, QUEM.delete_item_by_parent_artist_obj))
                    self.remove_album(temp_obj['ParentId'], obj['Id'])
            else:
                self.jellyfin_db.remove_items_by_parent_id(
                    *values(obj, QUEM.delete_item_by_parent_album_obj))

            self.remove_artist(obj['KodiId'], obj['Id'])

        self.jellyfin_db.remove_item(*values(obj, QUEM.delete_item_obj))

    def remove_artist(self, kodi_id, item_id):

        self.artwork.delete(kodi_id, "artist")
        self.delete(kodi_id)
        LOG.info("DELETE artist [%s] %s", kodi_id, item_id)

    def remove_album(self, kodi_id, item_id):

        self.artwork.delete(kodi_id, "album")
        self.delete_album(kodi_id)
        LOG.info("DELETE album [%s] %s", kodi_id, item_id)

    def remove_song(self, kodi_id, item_id):

        self.artwork.delete(kodi_id, "song")
        self.delete_song(kodi_id)
        LOG.info("DELETE song [%s] %s", kodi_id, item_id)

    @jellyfin_item()
    def get_child(self, item_id, e_item):
        ''' Get all child elements from tv show jellyfin id.
        '''
        obj = {'Id': item_id}
        child = []

        try:
            obj['KodiId'] = e_item[0]
            obj['FileId'] = e_item[1]
            obj['ParentId'] = e_item[3]
            obj['Media'] = e_item[4]
        except TypeError:
            return child

        obj['ParentId'] = obj['KodiId']

        for album in self.jellyfin_db.get_item_by_parent_id(
                *values(obj, QUEM.get_item_by_parent_album_obj)):

            temp_obj = dict(obj)
            temp_obj['ParentId'] = album[1]
            child.append((album[0], ))

            for song in self.jellyfin_db.get_item_by_parent_id(
                    *values(temp_obj, QUEM.get_item_by_parent_song_obj)):
                child.append((song[0], ))

        return child
Пример #9
0
class TVShows(KodiDb):
    def __init__(self,
                 server,
                 embydb,
                 videodb,
                 direct_path,
                 update_library=False):

        self.server = server
        self.emby = embydb
        self.video = videodb
        self.direct_path = direct_path
        self.update_library = update_library

        self.emby_db = emby_db.EmbyDatabase(embydb.cursor)
        self.objects = Objects()
        self.item_ids = []

        KodiDb.__init__(self, videodb.cursor)

    def __getitem__(self, key):

        if key == 'Series':
            return self.tvshow
        elif key == 'Season':
            return self.season
        elif key == 'Episode':
            return self.episode
        elif key == 'UserData':
            return self.userdata
        elif key in 'Removed':
            return self.remove

    @stop()
    @emby_item()
    @library_check()
    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 tvshow_add(self, obj):
        ''' Add object to kodi.
        '''
        obj['RatingId'] = self.create_entry_rating()
        self.add_ratings(*values(obj, QU.add_rating_tvshow_obj))

        obj['Unique'] = self.create_entry_unique_id()
        self.add_unique_id(*values(obj, QU.add_unique_id_tvshow_obj))

        obj['TopPathId'] = self.add_path(obj['TopLevel'])
        self.update_path(*values(obj, QU.update_path_toptvshow_obj))

        obj['PathId'] = self.add_path(*values(obj, QU.get_path_obj))

        self.add(*values(obj, QU.add_tvshow_obj))
        self.emby_db.add_reference(*values(obj, QUEM.add_reference_tvshow_obj))
        LOG.info("ADD tvshow [%s/%s/%s] %s: %s", obj['TopPathId'],
                 obj['PathId'], obj['ShowId'], obj['Title'], obj['Id'])

    def tvshow_update(self, obj):
        ''' Update object to kodi.
        '''
        obj['RatingId'] = self.get_rating_id(
            *values(obj, QU.get_unique_id_tvshow_obj))
        self.update_ratings(*values(obj, QU.update_rating_tvshow_obj))

        obj['Unique'] = self.get_unique_id(
            *values(obj, QU.get_unique_id_tvshow_obj))
        self.update_unique_id(*values(obj, QU.update_unique_id_tvshow_obj))

        self.update(*values(obj, QU.update_tvshow_obj))
        self.emby_db.update_reference(*values(obj, QUEM.update_reference_obj))
        LOG.info("UPDATE tvshow [%s/%s] %s: %s", obj['PathId'], obj['ShowId'],
                 obj['Title'], obj['Id'])

    def get_path_filename(self, obj):
        ''' Get the path and build it into protocol://path
        '''
        if self.direct_path:

            if '\\' in obj['Path']:
                obj['Path'] = "%s\\" % obj['Path']
                obj['TopLevel'] = "%s\\" % dirname(dirname(obj['Path']))
            else:
                obj['Path'] = "%s/" % obj['Path']
                obj['TopLevel'] = "%s/" % dirname(dirname(obj['Path']))

            if not validate(obj['Path']):
                raise Exception("Failed to validate path. User stopped.")
        else:
            obj['TopLevel'] = "plugin://plugin.video.emby.tvshows/"
            obj['Path'] = "%s%s/" % (obj['TopLevel'], obj['Id'])

    @stop()
    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.
        '''
        API = api.API(item, self.server['auth/server-address'])
        obj = self.objects.map(item, 'Season')

        obj['ShowId'] = show_id

        if obj['ShowId'] is None:

            try:
                obj['ShowId'] = self.emby_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.emby_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'])

    @stop()
    @emby_item()
    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 episode_add(self, obj):
        ''' Add object to kodi.
        '''
        obj['RatingId'] = self.create_entry_rating()
        self.add_ratings(*values(obj, QU.add_rating_episode_obj))

        obj['Unique'] = self.create_entry_unique_id()
        self.add_unique_id(*values(obj, QU.add_unique_id_episode_obj))

        obj['PathId'] = self.add_path(*values(obj, QU.add_path_obj))
        obj['FileId'] = self.add_file(*values(obj, QU.add_file_obj))

        try:
            self.add_episode(*values(obj, QU.add_episode_obj))
        except sqlite3.IntegrityError as error:

            LOG.error("IntegrityError for %s", obj)
            obj['EpisodeId'] = self.create_entry_episode()

            return self.episode_add(obj)

        self.emby_db.add_reference(
            *values(obj, QUEM.add_reference_episode_obj))
        LOG.debug("ADD episode [%s/%s] %s: %s", obj['PathId'], obj['FileId'],
                  obj['Id'], obj['Title'])

    def episode_update(self, obj):
        ''' Update object to kodi.
        '''
        obj['RatingId'] = self.get_rating_id(
            *values(obj, QU.get_rating_episode_obj))
        self.update_ratings(*values(obj, QU.update_rating_episode_obj))

        obj['Unique'] = self.get_unique_id(
            *values(obj, QU.get_unique_id_episode_obj))
        self.update_unique_id(*values(obj, QU.update_unique_id_episode_obj))

        self.update_episode(*values(obj, QU.update_episode_obj))

        self.emby_db.update_reference(*values(obj, QUEM.update_reference_obj))
        self.emby_db.update_parent_id(
            *values(obj, QUEM.update_parent_episode_obj))
        LOG.debug("UPDATE episode [%s/%s] %s: %s", obj['PathId'],
                  obj['FileId'], obj['Id'], obj['Title'])

    def get_episode_path_filename(self, obj):
        ''' Get the path and build it into protocol://path
        '''
        if '\\' in obj['Path']:
            obj['Filename'] = obj['Path'].rsplit('\\', 1)[1]
        else:
            obj['Filename'] = obj['Path'].rsplit('/', 1)[1]

        if self.direct_path:

            if not validate(obj['Path']):
                raise Exception("Failed to validate path. User stopped.")

            obj['Path'] = obj['Path'].replace(obj['Filename'], "")
        else:
            obj['Path'] = "plugin://plugin.video.emby.tvshows/%s/" % obj[
                'SeriesId']
            params = {
                'filename': obj['Filename'].encode('utf-8'),
                'id': obj['Id'],
                'dbid': obj['EpisodeId'],
                'mode': "play"
            }
            obj['Filename'] = "%s?%s" % (obj['Path'], urllib.urlencode(params))

    def get_show_id(self, obj):
        obj['ShowId'] = self.emby_db.get_item_by_id(
            *values(obj, QUEM.get_item_series_obj))

        if obj['ShowId'] is None:

            try:
                self.tvshow(self.server['api'].get_item(obj['SeriesId']),
                            library=None)
                obj['ShowId'] = self.emby_db.get_item_by_id(
                    *values(obj, QUEM.get_item_series_obj))[0]
            except (TypeError, KeyError):
                LOG.error("Unable to add series %s", obj['SeriesId'])

                return False
        else:
            obj['ShowId'] = obj['ShowId'][0]

        self.item_ids.append(obj['SeriesId'])

        return True

    @stop()
    @emby_item()
    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'])

    @stop()
    @emby_item()
    def remove(self, item_id, e_item):
        ''' Remove showid, fileid, pathid, emby reference.
            There's no episodes left, delete show and any possible remaining seasons
        '''
        obj = {'Id': item_id}

        try:
            obj['KodiId'] = e_item[0]
            obj['FileId'] = e_item[1]
            obj['ParentId'] = e_item[3]
            obj['Media'] = e_item[4]
        except TypeError:
            return

        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(
                *values(obj, QUEM.delete_item_by_parent_season_obj))

            try:
                temp_obj['Id'] = season[0]
                temp_obj['ParentId'] = season[1]
            except TypeError:
                return

            if not self.emby_db.get_item_by_parent_id(
                    *values(obj, QUEM.get_item_by_parent_episode_obj)):

                self.remove_season(obj['ParentId'], obj['Id'])
                self.emby_db.remove_item(
                    *values(temp_obj, QUEM.delete_item_obj))

            temp_obj['Id'] = self.emby_db.get_item_by_kodi_id(
                *values(temp_obj, QUEM.get_item_by_parent_tvshow_obj))

            if not self.get_total_episodes(
                    *values(temp_obj, QU.get_total_episodes_obj)):

                for season in self.emby_db.get_item_by_parent_id(
                        *values(temp_obj, QUEM.get_item_by_parent_season_obj)):
                    self.remove_season(season[1], obj['Id'])
                else:
                    self.emby_db.remove_items_by_parent_id(*values(
                        temp_obj, QUEM.delete_item_by_parent_season_obj))

                self.remove_tvshow(temp_obj['ParentId'], obj['Id'])
                self.emby_db.remove_item(
                    *values(temp_obj, QUEM.delete_item_obj))

        elif obj['Media'] == 'tvshow':
            obj['ParentId'] = obj['KodiId']

            for season in self.emby_db.get_item_by_parent_id(
                    *values(obj, QUEM.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(*values(
                        temp_obj, QUEM.get_item_by_parent_episode_obj)):
                    self.remove_episode(episode[1], episode[2], obj['Id'])
                else:
                    self.emby_db.remove_items_by_parent_id(*values(
                        temp_obj, QUEM.delete_item_by_parent_episode_obj))
            else:
                self.emby_db.remove_items_by_parent_id(
                    *values(obj, QUEM.delete_item_by_parent_season_obj))

            self.remove_tvshow(obj['KodiId'], obj['Id'])

        elif obj['Media'] == 'season':

            for episode in self.emby_db.get_item_by_parent_id(
                    *values(obj, QUEM.get_item_by_parent_episode_obj)):
                self.remove_episode(episode[1], episode[2], obj['Id'])
            else:
                self.emby_db.remove_items_by_parent_id(
                    *values(obj, QUEM.delete_item_by_parent_episode_obj))

            self.remove_season(obj['KodiId'], obj['Id'])

            if not self.emby_db.get_item_by_parent_id(
                    *values(obj, QUEM.delete_item_by_parent_season_obj)):

                self.remove_tvshow(obj['ParentId'], obj['Id'])
                self.emby_db.remove_item_by_kodi_id(
                    *values(obj, QUEM.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'])
        else:
            self.emby_db.remove_media_by_parent_id(obj['Id'])

        self.emby_db.remove_item(*values(obj, QUEM.delete_item_obj))

    def remove_tvshow(self, kodi_id, item_id):

        self.artwork.delete(kodi_id, "tvshow")
        self.delete_tvshow(kodi_id)
        LOG.debug("DELETE tvshow [%s] %s", kodi_id, item_id)

    def remove_season(self, kodi_id, item_id):

        self.artwork.delete(kodi_id, "season")
        self.delete_season(kodi_id)
        LOG.info("DELETE season [%s] %s", kodi_id, item_id)

    def remove_episode(self, kodi_id, file_id, item_id):

        self.artwork.delete(kodi_id, "episode")
        self.delete_episode(kodi_id, file_id)
        LOG.info("DELETE episode [%s/%s] %s", file_id, kodi_id, item_id)

    @emby_item()
    def get_child(self, item_id, e_item):
        ''' Get all child elements from tv show emby id.
        '''
        obj = {'Id': item_id}
        child = []

        try:
            obj['KodiId'] = e_item[0]
            obj['FileId'] = e_item[1]
            obj['ParentId'] = e_item[3]
            obj['Media'] = e_item[4]
        except TypeError:
            return child

        obj['ParentId'] = obj['KodiId']

        for season in self.emby_db.get_item_by_parent_id(
                *values(obj, QUEM.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(
                    *values(temp_obj, QUEM.get_item_by_parent_episode_obj)):
                child.append(episode[0])

        for episode in self.emby_db.get_media_by_parent_id(obj['Id']):
            child.append(episode[0])

        return child
Пример #10
0
class MusicVideos(KodiDb):
    def __init__(self, server, embydb, videodb, direct_path):

        self.server = server
        self.emby = embydb
        self.video = videodb
        self.direct_path = direct_path

        self.emby_db = emby_db.EmbyDatabase(embydb.cursor)
        self.objects = Objects()
        self.item_ids = []

        KodiDb.__init__(self, videodb.cursor)

    def __getitem__(self, key):

        if key == 'MusicVideo':
            return self.musicvideo
        elif key == 'UserData':
            return self.userdata
        elif key in 'Removed':
            return self.remove

    @stop()
    @emby_item()
    @library_check()
    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 musicvideo_add(self, obj):
        ''' Add object to kodi.
        '''
        obj['PathId'] = self.add_path(*values(obj, QU.add_path_obj))
        obj['FileId'] = self.add_file(*values(obj, QU.add_file_obj))

        self.add(*values(obj, QU.add_musicvideo_obj))
        self.emby_db.add_reference(*values(obj, QUEM.add_reference_mvideo_obj))
        LOG.info("ADD mvideo [%s/%s/%s] %s: %s", obj['PathId'], obj['FileId'],
                 obj['MvideoId'], obj['Id'], obj['Title'])

    def musicvideo_update(self, obj):
        ''' Update object to kodi.
        '''
        self.update(*values(obj, QU.update_musicvideo_obj))
        self.emby_db.update_reference(*values(obj, QUEM.update_reference_obj))
        LOG.info("UPDATE mvideo [%s/%s/%s] %s: %s", obj['PathId'],
                 obj['FileId'], obj['MvideoId'], obj['Id'], obj['Title'])

    def get_path_filename(self, obj):
        ''' Get the path and filename and build it into protocol://path
        '''
        obj['Filename'] = obj['Path'].rsplit(
            '\\', 1)[1] if '\\' in obj['Path'] else obj['Path'].rsplit('/',
                                                                       1)[1]

        if self.direct_path:

            if not validate(obj['Path']):
                raise Exception("Failed to validate path. User stopped.")

            obj['Path'] = obj['Path'].replace(obj['Filename'], "")

        else:
            obj['Path'] = "plugin://plugin.video.emby.musicvideos/"
            params = {
                'filename': obj['Filename'].encode('utf-8'),
                'id': obj['Id'],
                'dbid': obj['MvideoId'],
                'mode': "play"
            }
            obj['Filename'] = "%s?%s" % (obj['Path'], urllib.urlencode(params))

    @stop()
    @emby_item()
    def userdata(self, item, e_item):
        ''' This updates: Favorite, LastPlayedDate, Playcount, PlaybackPositionTicks
            Poster with progress bar
        '''
        API = api.API(item, self.server['auth/server-address'])
        obj = self.objects.map(item, 'MusicVideoUserData')

        try:
            obj['MvideoId'] = 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_mvideo_obj))
        else:
            self.remove_tag(*values(obj, QU.delete_tag_mvideo_obj))

        self.add_playstate(*values(obj, QU.add_bookmark_obj))
        self.emby_db.update_reference(*values(obj, QUEM.update_reference_obj))
        LOG.info("USERDATA mvideo [%s/%s] %s: %s", obj['FileId'],
                 obj['MvideoId'], obj['Id'], obj['Title'])

    @stop()
    @emby_item()
    def remove(self, item_id, e_item):
        ''' Remove mvideoid, fileid, pathid, emby reference. 
        '''
        obj = {'Id': item_id}

        try:
            obj['MvideoId'] = e_item[0]
            obj['FileId'] = e_item[1]
            obj['PathId'] = e_item[2]
        except TypeError:
            return

        self.artwork.delete(obj['MvideoId'], "musicvideo")
        self.delete(*values(obj, QU.delete_musicvideo_obj))

        if self.direct_path:
            self.remove_path(*values(obj, QU.delete_path_obj))

        self.emby_db.remove_item(*values(obj, QUEM.delete_item_obj))
        LOG.info("DELETE musicvideo %s [%s/%s] %s", obj['MvideoId'],
                 obj['PathId'], obj['FileId'], obj['Id'])
Пример #11
0
version = "171076039"

from movies import Movies
from musicvideos import MusicVideos
from tvshows import TVShows
from music import Music
from obj import Objects
from actions import Actions
from actions import PlaylistWorker
from actions import on_play, on_update, special_listener

Objects().mapping()