import os
import threading
import json
import uuid
import xbmc
import xbmcgui
import xbmcvfs
from helper import utils, player, queue, playerops
from emby import listitem, metadata
from database import dbio

ThemePlayerId = 0
ThemeKodiId = ""
ThemeKodiType = ""
ThemeKodiParentType = ""
ThemeKodiParentId = ""
VolumeFade = player.Volume
VolumeFadeInInterrupt = -1
ThemeQueue = queue.Queue()
RestoreBusy = threading.Lock()
ThemeBusy = threading.Lock()
TerminateTheme = False
TerminateRestore = False
TrackerEndTimeTicks = 0


# Player events (queued by monitor notifications)
def ThemePlay():
    if utils.DebugLog: xbmc.log("EMBY.monitor.themes: THREAD: --->[ ThemePlay ]", 1) # LOGDEBUG

    while True:
        ThemeReceived = ThemeQueue.get()

        if ThemeReceived == "QUIT":
            if utils.DebugLog: xbmc.log("EMBY.monitor.themes: THREAD: ---<[ ThemePlay ]", 1) # LOGDEBUG
            return

        if ThemeReceived == "STOP":
           # Terminate previous processes
            if RestoreBusy.locked():
                globals()['TerminateRestore'] = True

                with utils.SafeLock(RestoreBusy): # Wait for cancel
                    pass

            if ThemeBusy.locked():
                globals()['TerminateTheme'] = True

                with utils.SafeLock(ThemeBusy): # Wait for cancel
                    pass

            PlaybackStop()
        elif ThemeReceived == "FADE":
            with utils.SafeLock(ThemeBusy): # Wait for cancel
                pass

            with RestoreBusy:
                restore_Volume()
                globals()['TerminateRestore'] = False
        else:
            with utils.SafeLock(RestoreBusy): # Wait for cancel
                pass

            with utils.SafeLock(ThemeBusy):
                if PlaybackStop():
                    if ThemeReceived[0] and ThemeReceived[1]:
                        PlaybackStart(ThemeReceived[0], ThemeReceived[1])

                globals()['TerminateTheme'] = False

