Example #1
0
    def ServiceEntryPoint(self):
        
        ConnectionManager().checkServer()
        
        lastProgressUpdate = datetime.today()
        
        startupComplete = False
        #interval_FullSync = 600
        #interval_IncrementalSync = 300
        
        #cur_seconds_fullsync = interval_FullSync
        #cur_seconds_incrsync = interval_IncrementalSync
        
        user = UserClient()
        player = Player()
        ws = WebSocketThread()
        
        lastFile = None
        
        while not self.KodiMonitor.abortRequested():
            
            if self.KodiMonitor.waitForAbort(1):
                # Abort was requested while waiting. We should exit
                break
            
            if xbmc.Player().isPlaying():
                try:
                    playTime = xbmc.Player().getTime()
                    totalTime = xbmc.Player().getTotalTime()
                    currentFile = xbmc.Player().getPlayingFile()

                    if(player.played_information.get(currentFile) != None):
                        player.played_information[currentFile]["currentPosition"] = playTime
                    
                    # send update
                    td = datetime.today() - lastProgressUpdate
                    secDiff = td.seconds
                    if(secDiff > 3):
                        try:
                            player.reportPlayback()
                        except Exception, msg:
                            self.logMsg("Exception reporting progress: %s" % msg)
                            pass
                        lastProgressUpdate = datetime.today()
                    # only try autoplay when there's 20 seconds or less remaining and only once!
                    if (totalTime - playTime <= 20 and (lastFile==None or lastFile!=currentFile)):
                        lastFile = currentFile
                        player.autoPlayPlayback()
                    
                except Exception, e:
                    self.logMsg("Exception in Playback Monitor Service: %s" % e)
                    pass
Example #2
0
    def ServiceEntryPoint(self):

        kodiProfile = xbmc.translatePath("special://profile")

        # Server auto-detect
        ConnectionManager().checkServer()

        # Initialize important threads
        user = UserClient()
        player = Player()
        ws = WebSocketThread()
        library = LibrarySync()
        # Sync and progress report
        lastProgressUpdate = datetime.today()

        while not self.KodiMonitor.abortRequested():

            # Before proceeding, need to make sure:
            # 1. Server is online
            # 2. User is set
            # 3. User has access to the server

            if utils.window("kodiProfile_emby") != kodiProfile:
                # Profile change happened, terminate this thread
                self.logMsg("Kodi profile was: %s and changed to: %s. Terminating old Emby thread." % (kodiProfile, utils.window("kodiProfile_emby")), 1)
                break
            
            if utils.window('Server_online') == "true":
                
                # Emby server is online
                # Verify if user is set and has access to the server
                if (user.currUser is not None) and user.HasAccess:

                    # If an item is playing
                    if xbmc.Player().isPlaying():
                        try:
                            # Update and report progress
                            playTime = xbmc.Player().getTime()
                            totalTime = xbmc.Player().getTotalTime()
                            currentFile = player.currentFile

                            # Update positionticks
                            if player.played_information.get(currentFile) is not None:
                                player.played_information[currentFile]['currentPosition'] = playTime
                            
                            td = datetime.today() - lastProgressUpdate
                            secDiff = td.seconds
                            
                            # Report progress to Emby server
                            if (secDiff > 3):
                                player.reportPlayback()
                                lastProgressUpdate = datetime.today()
                            
                            elif utils.window('commandUpdate') == "true":
                                # Received a remote control command that
                                # requires updating immediately
                                utils.window('commandUpdate', clear=True)
                                player.reportPlayback()
                                lastProgressUpdate = da4tetime.today()
                            
                        except Exception as e:
                            self.logMsg("Exception in Playback Monitor Service: %s" % e, 1)
                            pass
                    else:
                        # Start up events
                        self.warn_auth = True
                        if utils.settings('supressConnectMsg') == "false":
                            if self.welcome_msg:
                                # Reset authentication warnings
                                self.welcome_msg = False
                                # Get additional users
                                additionalUsers = user.AdditionalUser
                                if additionalUsers:
                                    add = ", %s" % ", ".join(additionalUsers)
                                else:
                                    add = ""
                                xbmcgui.Dialog().notification("Emby server", "Welcome %s%s!" % (user.currUser, add), icon="special://home/addons/plugin.video.emby/icon.png", time=2000, sound=False)

                        # Start the Websocket Client
                        if (self.newWebSocketThread is None):
                            self.newWebSocketThread = "Started"
                            ws.start()
                        # Start the Library Sync Thread
                        if (self.newLibraryThread is None):
                            self.newLibraryThread = "Started"
                            library.start()
                            
                else:
                    
                    if (user.currUser is None) and self.warn_auth:
                        # Alert user is not authenticated and suppress future warning
                        self.warn_auth = False
                        self.logMsg("Not authenticated yet.", 1)

                    # User access is restricted.
                    # Keep verifying until access is granted
                    # unless server goes offline or Kodi is shut down.
                    while user.HasAccess == False:
                        # Verify access with an API call
                        user.hasAccess()

                        if utils.window('Server_online') != "true":
                            # Server went offline
                            break

                        if self.KodiMonitor.waitForAbort(5):
                            # Abort was requested while waiting. We should exit
                            break

            else:
                # Wait until Emby server is online
                # or Kodi is shut down.
                while not self.KodiMonitor.abortRequested():
                    
                    if user.getServer() == "":
                        # No server info set in add-on settings
                        pass
                    
                    elif user.getPublicUsers() == False:
                        # Server is offline.
                        # Alert the user and suppress future warning
                        if self.server_online:
                            self.logMsg("Server is offline.", 1)
                            utils.window('Server_online', value="false")
                            xbmcgui.Dialog().notification("Error connecting", "%s Server is unreachable." % self.addonName, icon="special://home/addons/plugin.video.emby/icon.png", sound=False)
                        self.server_online = False
                    
                    else:
                        # Server is online
                        if not self.server_online:
                            # Server was offline when Kodi started.
                            # Wait for server to be fully established.
                            if self.KodiMonitor.waitForAbort(5):
                                # Abort was requested while waiting.
                                break
                            # Alert the user that server is online.
                            xbmcgui.Dialog().notification("Emby server", "Welcome %s!" % user.currUser, icon="special://home/addons/plugin.video.emby/icon.png", time=2000, sound=False)
                        
                        self.server_online = True
                        self.logMsg("Server is online and ready.", 1)
                        utils.window('Server_online', value="true")
                        
                        # Start the User client
                        if self.newUserClient is None:
                            self.newUserClient = "Started"
                            user.start()
                        break

                    if self.KodiMonitor.waitForAbort(1):
                        # Abort was requested while waiting.
                        break

            if self.KodiMonitor.waitForAbort(1):
                # Abort was requested while waiting. We should exit
                break

        ##### Emby thread is terminating. #####

        # If music is enabled and direct stream for music is enabled
        # We use Kodi pathsubstitution to allow for music to play outside network
        # The setting needs to be set before Kodi starts.
        if utils.settings('enableMusicSync') == "true" and utils.settings('directstreammusic') == "true":
            # We need to keep track of the settings
            alternate = utils.settings('altip') == "true"
            pathsub = utils.settings('pathsub') == "true"
            
            if pathsub and not alternate:
                # Path sub in place, but primary address in use, remove it
                utils.pathsubstitution(False)
            elif not pathsub and alternate:
                # Path sub not in place, but secondary address in use, add it
                utils.pathsubstitution()
        
        if (self.newWebSocketThread is not None):
            ws.stopClient()

        if (self.newUserClient is not None):
            user.stopClient()

        self.logMsg("======== STOP %s ========" % self.addonName, 0)
