# -*- coding: utf-8 -*- ################################################################################################## import datetime import logging import re import urllib from obj import Objects from kodi import MusicVideos as KodiDb, queries as QU from database import jellyfin_db, queries as QUEM from helper import api, catch, stop, validate, library_check, jellyfin_item, values, Local ################################################################################################## LOG = logging.getLogger("JELLYFIN."+__name__) ################################################################################################## class MusicVideos(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) def __getitem__(self, key): LOG.debug("__getitem__(%r)", key) if key == 'MusicVideo': return self.musicvideo elif key == 'UserData': return self.userdata elif key in 'Removed': return self.remove @stop() @jellyfin_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 Jellyfin, see if we can infer it from the sortname attribute. ''' 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, '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.jellyfin_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.jellyfin_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.jellyfin/" 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() @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, '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.jellyfin_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() @jellyfin_item() def remove(self, item_id, e_item): ''' Remove mvideoid, fileid, pathid, jellyfin 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.jellyfin_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'])