def PlaybackStart(PlayKodiType, PlayKodiId):
    if PlayKodiType not in ("movie", "tvshow"):
        return

    EmbyId = ""
    ListItem = None
    ServerId = ""
    EmbyServer = None
    PositionStart = 0
    PositionEnd = 0
    EndTimeTicks = 0
    ThemeFile = ""
    StartTimeTicks = 0
    KodiItem = {}
    globals()['TrackerEndTimeTicks'] = 0
    EmbyType = utils.KodiTypeMapping[PlayKodiType]

    for ServerId, EmbyServer in list(utils.EmbyServers.items()):
        EmbyDB = dbio.DBOpenRO(ServerId, "Theme")

        if utils.theme_enable_audio and utils.theme_enable_video: # Both
            if utils.theme_priority == "audio":
                EmbyId, EmbyMetaData = EmbyDB.get_ThemeAudio_by_KodiId_EmbyType(PlayKodiId, EmbyType)
                PlayerId = 0

                if not EmbyId:
                    EmbyId, EmbyMetaData = EmbyDB.get_ThemeVideo_by_KodiId_EmbyType(PlayKodiId, EmbyType)
                    PlayerId = 1
            else:
                EmbyId, EmbyMetaData = EmbyDB.get_ThemeVideo_by_KodiId_EmbyType(PlayKodiId, EmbyType)
                PlayerId = 1

                if not EmbyId:
                    EmbyId, EmbyMetaData = EmbyDB.get_ThemeAudio_by_KodiId_EmbyType(PlayKodiId, EmbyType)
                    PlayerId = 0
        elif utils.theme_enable_audio: # Audio only
            EmbyId, EmbyMetaData = EmbyDB.get_ThemeAudio_by_KodiId_EmbyType(PlayKodiId, EmbyType)
            PlayerId = 0
        else: # Video only
            EmbyId, EmbyMetaData = EmbyDB.get_ThemeVideo_by_KodiId_EmbyType(PlayKodiId, EmbyType)
            PlayerId = 1

        dbio.DBCloseRO(ServerId, "Theme")

        if EmbyId:
            break

    del EmbyDB

    if EmbyId: # real theme
        if player.PlayItem[0] and (player.PlayItem[0] != ThemeKodiId or player.PlayItem[1] != ThemeKodiType) or player.VideoPlayback not in ("READY", "THEME") or player.Trailers:
            return

        Item = json.loads(EmbyMetaData)
        MediaSourceId = Item['MediaSources'][0]['Id']
        PlaySessionId = str(uuid.uuid4()).replace("-", "")
        Path = os.path.join(utils.DownloadPath, "EMBY-themes", "")
        ThemeFile = xbmcvfs.translatePath(f"{Path}{ServerId}_{Item['Id']}.{Item.get('Container', 'ukn')}") # Downloaded theme

        if not xbmcvfs.exists(ThemeFile): # remote theme
            ThemeFile = f"{EmbyServer.ServerData['ServerUrl']}/emby/videos/{EmbyId}/stream?static=true&MediaSourceId={MediaSourceId}&PlaySessionId={PlaySessionId}&DeviceId={EmbyServer.ServerData['DeviceId']}&api_key={EmbyServer.ServerData['AccessToken']}|seekable=0&failonerror=false&verifypeer=false" # seekable=0 must be set -> Kodi uses playerid -1 and not touching playlists

        player.QueuedPlayingItem = [{'QueueableMediaTypes': ["Audio", "Video", "Photo"], 'CanSeek': True, 'IsPaused': False, 'ItemId': int(EmbyId), 'MediaSourceId': MediaSourceId, 'PlaySessionId': PlaySessionId, 'PositionTicks': 0, 'RunTimeTicks': 0, 'VolumeLevel': player.Volume, 'PlaybackRate': 1, 'Shuffle': False, 'RepeatMode': "RepeatNone", 'IsMuted': False}, None, None, None, EmbyServer, PlayerId, "", ""]
        ListItem = listitem.set_ListItem(Item, ServerId)
        ListItem.setPath(ThemeFile)
        KodiId = Item['KodiId']
    elif utils.theme_ThemeBySkipIntro != "off" or utils.theme_ThemeByContent != "off": # fake theme
        isSkipIntro = False
        KodiContentId = 0
        Runtime = 0
        VideoDB = dbio.DBOpenRO("video", "Theme")
        ContentKodiDatas = []

        if PlayKodiType == "tvshow":
            ContentKodiDatas = VideoDB.get_episodeid_path_runtime_by_tvshowid(PlayKodiId)
        else:
            ContentKodiDatas = VideoDB.get_path_runtime_by_movieid(PlayKodiId)

        for ContentKodiData in ContentKodiDatas:
            if not ContentKodiData[2]: # Runtime not set
                continue

            ContentPath = ContentKodiData[1].replace("http://127.0.0.1:57342", "").replace("dav://127.0.0.1:57342", "").replace("/emby_addon_mode", "").replace("|redirect-limit=1000&failonerror=false", "")
            KodiContentId = ContentKodiData[0]
            Runtime = round(float(ContentKodiData[2]))
            ContentMetadata = metadata.load_MetaData(ContentPath, False, False)
            PositionStart = ContentMetadata['MediaSources'][0][0]['IntroStartPositionTicks']
            PositionEnd = ContentMetadata['MediaSources'][0][0]['IntroEndPositionTicks']

            if PositionStart and PositionEnd and Runtime > 3: # Minimum 3 minutes runtime
                StartTimeTicks = (PositionStart + 15) * 10000000 # 15 seconds start offset
                EndTimeTicks = (PositionEnd) * 10000000 - StartTimeTicks

                if EndTimeTicks < 150000000: # Minimum 15 seconds intro
                    StartTimeTicks = 0
                    continue

                isSkipIntro = True
                KodiItem, KodiId, ThemeFile, PlayerId, MediaSourceId, PlaySessionId = load_KodiItem(KodiContentId, ContentPath, ContentMetadata, StartTimeTicks, utils.theme_ThemeBySkipIntro, VideoDB, PlayKodiType)
                break

        if not StartTimeTicks and utils.theme_ThemeByContent and KodiContentId:
            ThemeFile = ""
            StartTimeTicks = 5000000 * Runtime # start in the middle of the content runtime
            EndTimeTicks = utils.theme_ThemeByContentDuration * 10000000
            KodiItem, KodiId, ThemeFile, PlayerId, MediaSourceId, PlaySessionId = load_KodiItem(KodiContentId, ContentPath, ContentMetadata, StartTimeTicks, utils.theme_ThemeByContent, VideoDB, PlayKodiType)

        if KodiItem:
            if isSkipIntro:
                if utils.theme_ThemeBySkipIntro == "video": # Video
                    KodiItem['mediatype'] = "video"
                else:
                    KodiItem['mediatype'] = "song"
            else:
                if utils.theme_ThemeByContent == "video": # Video
                    KodiItem['mediatype'] = "video"
                else:
                    KodiItem['mediatype'] = "song"

            _, ListItem = listitem.set_ListItem_from_Kodi_database(KodiItem, ThemeFile)
            player.QueuedPlayingItem = [{'QueueableMediaTypes': ["Audio", "Video", "Photo"], 'CanSeek': True, 'IsPaused': False, 'ItemId': int(ContentMetadata['EmbyId']), 'MediaSourceId': MediaSourceId, 'PlaySessionId': PlaySessionId, 'PositionTicks': 0, 'RunTimeTicks': 0, 'VolumeLevel': player.Volume, 'PlaybackRate': 1, 'Shuffle': False, 'RepeatMode': "RepeatNone", 'IsMuted': False}, None, None, None, utils.EmbyServers[ContentMetadata['ServerId']], PlayerId, "", ""]

        dbio.DBCloseRO("video", "Theme")

    if ListItem:
        globals()['VolumeFade'] = 0
        VolumeOld = player.Volume

        if TerminateTheme:
            return

        if PlayerId:
            globals().update({"ThemePlayerId": PlayerId, "ThemeKodiParentId": PlayKodiId, "ThemeKodiParentType": PlayKodiType, "ThemeKodiId": KodiId, "ThemeKodiType": "video"})
        else:
            globals().update({"ThemePlayerId": PlayerId, "ThemeKodiParentId": PlayKodiId, "ThemeKodiParentType": PlayKodiType, "ThemeKodiId": KodiId, "ThemeKodiType": "song"})

        if player.PlayItem[0] and (player.PlayItem[0] != ThemeKodiId or player.PlayItem[1] != ThemeKodiType) or player.VideoPlayback not in ("READY", "THEME") or player.Trailers:
            return

        if utils.theme_fade_in:
            xbmc.executebuiltin("SetVolume(0)", False)

        player.VideoPlayback = "THEME"
        player.XbmcPlayer.play(ThemeFile, listitem=ListItem, windowed=True)
        del ListItem

        # Wait for playback start
        with utils.SafeLock(playerops.PlaybackToggleCondition):
            while not player.PlayItem[0]:
                if utils.DebugLog: xbmc.log("EMBY.hooks.themes (DEBUG): CONDITION: --->[ PlaybackToggleCondition ]", 1)
                Notified = False
                Wait = 30

                while Wait > 0:
                    if playerops.PlaybackToggleCondition.wait(timeout=0.1):
                        Notified = True
                        break

                    Wait -= 1

                if utils.DebugLog: xbmc.log("EMBY.hooks.themes (DEBUG): CONDITION: ---<[ PlaybackToggleCondition ]", 1)

                if not Notified:
                    xbmc.log("EMBY.hooks.themes: Playback play timeout", 3)
                    xbmc.executebuiltin(f"SetVolume({VolumeOld})", False)
                    break

        utils.close_busyDialog(True)

        # Fade volume
        if utils.theme_fade_in:
            with utils.SafeLock(playerops.AVStartedCondition):
                while not playerops.AVStarted:
                    if utils.DebugLog: xbmc.log("EMBY.hooks.themes (DEBUG): CONDITION: --->[ AVStartedCondition ]", 1)
                    Notified = False
                    Wait = 30

                    while Wait > 0:
                        if playerops.AVStartedCondition.wait(timeout=0.1):
                            Notified = True
                            break

                        Wait -= 1

                    if utils.DebugLog: xbmc.log("EMBY.hooks.themes (DEBUG): CONDITION: ---<[ AVStartedCondition ]", 1)

                    if not Notified:
                        xbmc.log("EMBY.hooks.themes: AVstart timeout", 3)
                        xbmc.executebuiltin(f"SetVolume({VolumeOld})", False)
                        return

            globals()['TrackerEndTimeTicks'] = EndTimeTicks

            while VolumeFade != VolumeOld:
                if TerminateTheme:
                    globals()['VolumeFadeInInterrupt'] = VolumeOld
                    break

                globals()['VolumeFade'] += 1
                xbmc.executebuiltin(f"SetVolume({VolumeFade})", False)

                if not check_ThemePlaying() or utils.sleep(utils.theme_fade_in):
                    xbmc.executebuiltin(f"SetVolume({VolumeOld})", False)
                    break

            globals()['VolumeFadeInInterrupt'] = -1
            player.Volume = VolumeOld
    else:
        globals()['TrackerEndTimeTicks'] = EndTimeTicks