Example #3
0
if __addon__.getSetting('useNextUp') == "true":
    newNextUpThread = NextUpUpdaterThread()
    newNextUpThread.start()
else:
    xbmc.log("XBMB3C Service NextUp Disabled")    
    
newSuggestedThread = None
if __addon__.getSetting('useSuggested') == "true":
    newSuggestedThread = SuggestedUpdaterThread()
    newSuggestedThread.start()
else:
    xbmc.log("XBMB3C Service Suggested Disabled")   

newWebSocketThread = None
if __addon__.getSetting('useWebSocketRemote') == "true":
    newWebSocketThread = WebSocketThread()
    newWebSocketThread.start()
else:
    xbmc.log("XBMB3C Service WebSocketRemote Disabled")

newMenuThread = None
if __addon__.getSetting('useMenuLoader') == "true":
    newMenuThread = LoadMenuOptionsThread()
    newMenuThread.start()
else:
    xbmc.log("XBMB3C Service MenuLoader Disabled")

artworkRotationThread = None    
if __addon__.getSetting('useBackgroundLoader') == "true":
    artworkRotationThread = ArtworkRotationThread()
    artworkRotationThread.start()
 
 
 if __addon__.getSetting('useNextUp') == "true":
     newNextUpThread = NextUpUpdaterThread()
     newNextUpThread.start()
 else:
     printDebug("XBMB3C Service NextUp Disabled")    
     
 if __addon__.getSetting('useSuggested') == "true":
     newSuggestedThread = SuggestedUpdaterThread()
     newSuggestedThread.start()
 else:
     printDebug("XBMB3C Service Suggested Disabled")   
 
 if __addon__.getSetting('useWebSocketRemote') == "true":
     newWebSocketThread = WebSocketThread()
     newWebSocketThread.start()
 else:
     printDebug("XBMB3C Service WebSocketRemote Disabled")
 
 if __addon__.getSetting('useMenuLoader') == "true":
     newMenuThread = LoadMenuOptionsThread()
     newMenuThread.start()
 else:
     printDebug("XBMB3C Service MenuLoader Disabled")
 
 if __addon__.getSetting('useBackgroundLoader') == "true":
     artworkRotationThread = ArtworkRotationThread()
     artworkRotationThread.start()
 else:
     printDebug("XBMB3C Service BackgroundLoader Disabled")