def PlaybackStop():
    # No theme played
    if not ThemeKodiId or not player.PlayItem[0]:
        return True

    globals()['TrackerEndTimeTicks'] = 0

    if utils.theme_fade_out:
        if VolumeFadeInInterrupt == -1:
            VolumeOld = player.Volume
        else:
            VolumeOld = VolumeFadeInInterrupt

        while VolumeFade:
            globals()['VolumeFade'] -= 1
            xbmc.executebuiltin(f"SetVolume({VolumeFade})", False)

            if not check_ThemePlaying() or utils.sleep(utils.theme_fade_out):
                xbmc.executebuiltin(f"SetVolume({VolumeOld})", False)
                player.Volume = VolumeOld
                return False

            if TerminateTheme:
                player.Volume = VolumeOld
                return False

    utils.SendJson(f'{{"jsonrpc":"2.0","method":"Player.Stop","params":{{"playerid":{ThemePlayerId}}},"id":1}}', True)
    globals().update({"ThemePlayerId": 0, "ThemeKodiParentId": "", "ThemeKodiParentType": "", "ThemeKodiId": "", "ThemeKodiType": ""})

    # Wait for playback stop
    with utils.SafeLock(playerops.PlaybackToggleCondition):
        while player.PlayItem[0]:
            if utils.DebugLog: xbmc.log("EMBY.hooks.themes (DEBUG): CONDITION: --->[ PlaybackToggleCondition ]", 1)
            Notified = False
            Wait = 30

            while Wait > 0:
                if playerops.PlaybackToggleCondition.wait(timeout=0.1):
                    Notified = True
                    break
                Wait -= 1

            if utils.DebugLog: xbmc.log("EMBY.hooks.themes (DEBUG): CONDITION: ---<[ PlaybackToggleCondition ]", 1)

            if not Notified:
                xbmc.log("EMBY.hooks.themes: Playback stop timeout", 3)
                break

    if utils.theme_fade_out:
        utils.sleep(0.1) # Kodi needs time until playback actually stopped, monitor notification are not accurate
        xbmc.executebuiltin(f"SetVolume({VolumeOld})", False)
        player.Volume = VolumeOld

    return True