Example #5
0
class Player(xbmc.Player):

    # Borg - multiple instances, shared state
    _shared_state = {}

    xbmcplayer = xbmc.Player()
    doUtils = DownloadUtils()
    clientInfo = ClientInformation()
    ws = WebSocketThread()
    librarySync = LibrarySync()

    addonName = clientInfo.getAddonName()

    played_information = {}
    playStats = {}
    currentFile = None

    def __init__(self, *args):

        self.__dict__ = self._shared_state
        self.logMsg("Starting playback monitor.", 2)

    def logMsg(self, msg, lvl=1):

        self.className = self.__class__.__name__
        utils.logMsg("%s %s" % (self.addonName, self.className), msg, int(lvl))

    def GetPlayStats(self):
        return self.playStats

    def onPlayBackStarted(self):
        # Will be called when xbmc starts playing a file
        xbmcplayer = self.xbmcplayer
        self.stopAll()

        # Get current file
        try:
            currentFile = xbmcplayer.getPlayingFile()
            xbmc.sleep(300)
        except:
            currentFile = ""
            count = 0
            while not currentFile:
                xbmc.sleep(100)
                try:
                    currentFile = xbmcplayer.getPlayingFile()
                except:
                    pass

                if count == 5:  # try 5 times
                    self.logMsg("Cancelling playback report...", 1)
                    break
                else:
                    count += 1

        if currentFile:

            self.currentFile = currentFile

            # We may need to wait for info to be set in kodi monitor
            itemId = utils.window("%sitem_id" % currentFile)
            tryCount = 0
            while not itemId:

                xbmc.sleep(200)
                itemId = utils.window("%sitem_id" % currentFile)
                if tryCount == 20:  # try 20 times or about 10 seconds
                    self.logMsg(
                        "Could not find itemId, cancelling playback report...",
                        1)
                    break
                else:
                    tryCount += 1

            else:
                self.logMsg(
                    "ONPLAYBACK_STARTED: %s ITEMID: %s" %
                    (currentFile, itemId), 0)

                # Only proceed if an itemId was found.
                runtime = utils.window("%sruntimeticks" % currentFile)
                refresh_id = utils.window("%srefresh_id" % currentFile)
                playMethod = utils.window("%splaymethod" % currentFile)
                itemType = utils.window("%stype" % currentFile)
                seekTime = xbmcplayer.getTime()

                # Get playback volume
                volume_query = '{"jsonrpc": "2.0", "method": "Application.GetProperties", "params": {"properties": ["volume","muted"]}, "id": 1}'
                result = xbmc.executeJSONRPC(volume_query)
                result = json.loads(result)
                result = result.get('result')

                volume = result.get('volume')
                muted = result.get('muted')

                # Postdata structure to send to Emby server
                url = "{server}/mediabrowser/Sessions/Playing"
                postdata = {
                    'QueueableMediaTypes': "Video",
                    'CanSeek': True,
                    'ItemId': itemId,
                    'MediaSourceId': itemId,
                    'PlayMethod': playMethod,
                    'VolumeLevel': volume,
                    'PositionTicks': int(seekTime * 10000000),
                    'IsMuted': muted
                }

                # Get the current audio track and subtitles
                if playMethod == "Transcode":
                    # property set in PlayUtils.py
                    postdata['AudioStreamIndex'] = utils.window(
                        "%sAudioStreamIndex" % currentFile)
                    postdata['SubtitleStreamIndex'] = utils.window(
                        "%sSubtitleStreamIndex" % currentFile)

                else:
                    # Get the current kodi audio and subtitles and convert to Emby equivalent
                    track_query = '{"jsonrpc": "2.0", "method": "Player.GetProperties",  "params": {"playerid": 1,"properties": ["currentsubtitle","currentaudiostream","subtitleenabled"]} , "id": 1}'
                    result = xbmc.executeJSONRPC(track_query)
                    result = json.loads(result)
                    result = result.get('result')

                    try:  # Audio tracks
                        indexAudio = result['currentaudiostream']['index']
                    except (KeyError, TypeError):
                        indexAudio = 0

                    try:  # Subtitles tracks
                        indexSubs = result['currentsubtitle']['index']
                    except (KeyError, TypeError):
                        indexSubs = 0

                    try:  # If subtitles are enabled
                        subsEnabled = result['subtitleenabled']
                    except (KeyError, TypeError):
                        subsEnabled = ""

                    # Postdata for the audio
                    postdata['AudioStreamIndex'] = indexAudio + 1

                    # Postdata for the subtitles
                    if subsEnabled and len(
                            xbmc.Player().getAvailableSubtitleStreams()) > 0:

                        # Number of audiotracks to help get Emby Index
                        audioTracks = len(
                            xbmc.Player().getAvailableAudioStreams())
                        mapping = utils.window("%sIndexMapping" % currentFile)

                        if mapping:  # Set in PlaybackUtils.py

                            self.logMsg(
                                "Mapping for external subtitles index: %s" %
                                mapping, 2)
                            externalIndex = json.loads(mapping)

                            if externalIndex.get(str(indexSubs)):
                                # If the current subtitle is in the mapping
                                postdata[
                                    'SubtitleStreamIndex'] = externalIndex[str(
                                        indexSubs)]
                            else:
                                # Internal subtitle currently selected
                                postdata[
                                    'SubtitleStreamIndex'] = indexSubs - len(
                                        externalIndex) + audioTracks + 1

                        else:  # Direct paths enabled scenario or no external subtitles set
                            postdata[
                                'SubtitleStreamIndex'] = indexSubs + audioTracks + 1
                    else:
                        postdata['SubtitleStreamIndex'] = ""

                # Post playback to server
                self.logMsg("Sending POST play started: %s." % postdata, 2)
                self.doUtils.downloadUrl(url, postBody=postdata, type="POST")

                # Ensure we do have a runtime
                try:
                    runtime = int(runtime)
                except ValueError:
                    runtime = xbmcplayer.getTotalTime()
                    self.logMsg(
                        "Runtime is missing, grabbing runtime from Kodi player: %s"
                        % runtime, 1)

                # Save data map for updates and position calls
                data = {
                    'runtime': runtime,
                    'item_id': itemId,
                    'refresh_id': refresh_id,
                    'currentfile': currentFile,
                    'AudioStreamIndex': postdata['AudioStreamIndex'],
                    'SubtitleStreamIndex': postdata['SubtitleStreamIndex'],
                    'playmethod': playMethod,
                    'Type': itemType,
                    'currentPosition': int(seekTime)
                }

                self.played_information[currentFile] = data
                self.logMsg("ADDING_FILE: %s" % self.played_information, 1)

                # log some playback stats
                '''if(itemType != None):
                    if(self.playStats.get(itemType) != None):
                        count = self.playStats.get(itemType) + 1
                        self.playStats[itemType] = count
                    else:
                        self.playStats[itemType] = 1
                        
                if(playMethod != None):
                    if(self.playStats.get(playMethod) != None):
                        count = self.playStats.get(playMethod) + 1
                        self.playStats[playMethod] = count
                    else:
                        self.playStats[playMethod] = 1'''

    def reportPlayback(self):

        self.logMsg("reportPlayback Called", 2)
        xbmcplayer = self.xbmcplayer

        # Get current file
        currentFile = self.currentFile
        data = self.played_information.get(currentFile)

        # only report playback if emby has initiated the playback (item_id has value)
        if data:
            # Get playback information
            itemId = data['item_id']
            audioindex = data['AudioStreamIndex']
            subtitleindex = data['SubtitleStreamIndex']
            playTime = data['currentPosition']
            playMethod = data['playmethod']
            paused = data.get('paused', False)

            # Get playback volume
            volume_query = '{"jsonrpc": "2.0", "method": "Application.GetProperties", "params": {"properties": ["volume","muted"]}, "id": 1}'
            result = xbmc.executeJSONRPC(volume_query)
            result = json.loads(result)
            result = result.get('result')

            volume = result.get('volume')
            muted = result.get('muted')

            # Postdata for the websocketclient report
            postdata = {
                'QueueableMediaTypes': "Video",
                'CanSeek': True,
                'ItemId': itemId,
                'MediaSourceId': itemId,
                'PlayMethod': playMethod,
                'PositionTicks': int(playTime * 10000000),
                'IsPaused': paused,
                'VolumeLevel': volume,
                'IsMuted': muted
            }

            if playMethod == "Transcode":
                # Track can't be changed, keep reporting the same index
                postdata['AudioStreamIndex'] = audioindex
                postdata['AudioStreamIndex'] = subtitleindex

            else:
                # Get current audio and subtitles track
                track_query = '{"jsonrpc": "2.0", "method": "Player.GetProperties",  "params": {"playerid":1,"properties": ["currentsubtitle","currentaudiostream","subtitleenabled"]} , "id": 1}'
                result = xbmc.executeJSONRPC(track_query)
                result = json.loads(result)
                result = result.get('result')

                try:  # Audio tracks
                    indexAudio = result['currentaudiostream']['index']
                except (KeyError, TypeError):
                    indexAudio = 0

                try:  # Subtitles tracks
                    indexSubs = result['currentsubtitle']['index']
                except (KeyError, TypeError):
                    indexSubs = 0

                try:  # If subtitles are enabled
                    subsEnabled = result['subtitleenabled']
                except (KeyError, TypeError):
                    subsEnabled = ""

                # Postdata for the audio
                data['AudioStreamIndex'], postdata['AudioStreamIndex'] = [
                    indexAudio + 1
                ] * 2

                # Postdata for the subtitles
                if subsEnabled and len(
                        xbmc.Player().getAvailableSubtitleStreams()) > 0:

                    # Number of audiotracks to help get Emby Index
                    audioTracks = len(xbmc.Player().getAvailableAudioStreams())
                    mapping = utils.window("%sIndexMapping" % currentFile)

                    if mapping:  # Set in PlaybackUtils.py

                        self.logMsg(
                            "Mapping for external subtitles index: %s" %
                            mapping, 2)
                        externalIndex = json.loads(mapping)

                        if externalIndex.get(str(indexSubs)):
                            # If the current subtitle is in the mapping
                            data['SubtitleStreamIndex'], postdata[
                                'SubtitleStreamIndex'] = [
                                    externalIndex[str(indexSubs)]
                                ] * 2
                        else:
                            # Internal subtitle currently selected
                            data['SubtitleStreamIndex'], postdata[
                                'SubtitleStreamIndex'] = [
                                    indexSubs - len(externalIndex) +
                                    audioTracks + 1
                                ] * 2

                    else:  # Direct paths enabled scenario or no external subtitles set
                        data['SubtitleStreamIndex'], postdata[
                            'SubtitleStreamIndex'] = [
                                indexSubs + audioTracks + 1
                            ] * 2
                else:
                    data['SubtitleStreamIndex'], postdata[
                        'SubtitleStreamIndex'] = [""] * 2

            # Report progress via websocketclient
            postdata = json.dumps(postdata)
            self.logMsg("Report: %s" % postdata, 2)
            self.ws.sendProgressUpdate(postdata)

    def onPlayBackPaused(self):

        currentFile = self.currentFile
        self.logMsg("PLAYBACK_PAUSED: %s" % currentFile, 2)

        if self.played_information.get(currentFile):
            self.played_information[currentFile]['paused'] = True

            self.reportPlayback()

    def onPlayBackResumed(self):

        currentFile = self.currentFile
        self.logMsg("PLAYBACK_RESUMED: %s" % currentFile, 2)

        if self.played_information.get(currentFile):
            self.played_information[currentFile]['paused'] = False

            self.reportPlayback()

    def onPlayBackSeek(self, time, seekOffset):
        # Make position when seeking a bit more accurate
        currentFile = self.currentFile
        self.logMsg("PLAYBACK_SEEK: %s" % currentFile, 2)

        if self.played_information.get(currentFile):
            position = self.xbmcplayer.getTime()
            self.played_information[currentFile]['currentPosition'] = position

            self.reportPlayback()

    def onPlayBackStopped(self):
        # Will be called when user stops xbmc playing a file
        self.logMsg("ONPLAYBACK_STOPPED", 2)
        self.stopAll()

    def onPlayBackEnded(self):
        # Will be called when xbmc stops playing a file
        self.logMsg("ONPLAYBACK_ENDED", 2)
        self.stopAll()

    def stopAll(self):

        if not self.played_information:
            return

        self.logMsg("Played_information: %s" % self.played_information, 1)
        # Process each items
        for item in self.played_information:

            data = self.played_information.get(item)
            if data:

                self.logMsg("Item path: %s" % item, 2)
                self.logMsg("Item data: %s" % data, 2)

                runtime = data['runtime']
                currentPosition = data['currentPosition']
                itemId = data['item_id']
                refresh_id = data['refresh_id']
                currentFile = data['currentfile']
                type = data['Type']
                playMethod = data['playmethod']

                if currentPosition and runtime:
                    percentComplete = (currentPosition *
                                       10000000) / int(runtime)
                    markPlayedAt = float(utils.settings('markPlayed')) / 100

                    self.logMsg(
                        "Percent complete: %s Mark played at: %s" %
                        (percentComplete, markPlayedAt), 1)
                    # Prevent manually mark as watched in Kodi monitor > WriteKodiVideoDB().UpdatePlaycountFromKodi()
                    utils.window('SkipWatched%s' % itemId, "true")

                    self.stopPlayback(data)
                    offerDelete = utils.settings('offerDelete') == "true"
                    offerTypeDelete = False

                    if type == "Episode" and utils.settings(
                            'offerDeleteTV') == "true":
                        offerTypeDelete = True

                    elif type == "Movie" and utils.settings(
                            'offerDeleteMovies') == "true":
                        offerTypeDelete = True

                    if percentComplete >= markPlayedAt and offerDelete and offerTypeDelete:
                        # Make the bigger setting be able to disable option easily.
                        self.logMsg("Offering deletion for: %s." % itemId, 1)
                        return_value = xbmcgui.Dialog().yesno(
                            "Offer Delete",
                            "Delete %s" % currentFile.split("/")[-1],
                            "on Emby Server?")
                        if return_value:
                            # Delete Kodi entry before Emby
                            listItem = [itemId]
                            LibrarySync().removefromDB(listItem, True)

                # Stop transcoding
                if playMethod == "Transcode":
                    self.logMsg("Transcoding for %s terminated." % itemId, 1)
                    deviceId = self.clientInfo.getMachineId()
                    url = "{server}/mediabrowser/Videos/ActiveEncodings?DeviceId=%s" % deviceId
                    self.doUtils.downloadUrl(url, type="DELETE")

        self.played_information.clear()

    def stopPlayback(self, data):

        self.logMsg("stopPlayback called", 2)

        itemId = data['item_id']
        currentPosition = data['currentPosition']
        positionTicks = int(currentPosition * 10000000)

        url = "{server}/mediabrowser/Sessions/Playing/Stopped"
        postdata = {
            'ItemId': itemId,
            'MediaSourceId': itemId,
            'PositionTicks': positionTicks
        }

        self.doUtils.downloadUrl(url, postBody=postdata, type="POST")
        printDebug("XBMB3C Service RandomInfo Disabled")

    if __addon__.getSetting('useNextUp') == "true":
        newNextUpThread = NextUpUpdaterThread()
        newNextUpThread.start()
    else:
        printDebug("XBMB3C Service NextUp Disabled")

    if __addon__.getSetting('useSuggested') == "true":
        newSuggestedThread = SuggestedUpdaterThread()
        newSuggestedThread.start()
    else:
        printDebug("XBMB3C Service Suggested Disabled")

    if __addon__.getSetting('useWebSocketRemote') == "true":
        newWebSocketThread = WebSocketThread()
        newWebSocketThread.start()
    else:
        printDebug("XBMB3C Service WebSocketRemote Disabled")

    if __addon__.getSetting('useMenuLoader') == "true":
        newMenuThread = LoadMenuOptionsThread()
        newMenuThread.start()
    else:
        printDebug("XBMB3C Service MenuLoader Disabled")

    if __addon__.getSetting('useBackgroundLoader') == "true":
        artworkRotationThread = ArtworkRotationThread()
        artworkRotationThread.start()
    else:
        printDebug("XBMB3C Service BackgroundLoader Disabled")