def restore_Volume():
    if utils.theme_fade_in:
        VolumeOld = player.Volume

        while VolumeFade != VolumeOld:
            if TerminateRestore:
                globals()['VolumeFadeInInterrupt'] = VolumeOld
                break

            globals()['VolumeFade'] += 1
            xbmc.executebuiltin(f"SetVolume({VolumeFade})", False)

            if not check_ThemePlaying() or utils.sleep(utils.theme_fade_in):
                xbmc.executebuiltin(f"SetVolume({VolumeOld})", False)
                break

        globals()['VolumeFadeInInterrupt'] = -1
        player.Volume = VolumeOld

def check_ThemePlaying():
    if not player.PlayItem[0] or player.PlayItem[0] != ThemeKodiId or player.PlayItem[1] != ThemeKodiType:
        globals().update({"ThemePlayerId": 0, "ThemeKodiParentId": "", "ThemeKodiParentType": "", "ThemeKodiId": "", "ThemeKodiType": ""})
        return False

    return True

def get_KodiIds():
    KodiId = 0
    Result = utils.SendJson('{"jsonrpc":"2.0","method":"XBMC.GetInfoLabels","params":{"labels": ["ListItem.DBTYPE", "ListItem.DBID", "ListItem.TVShowDBID"]},"id":1}', True).get("result", {})

    if Result:
        KodiType = Result.get("ListItem.DBTYPE", "")
        KodiTypeReal = KodiType

        if KodiType in ("episode", "season"):
            KodiId = Result.get("ListItem.TVShowDBID", 0)
            KodiType = "tvshow"
        else:
            KodiId = Result.get("ListItem.DBID", 0)

        return KodiType, KodiId, KodiTypeReal

    return "", 0, ""