Example #7
0
    def ServiceEntryPoint(self):
        
        WINDOW = self.WINDOW
        addon = xbmcaddon.Addon(id=self.clientInfo.getAddonId())
        WINDOW.setProperty("Server_online", "")
        self.WINDOW.setProperty("Server_status", "")
        WINDOW.setProperty("Emby_Service_Timestamp", str(int(time.time())))
        
        ConnectionManager().checkServer()
        lastProgressUpdate = datetime.today()
        startupComplete = False
        
        user = UserClient()
        player = Player()
        ws = WebSocketThread()
        
        lastFile = None
        
        while not self.KodiMonitor.abortRequested():
            #WINDOW.setProperty("Emby_Service_Timestamp", str(int(time.time())))
                     
            if self.KodiMonitor.waitForAbort(1):
                # Abort was requested while waiting. We should exit
                break

            if WINDOW.getProperty('Server_online') == "true":
                # Server is online
                if (user.currUser != None) and (user.HasAccess == True):
                    self.warn_auth = True
                    if addon.getSetting('supressConnectMsg') == "false":
                        if self.welcome_msg:
                            # Reset authentication warnings
                            self.welcome_msg = False
                            xbmcgui.Dialog().notification("Emby server", "Welcome %s!" % user.currUser, time=2000, sound=False)

                    # Correctly launch the websocket, if user manually launches the add-on
                    if (self.newWebSocketThread == None):
                        self.newWebSocketThread = "Started"
                        ws.start()

                    if xbmc.Player().isPlaying():
                        #WINDOW.setProperty("Emby_Service_Timestamp", str(int(time.time())))
                        try:
                            playTime = xbmc.Player().getTime()
                            totalTime = xbmc.Player().getTotalTime()
                            currentFile = xbmc.Player().getPlayingFile()

                            if(player.played_information.get(currentFile) != None):
                                player.played_information[currentFile]["currentPosition"] = playTime
                            
                            # send update
                            td = datetime.today() - lastProgressUpdate
                            secDiff = td.seconds
                            if(secDiff > 3):
                                try:
                                    player.reportPlayback()
                                except Exception, msg:
                                    self.logMsg("Exception reporting progress: %s" % msg)
                                    pass
                                lastProgressUpdate = datetime.today()
                            elif WINDOW.getProperty('commandUpdate') == "true":
                                try:
                                    WINDOW.clearProperty('commandUpdate')
                                    player.reportPlayback()
                                except: pass
                                lastProgressUpdate = datetime.today()
                            
                        except Exception, e:
                            self.logMsg("Exception in Playback Monitor Service: %s" % e)
                            pass

                    else:
                        #full sync
                        if (startupComplete == False):
                            self.logMsg("Doing_Db_Sync: syncDatabase (Started)")
                            libSync = librarySync.FullLibrarySync()
                            self.logMsg("Doing_Db_Sync: syncDatabase (Finished) " + str(libSync))
                            #WINDOW.setProperty("Emby_Service_Timestamp", str(int(time.time())))
                            if (libSync):
                                startupComplete = True
                        else:
                            if self.KodiMonitor.waitForAbort(1):
                                # Abort was requested while waiting. We should exit
                                break
Example #8
0
class Player( xbmc.Player ):

    # Borg - multiple instances, shared state
    _shared_state = {}
    
    xbmcplayer = xbmc.Player()
    doUtils = DownloadUtils()
    clientInfo = ClientInformation()
    ws = WebSocketThread()

    addonName = clientInfo.getAddonName()
    addonId = clientInfo.getAddonId()
    addon = xbmcaddon.Addon(id=addonId)

    WINDOW = xbmcgui.Window(10000)

    logLevel = 0
    played_information = {}
    settings = None
    playStats = {}
    
    def __init__( self, *args ):
        
        self.__dict__ = self._shared_state
        self.logMsg("Starting playback monitor service", 1)
        
    def logMsg(self, msg, lvl=1):
        
        self.className = self.__class__.__name__
        utils.logMsg("%s %s" % (self.addonName, self.className), msg, int(lvl))      
    
    def hasData(self, data):
        if(data == None or len(data) == 0 or data == "None"):
            return False
        else:
            return True 
    
    def stopAll(self):

        self.ws.processPendingActions()
        if(len(self.played_information) == 0):
            return 
            
        addonSettings = xbmcaddon.Addon(id='plugin.video.emby')
        self.logMsg("emby Service -> played_information : " + str(self.played_information))
        
        for item_url in self.played_information:
            data = self.played_information.get(item_url)
            
            if (data is not None):
                self.logMsg("emby Service -> item_url  : " + item_url)
                self.logMsg("emby Service -> item_data : " + str(data))
                
                runtime = data.get("runtime")
                currentPosition = data.get("currentPosition")
                item_id = data.get("item_id")
                refresh_id = data.get("refresh_id")
                currentFile = data.get("currentfile")
                type = data.get("Type")

                if(currentPosition != None and self.hasData(runtime)):
                    runtimeTicks = int(runtime)
                    self.logMsg("emby Service -> runtimeticks:" + str(runtimeTicks))
                    percentComplete = (currentPosition * 10000000) / runtimeTicks
                    markPlayedAt = float(90) / 100    

                    self.logMsg("emby Service -> Percent Complete:" + str(percentComplete) + " Mark Played At:" + str(markPlayedAt))
                    self.stopPlayback(data)
                    
                if(refresh_id != None):
                    #report updates playcount and resume status to Kodi and MB3
                    librarySync.updatePlayCount(item_id)
                    
                
        self.played_information.clear()

        # stop transcoding - todo check we are actually transcoding?
        clientInfo = ClientInformation()
        txt_mac = clientInfo.getMachineId()
        url = "{server}/mediabrowser/Videos/ActiveEncodings"
        url = url + '?DeviceId=' + txt_mac
        self.doUtils.downloadUrl(url, type="DELETE")
    
    def stopPlayback(self, data):
        
        self.logMsg("stopPlayback called", 2)
        
        item_id = data.get("item_id")
        audioindex = data.get("AudioStreamIndex")
        subtitleindex = data.get("SubtitleStreamIndex")
        playMethod = data.get("playmethod")
        currentPosition = data.get("currentPosition")
        positionTicks = int(currentPosition * 10000000)

        url = "{server}/mediabrowser/Sessions/Playing/Stopped"
        
        postdata = {
            'QueueableMediaTypes': "Video",
            'CanSeek': True,
            'ItemId': item_id,
            'MediaSourceId': item_id,
            'PlayMethod': playMethod,
            'PositionTicks': positionTicks
        }

        if audioindex:
            postdata['AudioStreamIndex'] = audioindex

        if subtitleindex:
            postdata['SubtitleStreamIndex'] = subtitleindex    
            
        self.doUtils.downloadUrl(url, postBody=postdata, type="POST")
    
    def reportPlayback(self):
        
        self.logMsg("reportPlayback Called", 2)
        xbmcplayer = self.xbmcplayer

        currentFile = xbmcplayer.getPlayingFile()
        data = self.played_information.get(currentFile)

        # only report playback if emby has initiated the playback (item_id has value)
        if (data is not None) and (data.get("item_id") is not None):

            # Get playback information
            item_id = data.get("item_id")
            audioindex = data.get("AudioStreamIndex")
            subtitleindex = data.get("SubtitleStreamIndex")
            playTime = data.get("currentPosition")
            playMethod = data.get("playmethod")
            paused = data.get("paused")
            
            if paused is None:
                paused = False

            #url = "{server}/mediabrowser/Sessions/Playing/Progress" 
            postdata = {
                'QueueableMediaTypes': "Video",
                'CanSeek': True,
                'ItemId': item_id,
                'MediaSourceId': item_id,
                'IsPaused': paused,
                'PlayMethod': playMethod
            }

            if playTime:
                postdata['PositionTicks'] = int(playTime * 10000000)

            if audioindex:
                postdata['AudioStreamIndex'] = audioindex

            if subtitleindex:
                postdata['SubtitleStreamIndex'] = subtitleindex

            postdata = json.dumps(postdata)
            self.logMsg("Report: %s" % postdata)
            self.ws.sendProgressUpdate(postdata)
    
    def onPlayBackPaused( self ):
        currentFile = xbmc.Player().getPlayingFile()
        self.logMsg("PLAYBACK_PAUSED : " + currentFile,2)
        if(self.played_information.get(currentFile) != None):
            self.played_information[currentFile]["paused"] = "true"
        self.reportPlayback()
    
    def onPlayBackResumed( self ):
        currentFile = xbmc.Player().getPlayingFile()
        self.logMsg("PLAYBACK_RESUMED : " + currentFile,2)
        if(self.played_information.get(currentFile) != None):
            self.played_information[currentFile]["paused"] = "false"
        self.reportPlayback()
    
    def onPlayBackSeek( self, time, seekOffset ):
        self.logMsg("PLAYBACK_SEEK",2)
        self.reportPlayback()
        
    def onPlayBackStarted( self ):
        # Will be called when xbmc starts playing a file
        WINDOW = self.WINDOW
        xbmcplayer = self.xbmcplayer
        self.stopAll()
        
        if xbmcplayer.isPlaying():
            currentFile = xbmcplayer.getPlayingFile()
            self.logMsg("onPlayBackStarted: %s" % currentFile, 0)
            
            # we may need to wait until the info is available
            item_id = WINDOW.getProperty(currentFile + "item_id")
            tryCount = 0
            while(item_id == None or item_id == ""):
                xbmc.sleep(500)
                item_id = WINDOW.getProperty(currentFile + "item_id")
                tryCount += 1
                if(tryCount == 20): # try 20 times or about 10 seconds
                    return
            xbmc.sleep(500)
            
            # grab all the info about this item from the stored windows props
            # only ever use the win props here, use the data map in all other places
            runtime = WINDOW.getProperty(currentFile + "runtimeticks")
            refresh_id = WINDOW.getProperty(currentFile + "refresh_id")
            audioindex = WINDOW.getProperty(currentFile + "AudioStreamIndex")
            subtitleindex = WINDOW.getProperty(currentFile + "SubtitleStreamIndex")
            playMethod = WINDOW.getProperty(currentFile + "playmethod")
            itemType = WINDOW.getProperty(currentFile + "type")
            seekTime = WINDOW.getProperty(currentFile + "seektime")
            
            username = WINDOW.getProperty('currUser')
            sessionId = WINDOW.getProperty('sessionId%s' % username)

            if seekTime != "":
                PlaybackUtils().seekToPosition(int(seekTime))
            
            if (not item_id) or (len(item_id) == 0):
                self.logMsg("onPlayBackStarted: No info for current playing file", 0)
                return

            url = "{server}/mediabrowser/Sessions/Playing"
            postdata = {
                'QueueableMediaTypes': "Video",
                'CanSeek': True,
                'ItemId': item_id,
                'MediaSourceId': item_id,
                'PlayMethod': playMethod
            }

            if audioindex:
                postdata['AudioStreamIndex'] = audioindex

            if subtitleindex:
                postdata['SubtitleStreamIndex'] = subtitleindex
            
            self.logMsg("Sending POST play started.", 1)
            #self.logMsg("emby Service -> Sending Post Play Started : " + url, 0)
            self.doUtils.downloadUrl(url, postBody=postdata, type="POST")   
            
            # save data map for updates and position calls
            data = {}
            data["runtime"] = runtime
            data["item_id"] = item_id
            data["refresh_id"] = refresh_id
            data["currentfile"] = currentFile
            data["AudioStreamIndex"] = audioindex
            data["SubtitleStreamIndex"] = subtitleindex
            data["playmethod"] = playMethod
            data["Type"] = itemType
            self.played_information[currentFile] = data
            
            self.logMsg("emby Service -> ADDING_FILE : " + currentFile, 0)
            self.logMsg("emby Service -> ADDING_FILE : " + str(self.played_information), 0)

            # log some playback stats
            if(itemType != None):
                if(self.playStats.get(itemType) != None):
                    count = self.playStats.get(itemType) + 1
                    self.playStats[itemType] = count
                else:
                    self.playStats[itemType] = 1
                    
            if(playMethod != None):
                if(self.playStats.get(playMethod) != None):
                    count = self.playStats.get(playMethod) + 1
                    self.playStats[playMethod] = count
                else:
                    self.playStats[playMethod] = 1
            
            # reset in progress position
            self.reportPlayback()
            
    def GetPlayStats(self):
        return self.playStats
        
    def onPlayBackEnded( self ):
        # Will be called when xbmc stops playing a file
        self.logMsg("onPlayBackEnded", 0)
        
        #workaround when strm files are launched through the addon - mark watched when finished playing
        #TODO --> mark watched when 95% is played of the file
        WINDOW = xbmcgui.Window( 10000 )
        if WINDOW.getProperty("virtualstrm") != "":
            try:
                id = WINDOW.getProperty("virtualstrm")
                type = WINDOW.getProperty("virtualstrmtype")
                watchedurl = "{server}/mediabrowser/Users/{UserId}/PlayedItems/%s" % id
                self.doUtils.downloadUrl(watchedurl, postBody="", type="POST")
                librarySync.updatePlayCount(id)
            except: pass
        WINDOW.clearProperty("virtualstrm")
            
        self.stopAll()

    def onPlayBackStopped( self ):
        # Will be called when user stops xbmc playing a file
        self.logMsg("onPlayBackStopped", 0)
        self.stopAll()
        
    
    def autoPlayPlayback(self):
        currentFile = xbmc.Player().getPlayingFile()
        data = self.played_information.get(currentFile)
        
        # only report playback if emby has initiated the playback (item_id has value)
        if(data != None and data.get("item_id") != None):
            addonSettings = xbmcaddon.Addon(id='plugin.video.emby')
            
            item_id = data.get("item_id")
            type = data.get("Type")
          
            # if its an episode see if autoplay is enabled
            if addonSettings.getSetting("autoPlaySeason")=="true" and type=="Episode":
                    WINDOW = xbmcgui.Window( 10000 )
                    username = WINDOW.getProperty('currUser')
                    userid = WINDOW.getProperty('userId%s' % username)
                    server = WINDOW.getProperty('server%s' % username)
                    # add remaining unplayed episodes if applicable
                    MB3Episode = ReadEmbyDB().getItem(item_id)
                    userData = MB3Episode["UserData"]
                    if userData!=None and userData["Played"]==True:
                        pDialog = xbmcgui.DialogProgress()
                        seasonId = MB3Episode["SeasonId"]
                        url = "{server}/mediabrowser/Users/{UserId}/Items?ParentId=%s&ImageTypeLimit=1&Limit=1&SortBy=SortName&SortOrder=Ascending&Filters=IsUnPlayed&IncludeItemTypes=Episode&IsVirtualUnaired=false&Recursive=true&IsMissing=False&format=json" % seasonId
                        jsonData = self.doUtils.downloadUrl(url)     
                        if(jsonData != ""):
                            seasonData = json.loads(jsonData)
                            if seasonData.get("Items") != None:
                                item = seasonData.get("Items")[0]
                                pDialog.create("Auto Play next episode", str(item.get("ParentIndexNumber")) + "x" + str(item.get("IndexNumber")) + ". " + item["Name"] + " found","Cancel to stop automatic play")
                                count = 0
                                while(pDialog.iscanceled()==False and count < 10):
                                    xbmc.sleep(1000)
                                    count += 1
                                    progress = count * 10
                                    remainingsecs = 10 - count
                                    pDialog.update(progress, str(item.get("ParentIndexNumber")) + "x" + str(item.get("IndexNumber")) + ". " + item["Name"] + " found","Cancel to stop automatic play", str(remainingsecs) + " second(s) until auto dismiss")
                                
                                pDialog.close()
                        
                            if pDialog.iscanceled()==False:
                                playTime = xbmc.Player().getTime()
                                totalTime = xbmc.Player().getTotalTime()
                                while xbmc.Player().isPlaying() and (totalTime-playTime > 2):
                                    xbmc.sleep(500)
                                    playTime = xbmc.Player().getTime()
                                    totalTime = xbmc.Player().getTotalTime()
                                
                                PlaybackUtils().PLAYAllEpisodes(seasonData.get("Items"))  