def download():
    utils.close_dialog(10146) # addoninformation
    DownloadAudioThemes = False
    DownloadVideoThemes = False
    Path = os.path.join(utils.DownloadPath, "EMBY-themes", "")
    utils.mkDir(Path)
    DownloadAudioThemes = utils.Dialog.yesno(heading=utils.addon_name, message=utils.Translate(33758), yeslabel=utils.Translate(33760), nolabel=utils.Translate(33761), defaultbutton=11) # defaultbutton=11 = yes
    DownloadVideoThemes = utils.Dialog.yesno(heading=utils.addon_name, message=utils.Translate(33759), yeslabel=utils.Translate(33760), nolabel=utils.Translate(33761), defaultbutton=10) # defaultbutton=10 = no

    if not DownloadAudioThemes and not DownloadVideoThemes:
        return

    ProgressBar = xbmcgui.DialogProgressBG()
    ProgressBar.create(utils.Translate(33199), utils.Translate(33451))
    Themes = []

    for ServerId, EmbyServer in list(utils.EmbyServers.items()):
        EmbyDB = dbio.DBOpenRO(ServerId, "ThemeDownload")

        if DownloadAudioThemes:
            Themes += EmbyDB.get_ThemeAudio()

        if DownloadVideoThemes:
            Themes += EmbyDB.get_ThemeVideo()

        dbio.DBCloseRO(ServerId, "ThemeDownload")
        TotalItems = len(Themes) / 100

        for Index, Trailer in enumerate(Themes):
            Item = json.loads(Trailer[1])
            ProgressBar.update(int(Index / TotalItems), utils.Translate(33451), str(Trailer))
            FilePath = xbmcvfs.translatePath(f"{Path}{ServerId}_{Trailer[0]}.{Item.get('Container', 'ukn')}")

            if not xbmcvfs.exists(FilePath):
                FolderPath = xbmcvfs.translatePath(Path)

                if 'Size' not in Item or not Item['Size']:
                    if utils.DebugLog: xbmc.log(f"EMBY.monitor.themes: Theme has no filesize: {Item}", 3) # LOGERROR
                    continue

                EmbyServer.API.download_file(Trailer[0], "", FolderPath, FilePath, Item['Size'], Item['Id'], "", "", "", "")
            else:
                if utils.DebugLog: xbmc.log(f"EMBY.monitor.themes: Theme exists: {FilePath}", 1) # LOGDEBUG

    ProgressBar.close()
    del ProgressBar
    utils.Dialog.notification(heading=utils.addon_name, message=utils.Translate(33153), icon=utils.icon, time=utils.displayMessage, sound=False)

def PositionTracker():
    if utils.DebugLog: xbmc.log("EMBY.monitor.themes: THREAD: --->[ position tracker ]", 1) # LOGDEBUG

    while not utils.SystemShutdown:
        if utils.sleep(1):
            break

        if not TrackerEndTimeTicks:
            continue

        Position = int(playerops.PlayBackPosition())

        if Position < 1:
            continue

        if utils.DebugLog: xbmc.log(f"EMBY.monitor.themes: PositionTracker: Position: {Position} / ThemeEndPosition: {TrackerEndTimeTicks}", 1) # LOGDEBUG

        if Position > TrackerEndTimeTicks:
            ThemeQueue.put("STOP")

    if utils.DebugLog: xbmc.log("EMBY.monitor.themes: THREAD: ---<[ position tracker ]", 1) # LOGDEBUG

def monitor_Themes():
    if utils.DebugLog: xbmc.log("EMBY.hooks.themes: THREAD: --->[ Monitor themes ]", 1) # LOGDEBUG
    KodiTypeOld = ""
    KodiIdOld = ""
    utils.start_thread(ThemePlay, ())
    utils.start_thread(PositionTracker, ())

    while True:
        # check if themes enabled
        if utils.DebugLog: xbmc.log("EMBY.hooks.theme (DEBUG): CONDITION: --->[ SettingsChangedCondition ]", 1) # LOGDEBUG

        with utils.SafeLock(utils.SettingsChangedCondition):
            while not utils.theme_enable_audio and not utils.theme_enable_video:
                utils.SettingsChangedCondition.wait(timeout=0.1)

                if utils.SystemShutdown:
                    if utils.DebugLog:
                        xbmc.log("EMBY.monitor.themes (DEBUG): THREAD: ---<[ Monitor themes ]", 1) # LOGDEBUG
                        xbmc.log("EMBY.hooks.theme (DEBUG): CONDITION: ---<[ SettingsChangedCondition ]", 1) # LOGDEBUG

                    return

        if utils.DebugLog: xbmc.log("EMBY.hooks.theme (DEBUG): CONDITION: ---<[ SettingsChangedCondition ]", 1) # LOGDEBUG

        # Check if regular content is playing
        if utils.RemoteMode or (player.PlayItem[0] and (player.PlayItem[0] != ThemeKodiId or player.PlayItem[1] != ThemeKodiType) or player.VideoPlayback not in ("READY", "THEME") or player.Trailers):
            globals().update({"ThemePlayerId": 0, "ThemeKodiParentId": "", "ThemeKodiParentType": "", "ThemeKodiId": "", "ThemeKodiType": ""})
            KodiIdOld = ""
            KodiTypeOld = ""

            if utils.sleep(3):
                ThemeQueue.put("QUIT")
                if utils.DebugLog: xbmc.log("EMBY.monitor.themes (DEBUG): THREAD: ---<[ Monitor themes ]", 1) # LOGDEBUG
                return

            continue

        KodiTypeCompare, KodiIdCompare, KodiTypeReal = get_KodiIds()

        # Ignore navigation views
        if not utils.theme_enable_homescreen and xbmc.getCondVisibility('Window.IsActive(10000)'):
            ThemeQueue.put("STOP")
            continue

        WindowNav = -1

        if not utils.theme_enable_viewseries and KodiTypeReal == "tvshow":
            WindowNav = xbmc.getCondVisibility('Window.IsActive(10025)')

            if WindowNav:
                if utils.sleep(utils.theme_delay):
                    ThemeQueue.put("QUIT")
                    if utils.DebugLog: xbmc.log("EMBY.monitor.themes: THREAD: ---<[ Monitor themes ]", 1) # LOGDEBUG
                    return

                ThemeQueue.put("STOP")
                continue

        if not utils.theme_enable_viewseason and KodiTypeReal == "season":
            if WindowNav == -1:
                WindowNav = xbmc.getCondVisibility('Window.IsActive(10025)')

            if WindowNav:
                if utils.sleep(utils.theme_delay * 10):
                    ThemeQueue.put("QUIT")
                    if utils.DebugLog: xbmc.log("EMBY.monitor.themes: THREAD: ---<[ Monitor themes ]", 1) # LOGDEBUG
                    return

                ThemeQueue.put("STOP")
                continue

        if not utils.theme_enable_viewepisode and KodiTypeReal == "episode":
            if WindowNav == -1:
                WindowNav = xbmc.getCondVisibility('Window.IsActive(10025)')

            if WindowNav:
                if utils.sleep(utils.theme_delay * 10):
                    ThemeQueue.put("QUIT")
                    if utils.DebugLog: xbmc.log("EMBY.monitor.themes: THREAD: ---<[ Monitor themes ]", 1) # LOGDEBUG
                    return

                ThemeQueue.put("STOP")
                continue

        if not utils.theme_enable_viewmovie and KodiTypeReal == "movie":
            if WindowNav == -1:
                WindowNav = xbmc.getCondVisibility('Window.IsActive(10025)')

            if WindowNav:
                if utils.sleep(utils.theme_delay * 10):
                    ThemeQueue.put("QUIT")
                    if utils.DebugLog: xbmc.log("EMBY.monitor.themes: THREAD: ---<[ Monitor themes ]", 1) # LOGDEBUG
                    return

                ThemeQueue.put("STOP")
                continue

        # Ignore visualizations etc.
        if xbmc.getCondVisibility('Window.IsActive(12005)') or xbmc.getCondVisibility('Window.IsActive(12006)') or xbmc.getCondVisibility('Window.IsActive(10142)'):  # skip fullscreenvideo, visualisation, fullscreeninfo
            continue

        # Wait for navigation end
        ThemePlayThreadDelay = 0

        while ThemePlayThreadDelay < 10:
            ThemePlayThreadDelay += 1

            if utils.sleep(utils.theme_delay):
                ThemeQueue.put("QUIT")
                if utils.DebugLog: xbmc.log("EMBY.monitor.themes: THREAD: ---<[ Monitor themes ]", 1) # LOGDEBUG
                return

            KodiType, KodiId, KodiTypeReal = get_KodiIds()

            if KodiTypeCompare != KodiType or KodiIdCompare != KodiId:
                break
        else: # no break triggered
            # Check if item has changed
            if KodiIdOld != KodiId or KodiTypeOld != KodiType:
                KodiIdOld = KodiId
                KodiTypeOld = KodiType

                # Terminate previous processes
                if RestoreBusy.locked():
                    globals()['TerminateRestore'] = True

                if ThemeBusy.locked():
                    globals()['TerminateTheme'] = True

                # Run commands
                if ThemeKodiId and KodiId == ThemeKodiParentId and KodiType == ThemeKodiParentType:
                    ThemeQueue.put("FADE")
                else:
                    ThemeQueue.put(((KodiType, KodiId),))