Example #9
0
                    if(startupComplete == False):
                        self.logMsg("Doing_Db_Sync: syncDatabase (Started)")
                        libSync = librarySync.syncDatabase()
                        self.logMsg("Doing_Db_Sync: syncDatabase (Finished) " + str(libSync))
                        countSync = librarySync.updatePlayCounts()
                        self.logMsg("Doing_Db_Sync: updatePlayCounts (Finished) "  + str(countSync))

                        # Force refresh newly set thumbnails
                        xbmc.executebuiltin("UpdateLibrary(video)")
                        if(libSync and countSync):
                            startupComplete = True
                    else:
                        if self.KodiMonitor.waitForAbort(10):
                            # Abort was requested while waiting. We should exit
                            break    
                        WebSocketThread().processPendingActions()
                    
                else:
                    self.logMsg("Not authenticated yet", 0)
                    
        self.logMsg("stopping Service", 0)

        # If user reset library database.
        WINDOW = xbmcgui.Window(10000)
        if WINDOW.getProperty("SyncInstallRunDone") == "false":
            addon = xbmcaddon.Addon('plugin.video.emby')
            addon.setSetting("SyncInstallRunDone", "false")
        
        if (self.newWebSocketThread != None):
            ws.stopClient()
Example #10
0
 def ServiceEntryPoint(self):
     
     ConnectionManager().checkServer()
     
     lastProgressUpdate = datetime.today()
     
     interval_FullSync = 600
     interval_IncrementalSync = 300
     
     cur_seconds_fullsync = interval_FullSync
     cur_seconds_incrsync = interval_IncrementalSync
     
     user = UserClient()
     player = Player()
     ws = WebSocketThread()
     
     while not self.KodiMonitor.abortRequested():
         
         xbmc.sleep(1000)
         
         if xbmc.Player().isPlaying():
             try:
                 playTime = xbmc.Player().getTime()
                 currentFile = xbmc.Player().getPlayingFile()
                 
                 if(player.played_information.get(currentFile) != None):
                     player.played_information[currentFile]["currentPosition"] = playTime
                 
                 # send update
                 td = datetime.today() - lastProgressUpdate
                 secDiff = td.seconds
                 if(secDiff > 10):
                     try:
                         player.reportPlayback()
                     except Exception, msg:
                         xbmc.log("MB3 Sync Service -> Exception reporting progress : " + msg)
                         pass
                     lastProgressUpdate = datetime.today()
                 
             except Exception, e:
                 xbmc.log("MB3 Sync Service -> Exception in Playback Monitor Service : " + str(e))
                 pass
         else:
             if (self.newUserClient == None):
                     self.newUserClient = "Started"
                     user.start()
             # background worker for database sync
             if (user.currUser != None):
                 
                 # Correctly launch the websocket, if user manually launches the add-on
                 if (self.newWebSocketThread == None):
                     self.newWebSocketThread = "Started"
                     ws.start()
         
                 #full sync
                 if(cur_seconds_fullsync >= interval_FullSync):
                     xbmc.log("Doing_Db_Sync: syncDatabase (Started)")
                     worked = librarySync.syncDatabase()
                     xbmc.log("Doing_Db_Sync: syncDatabase (Finished) " + str(worked))
                     if(worked):
                         cur_seconds_fullsync = 0
                     else:
                         cur_seconds_fullsync = interval_FullSync - 10
                 else:
                     cur_seconds_fullsync += 1
                 
                 #incremental sync
                 if(cur_seconds_incrsync >= interval_IncrementalSync):
                     xbmc.log("Doing_Db_Sync: updatePlayCounts (Started)")
                     worked = librarySync.updatePlayCounts()
                     xbmc.log("Doing_Db_Sync: updatePlayCounts (Finished) "  + str(worked))
                     if(worked):
                         cur_seconds_incrsync = 0
                     else:
                         cur_seconds_incrsync = interval_IncrementalSync - 10
                 else:
                     cur_seconds_incrsync += 1
           
                 
             else:
                 xbmc.log("Not authenticated yet")
Example #11
0
    def ServiceEntryPoint(self):
        
        WINDOW = self.WINDOW
        WINDOW.setProperty("Server_online", "")
        self.WINDOW.setProperty("Server_status", "")
        WINDOW.setProperty("Emby_Service_Timestamp", str(int(time.time())))
        
        ConnectionManager().checkServer()
        lastProgressUpdate = datetime.today()
        startupComplete = False
        
        user = UserClient()
        player = Player()
        ws = WebSocketThread()
        
        lastFile = None
        
        while not self.KodiMonitor.abortRequested():
            #WINDOW.setProperty("Emby_Service_Timestamp", str(int(time.time())))
                     
            if self.KodiMonitor.waitForAbort(1):
                # Abort was requested while waiting. We should exit
                break

            if WINDOW.getProperty('Server_online') == "true":
                # Server is online
                if (user.currUser != None) and (user.HasAccess == True):
                    self.warn_auth = True

                    # Correctly launch the websocket, if user manually launches the add-on
                    if (self.newWebSocketThread == None):
                        self.newWebSocketThread = "Started"
                        ws.start()

                    if xbmc.Player().isPlaying():
                        #WINDOW.setProperty("Emby_Service_Timestamp", str(int(time.time())))
                        try:
                            playTime = xbmc.Player().getTime()
                            totalTime = xbmc.Player().getTotalTime()
                            currentFile = xbmc.Player().getPlayingFile()

                            if(player.played_information.get(currentFile) != None):
                                player.played_information[currentFile]["currentPosition"] = playTime
                            
                            # send update
                            td = datetime.today() - lastProgressUpdate
                            secDiff = td.seconds
                            if(secDiff > 3):
                                try:
                                    player.reportPlayback()
                                except Exception, msg:
                                    self.logMsg("Exception reporting progress: %s" % msg)
                                    pass
                                lastProgressUpdate = datetime.today()
                            elif WINDOW.getProperty('commandUpdate') == "true":
                                try:
                                    WINDOW.clearProperty('commandUpdate')
                                    player.reportPlayback()
                                except: pass
                                lastProgressUpdate = datetime.today()
                            # only try autoplay when there's 20 seconds or less remaining and only once!
                            addonSettings = xbmcaddon.Addon(id='plugin.video.emby')
                          
                            # if its an episode see if autoplay is enabled
                            if addonSettings.getSetting("autoPlaySeason")=="true":
                                notificationtime = addonSettings.getSetting("autoPlaySeasonTime")
                                if (totalTime - playTime <= int(notificationtime) and (lastFile==None or lastFile!=currentFile)):
                                    lastFile = currentFile
                                    player.autoPlayPlayback()
                                    self.logMsg("Netflix style autoplay succeeded.", 2)
                            
                        except Exception, e:
                            self.logMsg("Exception in Playback Monitor Service: %s" % e)
                            pass

                    else:
                        #full sync
                        if (startupComplete == False):
                            self.logMsg("Doing_Db_Sync: syncDatabase (Started)")
                            libSync = librarySync.FullLibrarySync()
                            self.logMsg("Doing_Db_Sync: syncDatabase (Finished) " + str(libSync))
                            #WINDOW.setProperty("Emby_Service_Timestamp", str(int(time.time())))
                            if (libSync):
                                startupComplete = True
                        else:
                            if self.KodiMonitor.waitForAbort(1):
                                # Abort was requested while waiting. We should exit
                                break