def load_KodiItem(KodiContentId, ContentPath, ContentMetadata, StartTimeTicks, ThemeBy, VideoDB, PlayKodiType):
    MediaSourceId = ContentMetadata['MediaSources'][0][0]['Id']
    PlaySessionId = str(uuid.uuid4()).replace("-", "")

    if ContentMetadata['ServerId'] in utils.EmbyServers:
        if PlayKodiType == "tvshow":
            KodiItem = VideoDB.get_episode_metadata_for_listitem(KodiContentId, ContentPath)
        else:
            KodiItem = VideoDB.get_movie_metadata_for_listitem(KodiContentId, ContentPath)

        if ThemeBy == "video": # Video
            PlayerId = 1
            ThemeFile = f"{utils.EmbyServers[ContentMetadata['ServerId']].ServerData['ServerUrl']}/emby/videos/{ContentMetadata['EmbyId']}/stream.ts?MediaSourceId={MediaSourceId}&PlaySessionId={PlaySessionId}&DeviceId={utils.EmbyServers[ContentMetadata['ServerId']].ServerData['DeviceId']}&api_key={utils.EmbyServers[ContentMetadata['ServerId']].ServerData['AccessToken']}&StartTimeTicks={StartTimeTicks}&MaxAudioChannels=1&VideoCodec=h264&MaxHeight=1080&VideoBitrate=1000000&AudioCodec=aac&MaxFramerate=25&Profile=baseline&stream.ts|seekable=0&failonerror=false&verifypeer=false" # Works
        else: # Audio
            PlayerId = 0
            ThemeFile = f"{utils.EmbyServers[ContentMetadata['ServerId']].ServerData['ServerUrl']}/emby/audio/{ContentMetadata['EmbyId']}/stream.aac?MediaSourceId={MediaSourceId}&PlaySessionId={PlaySessionId}&DeviceId={utils.EmbyServers[ContentMetadata['ServerId']].ServerData['DeviceId']}&api_key={utils.EmbyServers[ContentMetadata['ServerId']].ServerData['AccessToken']}&StartTimeTicks={StartTimeTicks}&AudioCodec=aac&Profile=baseline&MaxAudioChannels=1&VideoStreamIndex-1&EnableAutoStreamCopy=false&VideoCodec=copy&stream.acc|seekable=0&failonerror=false&verifypeer=false" # Works

        KodiId = utils.set_EmbyId_ServerId_by_Fake_KodiId(ContentMetadata['EmbyId'], ContentMetadata['ServerId'])
        KodiItem['dbid'] = KodiId
        return KodiItem, KodiId, ThemeFile, PlayerId, MediaSourceId, PlaySessionId

    return None, 0, "", -1, "", ""