Example #12
0
class Monitor():

    logLevel = 0
    settings = None

    def __init__(self, *args):

        self.settings = xbmcaddon.Addon(id='plugin.video.xbmb3c')
        try:
            self.logLevel = int(self.settings.getSetting('logLevel'))
        except:
            pass

        self.printDebug("XBMB3C Service -> starting Monitor")

        pass

    def printDebug(self, msg, level=1):
        if (self.logLevel >= level):
            if (self.logLevel == 2):
                try:
                    xbmc.log("XBMB3C " + str(level) + " -> " +
                             inspect.stack()[1][3] + " : " + str(msg))
                except UnicodeEncodeError:
                    xbmc.log("XBMB3C " + str(level) + " -> " +
                             inspect.stack()[1][3] + " : " +
                             str(msg.encode('utf-8')))
            else:
                try:
                    xbmc.log("XBMB3C " + str(level) + " -> " + str(msg))
                except UnicodeEncodeError:
                    xbmc.log("XBMB3C " + str(level) + " -> " +
                             str(msg.encode('utf-8')))

    def SkinCompatibilityMessage(self):
        return_value = xbmcgui.Dialog().yesno(
            self.settings.getLocalizedString(30229),
            self.settings.getLocalizedString(30230),
            self.settings.getLocalizedString(30231),
            self.settings.getLocalizedString(30232),
            nolabel="Ok",
            yeslabel="Dont Show Again")
        if return_value:
            xbmc.log("ignoring skin compatibility message forever")
            self.settings.setSetting("skinMessageIgnored", "true")

    def ServiceEntryPoint(self):

        xbmcgui.Window(10000).setProperty("XBMB3C_Service_Timestamp",
                                          str(int(time.time())))

        # auth the service
        try:
            downloadUtils = DownloadUtils()
            downloadUtils.authenticate()
        except Exception, e:
            pass

        # start some worker threads
        if self.settings.getSetting('useSkinHelper') == "true":
            skinHelperThread = SkinHelperThread()
            skinHelperThread.start()
        else:
            self.printDebug("XBMB3C Service SkinHelperThread Disabled")
            skinHelperThread = None

        if self.settings.getSetting('useInProgressUpdater') == "true":
            newInProgressThread = InProgressUpdaterThread()
            newInProgressThread.start()
        else:
            self.printDebug("XBMB3C Service InProgressUpdater Disabled")
            newInProgressThread = None

        if self.settings.getSetting('useRecentInfoUpdater') == "true":
            newRecentInfoThread = RecentInfoUpdaterThread()
            newRecentInfoThread.start()
        else:
            self.printDebug("XBMB3C Service RecentInfoUpdater Disabled")
            newRecentInfoThread = None

        if self.settings.getSetting('useRandomInfo') == "true":
            newRandomInfoThread = RandomInfoUpdaterThread()
            newRandomInfoThread.start()
        else:
            self.printDebug("XBMB3C Service RandomInfo Disabled")
            newRandomInfoThread = None

        if self.settings.getSetting('useNextUp') == "true":
            newNextUpThread = NextUpUpdaterThread()
            newNextUpThread.start()
        else:
            self.printDebug("XBMB3C Service NextUp Disabled")
            newNextUpThread = None

        if self.settings.getSetting('useSuggested') == "true":
            newSuggestedThread = SuggestedUpdaterThread()
            newSuggestedThread.start()
        else:
            self.printDebug("XBMB3C Service Suggested Disabled")
            newSuggestedThread = None

        if self.settings.getSetting('useWebSocketRemote') == "true":
            newWebSocketThread = WebSocketThread()
            newWebSocketThread.start()
        else:
            self.printDebug("XBMB3C Service WebSocketRemote Disabled")
            newWebSocketThread = None

        if self.settings.getSetting('useMenuLoader') == "true":
            newMenuThread = LoadMenuOptionsThread()
            newMenuThread.start()
        else:
            self.printDebug("XBMB3C Service MenuLoader Disabled")
            newMenuThread = None

        if self.settings.getSetting('useBackgroundLoader') == "true":
            artworkRotationThread = ArtworkRotationThread()
            artworkRotationThread.start()
        else:
            self.printDebug("XBMB3C Service BackgroundLoader Disabled")
            artworkRotationThread = None

        if self.settings.getSetting(
                'useThemeMovies') == "true" or self.settings.getSetting(
                    'useThemeMusic') == "true":
            newThemeMediaThread = ThemeMediaThread()
            newThemeMediaThread.start()
        else:
            self.printDebug("XBMB3C Service ThemeMedia Disabled")
            newThemeMediaThread = None

        if self.settings.getSetting('useInfoLoader') == "true":
            newInfoThread = InfoUpdaterThread()
            newInfoThread.start()
        else:
            self.printDebug("XBMB3C Service InfoLoader Disabled")
            newInfoThread = None

        if self.settings.getSetting('usePlaylistsUpdater') == "true":
            newPlaylistsThread = PlaylistItemUpdaterThread()
            newPlaylistsThread.start()
        else:
            self.printDebug("XBMB3C Service PlaylistsUpdater Disabled")
            newPlaylistsThread = None

        if self.settings.getSetting('useBackgroundData') == "true":
            newBackgroundDataThread = BackgroundDataUpdaterThread()
            newBackgroundDataThread.start()
        else:
            self.printDebug("XBMB3C BackgroundDataUpdater Disabled")
            newBackgroundDataThread = None

        # start the service
        service = Service()
        lastProgressUpdate = datetime.today()

        addonSettings = xbmcaddon.Addon(id='plugin.video.xbmb3c')
        if socket.gethostname() != None and socket.gethostname(
        ) != '' and addonSettings.getSetting("deviceName") == 'XBMB3C':
            addonSettings.setSetting("deviceName", socket.gethostname())

        xbmc.log("XBMB3C Service -> Starting Service")

        whenStarted = datetime.today()
        skinMessageShown = False

        while not xbmc.abortRequested:
            if xbmc.Player().isPlaying():
                try:
                    playTime = xbmc.Player().getTime()
                    currentFile = xbmc.Player().getPlayingFile()

                    if (service.played_information.get(currentFile) != None):
                        service.played_information[currentFile][
                            "currentPossition"] = playTime

                    # send update
                    td = datetime.today() - lastProgressUpdate
                    secDiff = td.seconds
                    if (secDiff > 10):
                        try:
                            service.reportPlayback(currentFile)
                            #if(service.played_information.get(currentFile) != None and service.played_information.get(currentFile).get("item_id") != None):
                            #item_id =  service.played_information.get(currentFile).get("item_id")
                            #if(newWebSocketThread != None):
                            #newWebSocketThread.sendProgressUpdate(item_id, str(int(playTime * 10000000)))
                        except Exception, msg:
                            try:
                                xbmc.log(
                                    "XBMB3C Service -> Exception reporting progress : "
                                    + str(msg))
                            except:
                                pass
                            pass
                        lastProgressUpdate = datetime.today()

                except Exception, e:
                    xbmc.log(
                        "XBMB3C Service -> Exception in Playback Monitor Service : "
                        + str(e))
                    pass
            else:
                if (skinMessageShown == False):
                    timeSinceStart = (datetime.today() - whenStarted).seconds
                    if (timeSinceStart > 10):
                        skinMessageShown = True
                        skinIsCompatible = xbmcgui.Window(10000).getProperty(
                            "SkinIsCompatible")
                        skinMessageIgnored = self.settings.getSetting(
                            "skinMessageIgnored")
                        if (skinIsCompatible != "true"
                                and skinMessageIgnored != "true"):
                            self.SkinCompatibilityMessage()

            xbmc.sleep(1000)
            xbmcgui.Window(10000).setProperty("XBMB3C_Service_Timestamp",
                                              str(int(time.time())))