def getAuthHeader(self, authenticate=True):
        clientInfo = ClientInformation()
        txt_mac = clientInfo.getMachineId()
        version = clientInfo.getVersion()

        deviceName = self.addonSettings.getSetting('deviceName')
        deviceName = deviceName.replace("\"", "_")

        if (authenticate == False):
            authString = "MediaBrowser Client=\"Kodi\",Device=\"" + deviceName + "\",DeviceId=\"" + txt_mac + "\",Version=\"" + version + "\""
            headers = {
                "Accept-encoding": "gzip",
                "Accept-Charset": "UTF-8,*",
                "Authorization": authString
            }
            return headers
        else:
            userid = self.getUserId()
            authString = "MediaBrowser UserId=\"" + userid + "\",Client=\"Kodi\",Device=\"" + deviceName + "\",DeviceId=\"" + txt_mac + "\",Version=\"" + version + "\""
            headers = {
                "Accept-encoding": "gzip",
                "Accept-Charset": "UTF-8,*",
                "Authorization": authString
            }

            authToken = self.authenticate()
            if (authToken != ""):
                headers["X-MediaBrowser-Token"] = authToken

            self.logMsg("Authentication Header : " + str(headers))
            return headers
 def postcapabilities(self):
     self.logMsg("postcapabilities called")
     
     # Set Capabilities
     mb3Port = self.addonSettings.getSetting('port')
     mb3Host = self.addonSettings.getSetting('ipaddress')
     clientInfo = ClientInformation()
     machineId = clientInfo.getMachineId()
     
     # get session id
     url = "http://" + mb3Host + ":" + mb3Port + "/mediabrowser/Sessions?DeviceId=" + machineId + "&format=json"
     self.logMsg("Session URL : " + url);
     jsonData = self.downloadUrl(url)
     self.logMsg("Session JsonData : " + jsonData)
     result = json.loads(jsonData)
     self.logMsg("Session JsonData : " + str(result))
     sessionId = result[0].get("Id")
     self.logMsg("Session Id : " + str(sessionId))
     
     # post capability data
     playableMediaTypes = "Audio,Video,Photo"
     supportedCommands = "Play,Playstate,DisplayContent,GoHome,SendString,GoToSettings,DisplayMessage,PlayNext"
     
     url = "http://" + mb3Host + ":" + mb3Port + "/mediabrowser/Sessions/Capabilities?Id=" + sessionId + "&PlayableMediaTypes=" + playableMediaTypes + "&SupportedCommands=" + supportedCommands + "&SupportsMediaControl=True"
     postData = {}
     #postData["Id"] = sessionId;
     #postData["PlayableMediaTypes"] = "Video";
     #postData["SupportedCommands"] = "MoveUp";
     stringdata = json.dumps(postData)
     self.logMsg("Capabilities URL : " + url);
     self.logMsg("Capabilities Data : " + stringdata)
     
     self.downloadUrl(url, postBody=stringdata, type="POST")
示例#3
0
def stopAll(played_information):

    if(len(played_information) == 0):
        return 
        
    addonSettings = xbmcaddon.Addon(id='plugin.video.xbmb3c')
    xbmc.log ("XBMB3C Service -> played_information : " + str(played_information))
    
    for item_url in played_information:
        data = played_information.get(item_url)
        if(data != None):
            xbmc.log ("XBMB3C Service -> item_url  : " + item_url)
            xbmc.log ("XBMB3C Service -> item_data : " + str(data))
            
            watchedurl = data.get("watchedurl")
            positionurl = data.get("positionurl")
            deleteurl = data.get("deleteurl")
            runtime = data.get("runtime")
            currentPossition = data.get("currentPossition")
            item_id = data.get("item_id")
            
            if(currentPossition != None and hasData(runtime) and hasData(positionurl) and hasData(watchedurl)):
                runtimeTicks = int(runtime)
                xbmc.log ("XBMB3C Service -> runtimeticks:" + str(runtimeTicks))
                percentComplete = (currentPossition * 10000000) / runtimeTicks
                markPlayedAt = float(addonSettings.getSetting("markPlayedAt")) / 100    

                xbmc.log ("XBMB3C Service -> Percent Complete:" + str(percentComplete) + " Mark Played At:" + str(markPlayedAt))
                if (percentComplete > markPlayedAt):
                
                    gotDeleted = 0
                    if(deleteurl != None and deleteurl != ""):
                        xbmc.log ("XBMB3C Service -> Offering Delete:" + str(deleteurl))
                        gotDeleted = deleteItem(deleteurl)
                        
                    if(gotDeleted == 0):
                        setPosition(positionurl + '/Progress?PositionTicks=0', 'POST')
                        if(newWebSocketThread != None):
                            newWebSocketThread.playbackStopped(item_id, str(0))
                        markWatched(watchedurl)
                else:
                    #markUnWatched(watchedurl) # this resets the LastPlayedDate and that causes issues with sortby PlayedDate so I removed it for now
                    if(newWebSocketThread != None):
                        newWebSocketThread.playbackStopped(item_id, str(int(currentPossition * 10000000)))
                    setPosition(positionurl + '?PositionTicks=' + str(int(currentPossition * 10000000)), 'DELETE')
                    
    if(newNextUpThread != None):
        newNextUpThread.updateNextUp()
        
    if(artworkRotationThread != None):
        artworkRotationThread.updateActionUrls()
        
    played_information.clear()

    # stop transcoding - todo check we are actually transcoding?
    clientInfo = ClientInformation()
    txt_mac = clientInfo.getMachineId()
    url = ("http://%s:%s/mediabrowser/Videos/ActiveEncodings" % (addonSettings.getSetting('ipaddress'), addonSettings.getSetting('port')))  
    url = url + '?DeviceId=' + txt_mac
    stopTranscoding(url)
示例#4
0
    def postcapabilities(self):
        self.logMsg("postcapabilities called")

        # Set Capabilities
        mb3Port = self.addonSettings.getSetting('port')
        mb3Host = self.addonSettings.getSetting('ipaddress')
        clientInfo = ClientInformation()
        machineId = clientInfo.getMachineId()

        # get session id
        url = "http://" + mb3Host + ":" + mb3Port + "/mediabrowser/Sessions?DeviceId=" + machineId + "&format=json"
        self.logMsg("Session URL : " + url)
        jsonData = self.downloadUrl(url)
        self.logMsg("Session JsonData : " + jsonData)
        result = json.loads(jsonData)
        self.logMsg("Session JsonData : " + str(result))
        sessionId = result[0].get("Id")
        self.logMsg("Session Id : " + str(sessionId))

        # post capability data
        playableMediaTypes = "Audio,Video,Photo"
        supportedCommands = "Play,Playstate,DisplayContent,GoHome,SendString,GoToSettings,DisplayMessage,PlayNext"

        url = "http://" + mb3Host + ":" + mb3Port + "/mediabrowser/Sessions/Capabilities?Id=" + sessionId + "&PlayableMediaTypes=" + playableMediaTypes + "&SupportedCommands=" + supportedCommands + "&SupportsMediaControl=True"
        postData = {}
        #postData["Id"] = sessionId;
        #postData["PlayableMediaTypes"] = "Video";
        #postData["SupportedCommands"] = "MoveUp";
        stringdata = json.dumps(postData)
        self.logMsg("Capabilities URL : " + url)
        self.logMsg("Capabilities Data : " + stringdata)

        self.downloadUrl(url, postBody=stringdata, type="POST")
    def stopAll(self):

        if(len(self.played_information) == 0):
            return 
            
        addonSettings = xbmcaddon.Addon(id='plugin.video.xbmb3c')
        self.printDebug("XBMB3C Service -> played_information : " + str(self.played_information))
        
        for item_url in self.played_information:
            data = self.played_information.get(item_url)
            
            if(data != None):
                self.printDebug("XBMB3C Service -> item_url  : " + item_url)
                self.printDebug("XBMB3C Service -> item_data : " + str(data))
                
                deleteurl = data.get("deleteurl")
                runtime = data.get("runtime")
                currentPossition = data.get("currentPossition")
                item_id = data.get("item_id")
                refresh_id = data.get("refresh_id")
                currentFile = data.get("currentfile")
                
                if(refresh_id != None):
                    BackgroundDataUpdaterThread().updateItem(refresh_id)
                
                if(currentPossition != None and self.hasData(runtime)):
                    runtimeTicks = int(runtime)
                    self.printDebug("XBMB3C Service -> runtimeticks:" + str(runtimeTicks))
                    percentComplete = (currentPossition * 10000000) / runtimeTicks
                    offerDeleteAt = float(addonSettings.getSetting("offerDeleteAt")) / 100    

                    self.printDebug("XBMB3C Service -> Percent Complete:" + str(percentComplete) + " Mark Played At:" + str(offerDeleteAt))
                    self.stopPlayback(data)
                    
                    if (percentComplete > offerDeleteAt):
                        gotDeleted = 0
                        if(deleteurl != None and deleteurl != ""):
                            self.printDebug("XBMB3C Service -> Offering Delete:" + str(deleteurl))
                            gotDeleted = self.deleteItem(deleteurl)

        # update some of the display info
        if self.settings.getSetting('useNextUp') == "true":
            NextUpUpdaterThread().updateNextUp()
            
        if self.settings.getSetting('useBackgroundLoader') == "true":
            ArtworkRotationThread().updateActionUrls()
            
        self.played_information.clear()

        # stop transcoding - todo check we are actually transcoding?
        clientInfo = ClientInformation()
        txt_mac = clientInfo.getMachineId()
        url = ("http://%s:%s/mediabrowser/Videos/ActiveEncodings" % (addonSettings.getSetting('ipaddress'), addonSettings.getSetting('port')))  
        url = url + '?DeviceId=' + txt_mac
        self.downloadUtils.downloadUrl(url, type="DELETE")
示例#6
0
   def getPlayUrl(self, server, id, result):
   
     addonSettings = xbmcaddon.Addon(id='plugin.video.xbmb3c')
     # if the path is local and depending on the video quality play we can direct play it do so-
     xbmc.log("XBMB3C getPlayUrl")
     if self.isDirectPlay(result) == True:
         xbmc.log("XBMB3C getPlayUrl -> Direct Play")
         playurl = result.get("Path")
         if playurl != None:
           #We have a path to play so play it
           USER_AGENT = 'QuickTime/7.7.4'
       
           # If the file it is not a media stub
           if (result.get("IsPlaceHolder") != True):
             if (result.get("VideoType") == "Dvd"):
               playurl = playurl + "/VIDEO_TS/VIDEO_TS.IFO"
             elif (result.get("VideoType") == "BluRay"):
               playurl = playurl + "/BDMV/index.bdmv"
           if addonSettings.getSetting('smbusername') == '':
             playurl = playurl.replace("\\\\", "smb://")
           else:
             playurl = playurl.replace("\\\\", "smb://" + addonSettings.getSetting('smbusername') + ':' + addonSettings.getSetting('smbpassword') + '@')
           playurl = playurl.replace("\\", "/")
       
           if ("apple.com" in playurl):
             playurl += '?|User-Agent=%s' % USER_AGENT
           if addonSettings.getSetting('playFromStream') == "true":
             playurl = 'http://' + server + '/mediabrowser/Videos/' + id + '/stream?static=true'
             mediaSources = result.get("MediaSources")
             if(mediaSources != None):
               if mediaSources[0].get('DefaultAudioStreamIndex') != None:
                 playurl = playurl + "&AudioStreamIndex=" +str(mediaSources[0].get('DefaultAudioStreamIndex'))
               if mediaSources[0].get('DefaultSubtitleStreamIndex') != None:
                 playurl = playurl + "&SubtitleStreamIndex=" + str(mediaSources[0].get('DefaultAudioStreamIndex')) 
 
     else:
         #No path or has a path but not sufficient network so transcode
         xbmc.log("XBMB3C getPlayUrl -> Transcode")
         if result.get("Type") == "Audio":
           playurl = 'http://' + server + '/mediabrowser/Audio/' + id + '/stream.mp3'
         else:
           clientInfo = ClientInformation()
           txt_mac = clientInfo.getMachineId()
           playurl = 'http://' + server + '/mediabrowser/Videos/' + id + '/master.m3u8?mediaSourceId=' + id
           playurl = playurl + '&videoCodec=h264'
           playurl = playurl + '&AudioCodec=aac,ac3'
           playurl = playurl + '&deviceId=' + txt_mac
           playurl = playurl + '&VideoBitrate=' + str(int(self.getVideoBitRate()) * 1000)
           mediaSources = result.get("MediaSources")
           if(mediaSources != None):
             if mediaSources[0].get('DefaultAudioStreamIndex') != None:
                playurl = playurl + "&AudioStreamIndex=" +str(mediaSources[0].get('DefaultAudioStreamIndex'))
             if mediaSources[0].get('DefaultSubtitleStreamIndex') != None:
                playurl = playurl + "&SubtitleStreamIndex=" + str(mediaSources[0].get('DefaultSubtitleStreamIndex'))
     return playurl.encode('utf-8')
示例#7
0
def getAuthHeader():
    addonSettings = xbmcaddon.Addon(id='plugin.video.xbmb3c')
    deviceName = addonSettings.getSetting('deviceName')
    deviceName = deviceName.replace("\"", "_") # might need to url encode this as it is getting added to the header and is user entered data
    clientInfo = ClientInformation()
    txt_mac = clientInfo.getMachineId()
    version = clientInfo.getVersion()  
    userid = xbmcgui.Window( 10000 ).getProperty("userid")
    authString = "MediaBrowser UserId=\"" + userid + "\",Client=\"XBMC\",Device=\"" + deviceName + "\",DeviceId=\"" + txt_mac + "\",Version=\"" + version + "\""
    headers = {'Accept-encoding': 'gzip', 'Authorization' : authString}
    xbmc.log("XBMB3C Authentication Header : " + str(headers))
    return headers 
    def authenticate(self):    
        WINDOW = xbmcgui.Window( 10000 )

        token = WINDOW.getProperty("AccessToken"+self.addonSettings.getSetting('username'))
        if(token != None and token != ""):
            self.logMsg("DownloadUtils -> Returning saved AccessToken for user : "******" token: "+ token)
            return token
        
        port = self.addonSettings.getSetting("port")
        host = self.addonSettings.getSetting("ipaddress")
        if(host == None or host == "" or port == None or port == ""):
            return ""
            
        url = "http://" + self.addonSettings.getSetting("ipaddress") + ":" + self.addonSettings.getSetting("port") + "/mediabrowser/Users/AuthenticateByName?format=json"
    
        clientInfo = ClientInformation()
        txt_mac = clientInfo.getMachineId()
        version = clientInfo.getVersion()

        deviceName = self.addonSettings.getSetting('deviceName')
        deviceName = deviceName.replace("\"", "_")

        authString = "Mediabrowser Client=\"XBMC\",Device=\"" + deviceName + "\",DeviceId=\"" + txt_mac + "\",Version=\"" + version + "\""
        headers = {'Accept-encoding': 'gzip', 'Authorization' : authString}
        
        if self.addonSettings.getSetting('password') !=None and  self.addonSettings.getSetting('password') !='':   
            sha1 = hashlib.sha1(self.addonSettings.getSetting('password'))
            sha1 = sha1.hexdigest()
        else:
            sha1 = 'da39a3ee5e6b4b0d3255bfef95601890afd80709'
        
        messageData = "username="******"&password="******"POST", authenticate=False)

        accessToken = None
        try:
            result = json.loads(resp)
            accessToken = result.get("AccessToken")
        except:
            pass

        if(accessToken != None):
            self.logMsg("User Authenticated : " + accessToken)
            WINDOW.setProperty("AccessToken"+self.addonSettings.getSetting('username'), accessToken)
            WINDOW.setProperty("userid", result.get("User").get("Id"))
            return accessToken
        else:
            self.logMsg("User NOT Authenticated")
            WINDOW.setProperty("AccessToken"+self.addonSettings.getSetting('username'), "")
            return ""            
示例#9
0
class WebSocketThread(threading.Thread):

    _shared_state = {}

    clientInfo = ClientInformation()
    KodiMonitor = KodiMonitor.Kodi_Monitor()
    addonName = clientInfo.getAddonName()

    client = None
    keepRunning = True

    def __init__(self, *args):

        self.__dict__ = self._shared_state
        threading.Thread.__init__(self, *args)

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

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

    def sendProgressUpdate(self, data):
        self.logMsg("sendProgressUpdate", 1)
        if self.client:
            try:
                # Send progress update
                messageData = {
                    'MessageType': "ReportPlaybackProgress",
                    'Data': data
                }
                messageString = json.dumps(messageData)
                self.client.send(messageString)
                self.logMsg("Message data: %s" % messageString, 2)
            except Exception, e:
                self.logMsg("Exception: %s" % e, 1)
示例#10
0
    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 on_open(self, ws):
     try:
         clientInfo = ClientInformation()
         machineId = clientInfo.getMachineId()
         version = clientInfo.getVersion()
         messageData = {}
         messageData["MessageType"] = "Identity"
         
         addonSettings = xbmcaddon.Addon(id='plugin.video.xbmb3c')
         deviceName = addonSettings.getSetting('deviceName')
         deviceName = deviceName.replace("\"", "_")
     
         messageData["Data"] = "XBMC|" + machineId + "|" + version + "|" + deviceName
         messageString = json.dumps(messageData)
         self.logMsg("Opened : " + str(messageString))
         ws.send(messageString)
     except Exception, e:
         self.logMsg("Exception : " + str(e), level=0)                
 def on_open(self, ws):
     try:
         clientInfo = ClientInformation()
         machineId = clientInfo.getMachineId()
         version = clientInfo.getVersion()
         messageData = {}
         messageData["MessageType"] = "Identity"
         
         addonSettings = xbmcaddon.Addon(id='plugin.video.xbmb3c')
         deviceName = addonSettings.getSetting('deviceName')
         deviceName = deviceName.replace("\"", "_")
     
         messageData["Data"] = "Kodi|" + machineId + "|" + version + "|" + deviceName
         messageString = json.dumps(messageData)
         self.logMsg("Opened : " + str(messageString))
         ws.send(messageString)
     except Exception, e:
         self.logMsg("Exception : " + str(e), level=0)                
    def on_open(self, ws):

        clientInfo = ClientInformation()
        machineId = clientInfo.getMachineId()
        version = clientInfo.getVersion()
        messageData = {}
        messageData["MessageType"] = "Identity"
        
        addonSettings = xbmcaddon.Addon(id='plugin.video.xbmb3c')
        deviceName = addonSettings.getSetting('deviceName')
        deviceName = deviceName.replace("\"", "_")
    
        messageData["Data"] = "Kodi|" + machineId + "|" + version + "|" + deviceName
        messageString = json.dumps(messageData)
        self.logMsg("Opened : " + str(messageString))
        ws.send(messageString)
        
        # Set Capabilities
        xbmc.log("postcapabilities_called")
        downloadUtils = DownloadUtils()
        downloadUtils.postcapabilities()
示例#14
0
    def on_open(self, ws):

        clientInfo = ClientInformation()
        machineId = clientInfo.getMachineId()
        version = clientInfo.getVersion()
        messageData = {}
        messageData["MessageType"] = "Identity"

        addonSettings = xbmcaddon.Addon(id='plugin.video.xbmb3c')
        deviceName = addonSettings.getSetting('deviceName')
        deviceName = deviceName.replace("\"", "_")

        messageData[
            "Data"] = "Kodi|" + machineId + "|" + version + "|" + deviceName
        messageString = json.dumps(messageData)
        self.logMsg("Opened : " + str(messageString))
        ws.send(messageString)

        # Set Capabilities
        xbmc.log("postcapabilities_called")
        downloadUtils = DownloadUtils()
        downloadUtils.postcapabilities()
    def getAuthHeader(self, authenticate=True):
        clientInfo = ClientInformation()
        txt_mac = clientInfo.getMachineId()
        version = clientInfo.getVersion()
        
        deviceName = self.addonSettings.getSetting('deviceName')
        deviceName = deviceName.replace("\"", "_")

        if(authenticate == False):
            authString = "MediaBrowser Client=\"Kodi\",Device=\"" + deviceName + "\",DeviceId=\"" + txt_mac + "\",Version=\"" + version + "\""
            headers = {"Accept-encoding": "gzip", "Accept-Charset" : "UTF-8,*", "Authorization" : authString}        
            return headers
        else:
            userid = self.getUserId()
            authString = "MediaBrowser UserId=\"" + userid + "\",Client=\"Kodi\",Device=\"" + deviceName + "\",DeviceId=\"" + txt_mac + "\",Version=\"" + version + "\""
            headers = {"Accept-encoding": "gzip", "Accept-Charset" : "UTF-8,*", "Authorization" : authString}        
                
            authToken = self.authenticate()
            if(authToken != ""):
                headers["X-MediaBrowser-Token"] = authToken
                    
            self.logMsg("Authentication Header : " + str(headers))
            return headers
示例#16
0
    def run(self):

        WINDOW = xbmcgui.Window(10000)
        logLevel = int(WINDOW.getProperty('getLogLevel'))
        username = WINDOW.getProperty('currUser')
        server = WINDOW.getProperty('server%s' % username)
        token = WINDOW.getProperty('accessToken%s' % username)
        deviceId = ClientInformation().getMachineId()
        '''if (logLevel == 2):
            websocket.enableTrace(True)'''

        # Get the appropriate prefix for websocket
        if "https" in server:
            server = server.replace('https', 'wss')
        else:
            server = server.replace('http', 'ws')

        websocketUrl = "%s?api_key=%s&deviceId=%s" % (server, token, deviceId)
        self.logMsg("websocket URL: %s" % websocketUrl)

        self.client = websocket.WebSocketApp(websocketUrl,
                                             on_message=self.on_message,
                                             on_error=self.on_error,
                                             on_close=self.on_close)

        self.client.on_open = self.on_open

        while self.keepRunning:

            self.client.run_forever()

            if self.keepRunning:
                self.logMsg("Client Needs To Restart", 2)
                if self.KodiMonitor.waitForAbort(5):
                    break

        self.logMsg("Thread Exited", 1)
    def authenticate(self, retreive=True):
    
        WINDOW = xbmcgui.Window(10000)
        self.addonSettings = xbmcaddon.Addon(id='plugin.video.xbmb3c')
        username = self.addonSettings.getSetting('username')
        
        token = WINDOW.getProperty("AccessToken" + username)
        if(token != None and token != ""):
            self.logMsg("DownloadUtils -> Returning saved (WINDOW) AccessToken for user:"******" token:" + token)
            return token
        
        token = self.addonSettings.getSetting("AccessToken" + username)
        if(token != None and token != ""):
            WINDOW.setProperty("AccessToken" + username, token)
            self.logMsg("DownloadUtils -> Returning saved (SETTINGS) AccessToken for user:"******" token:" + token)
            return token        
        
        port = self.addonSettings.getSetting("port")
        host = self.addonSettings.getSetting("ipaddress")
        if(host == None or host == "" or host == "<none>" or port == None or port == ""):
            return ""
        
        if(retreive == False):
            return ""
        
        url = "http://" + host + ":" + port + "/mediabrowser/Users/AuthenticateByName?format=json"
    
        clientInfo = ClientInformation()
        txt_mac = clientInfo.getMachineId()
        version = clientInfo.getVersion()
        
        # get user info
        jsonData = self.downloadUrl("http://" + host + ":" + port + "/mediabrowser/Users/Public?format=json", authenticate=False)
        users = []
        if(jsonData != ""):
            users = json.loads(jsonData)
        userHasPassword = False
        for user in users:
            name = user.get("Name")
            if(username == name):
                if(user.get("HasPassword") == True):
                    userHasPassword = True
                break
        
        password = ""
        if(userHasPassword):
            password = xbmcgui.Dialog().input("Enter Password for user : "******""):   
            sha1 = hashlib.sha1(password)
            sha1 = sha1.hexdigest()
        else:
            sha1 = 'da39a3ee5e6b4b0d3255bfef95601890afd80709'
        
        messageData = "username="******"&password="******"POST", authenticate=False)

        result = None
        accessToken = None
        try:
            xbmc.log("Auth_Reponce: " + str(resp))
            result = json.loads(resp)
            accessToken = result.get("AccessToken")
        except:
            pass

        if(result != None and accessToken != None):
            userID = result.get("User").get("Id")
            self.logMsg("User Authenticated : " + accessToken)
            WINDOW.setProperty("AccessToken" + username, accessToken)
            WINDOW.setProperty("userid" + username, userID)
            self.addonSettings.setSetting("AccessToken" + username, accessToken)
            self.addonSettings.setSetting("userid" + username, userID)
            return accessToken
        else:
            self.logMsg("User NOT Authenticated")
            WINDOW.setProperty("AccessToken" + username, "")
            WINDOW.setProperty("userid" + username, "")
            self.addonSettings.setSetting("AccessToken" + username, "")
            self.addonSettings.setSetting("userid" + username, "")
            return ""            
示例#18
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"))  
class Player(xbmc.Player):
    # Borg - multiple instances, shared state
    _shared_state = {}

    xbmcplayer = xbmc.Player()
    clientInfo = ClientInformation()

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

    episode = None
    nextUpPage = None
    stillWatchingPage = None
    logLevel = 0
    totalTime = 0
    currenttvshowid = None
    currentepisodeid = None
    playedinarow = 1
    playbackonended = False
    fields_base = '"dateadded", "file", "lastplayed","plot", "title", "art", "playcount",'
    fields_file = fields_base + '"streamdetails", "director", "resume", "runtime",'
    fields_tvshows = fields_base + '"sorttitle", "mpaa", "premiered", "year", "episode", "watchedepisodes", "votes", "rating", "studio", "season", "genre", "episodeguide", "tag", "originaltitle", "imdbnumber"'
    fields_episodes = fields_file + '"cast", "productioncode", "rating", "votes", "episode", "showtitle", "tvshowid", "season", "firstaired", "writer", "originaltitle"'

    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 json_query(self, query, ret):
        try:
            xbmc_request = json.dumps(query)
            result = xbmc.executeJSONRPC(xbmc_request)
            result = unicode(result, 'utf-8', errors='ignore')
            if ret:
                return json.loads(result)['result']

            else:
                return json.loads(result)
        except:
            xbmc_request = json.dumps(query)
            result = xbmc.executeJSONRPC(xbmc_request)
            result = unicode(result, 'utf-8', errors='ignore')
            self.logMsg(json.loads(result), 1)
            return json.loads(result)

    def onPlayBackStarted(self):
        # Will be called when kodi starts playing a file
        self.playbackonended = False
        self.episode = None
        WINDOW = xbmcgui.Window(10000)
        WINDOW.clearProperty("NextUpNotification.NowPlaying.DBID")
        WINDOW.clearProperty("NextUpNotification.NowPlaying.Type")
        # Get the active player
        result = xbmc.executeJSONRPC(
            '{"jsonrpc": "2.0", "id": 1, "method": "Player.GetActivePlayers"}')
        result = unicode(result, 'utf-8', errors='ignore')
        self.logMsg("Got active player " + result, 2)
        result = json.loads(result)

        # Seems to work too fast loop whilst waiting for it to become active
        while not result["result"]:
            result = xbmc.executeJSONRPC(
                '{"jsonrpc": "2.0", "id": 1, "method": "Player.GetActivePlayers"}'
            )
            result = unicode(result, 'utf-8', errors='ignore')
            self.logMsg("Got active player " + result, 2)
            result = json.loads(result)

        if 'result' in result and result["result"][0] is not None:
            playerid = result["result"][0]["playerid"]

            # Get details of the playing media
            self.logMsg("Getting details of now  playing media", 1)
            result = xbmc.executeJSONRPC(
                '{"jsonrpc": "2.0", "id": 1, "method": "Player.GetItem", "params": {"playerid": '
                + str(playerid) +
                ', "properties": ["showtitle", "tvshowid", "episode", "season", "playcount","genre"] } }'
            )
            result = unicode(result, 'utf-8', errors='ignore')
            self.logMsg("Got details of now playing media" + result, 2)

            result = json.loads(result)
            if 'result' in result:
                itemtype = result["result"]["item"]["type"]
                if itemtype == "episode":
                    WINDOW.setProperty("NextUpNotification.NowPlaying.Type",
                                       itemtype)
                    tvshowid = result["result"]["item"]["tvshowid"]
                    WINDOW.setProperty("NextUpNotification.NowPlaying.DBID",
                                       str(tvshowid))
                elif itemtype == "movie":
                    WINDOW.setProperty("NextUpNotification.NowPlaying.Type",
                                       itemtype)
                    id = result["result"]["item"]["id"]
                    WINDOW.setProperty("NextUpNotification.NowPlaying.DBID",
                                       str(id))

    def iStream_fix(self, show_npid, showtitle, episode_np, season_np):

        # streams from iStream dont provide the showid and epid for above
        # they come through as tvshowid = -1, but it has episode no and season no and show name
        # need to insert work around here to get showid from showname, and get epid from season and episode no's
        # then need to ignore prevcheck
        self.logMsg('fixing strm, data follows...')
        self.logMsg('show_npid = ' + str(show_npid))
        self.logMsg('showtitle = ' + str(showtitle))
        self.logMsg('episode_np = ' + str(episode_np))
        self.logMsg('season_np = ' + str(season_np))

        show_request_all = {
            "jsonrpc": "2.0",
            "method": "VideoLibrary.GetTVShows",
            "params": {
                "properties": ["title"]
            },
            "id": "1"
        }
        eps_query = {
            "jsonrpc": "2.0",
            "method": "VideoLibrary.GetEpisodes",
            "params": {
                "properties": [
                    "season", "episode", "runtime", "resume", "playcount",
                    "tvshowid", "lastplayed", "file"
                ],
                "tvshowid":
                "1"
            },
            "id": "1"
        }

        ep_npid = " "

        redo = True
        count = 0
        while redo and count < 2:  # this ensures the section of code only runs twice at most [ only runs once fine ?
            redo = False
            count += 1
            if show_npid == -1 and showtitle and episode_np and season_np:
                tmp_shows = self.json_query(show_request_all, True)
                self.logMsg('tmp_shows = ' + str(tmp_shows))
                if 'tvshows' in tmp_shows:
                    for x in tmp_shows['tvshows']:
                        if x['label'] == showtitle:
                            show_npid = x['tvshowid']
                            eps_query['params']['tvshowid'] = show_npid
                            tmp_eps = self.json_query(eps_query, True)
                            self.logMsg('tmp eps = ' + str(tmp_eps))
                            if 'episodes' in tmp_eps:
                                for y in tmp_eps['episodes']:
                                    if (y['season']) == season_np and (
                                            y['episode']) == episode_np:
                                        ep_npid = y['episodeid']
                                        self.logMsg('playing epid stream = ' +
                                                    str(ep_npid))

        return show_npid, ep_npid

    def findNextEpisode(self, result, currentFile, includeWatched):
        self.logMsg("Find next episode called", 1)
        position = 0
        for episode in result["result"]["episodes"]:
            # find position of current episode
            if self.currentepisodeid == episode["episodeid"]:
                # found a match so add 1 for the next and get out of here
                position += 1
                break
            position += 1
        # check if it may be a multi-part episode
        while result["result"]["episodes"][position]["file"] == currentFile:
            position += 1
        # skip already watched episodes?
        while not includeWatched and result["result"]["episodes"][position][
                "playcount"] > 1:
            position += 1

        # now return the episode
        self.logMsg(
            "Find next episode found next episode in position: " +
            str(position), 1)
        try:
            episode = result["result"]["episodes"][position]
        except:
            # no next episode found
            episode = None

        return episode

    def displayRandomUnwatched(self):
        currentFile = xbmc.Player().getPlayingFile()

        # Get the active player
        result = xbmc.executeJSONRPC(
            '{"jsonrpc": "2.0", "id": 1, "method": "Player.GetActivePlayers"}')
        result = unicode(result, 'utf-8', errors='ignore')
        self.logMsg("Got active player " + result, 2)
        result = json.loads(result)

        # Seems to work too fast loop whilst waiting for it to become active
        while not result["result"]:
            result = xbmc.executeJSONRPC(
                '{"jsonrpc": "2.0", "id": 1, "method": "Player.GetActivePlayers"}'
            )
            result = unicode(result, 'utf-8', errors='ignore')
            self.logMsg("Got active player " + result, 2)
            result = json.loads(result)

        if 'result' in result and result["result"][0] is not None:
            playerid = result["result"][0]["playerid"]

            # Get details of the playing media
            self.logMsg("Getting details of playing media", 1)
            result = xbmc.executeJSONRPC(
                '{"jsonrpc": "2.0", "id": 1, "method": "Player.GetItem", "params": {"playerid": '
                + str(playerid) +
                ', "properties": ["showtitle", "tvshowid", "episode", "season", "playcount","genre"] } }'
            )
            result = unicode(result, 'utf-8', errors='ignore')
            self.logMsg("Got details of playing media" + result, 2)

            result = json.loads(result)
            if 'result' in result:
                itemtype = result["result"]["item"]["type"]
                if itemtype == "episode":
                    # playing an episode so find a random unwatched show from the same genre
                    genres = result["result"]["item"]["genre"]
                    if genres:
                        genretitle = genres[0]
                        self.logMsg(
                            "Looking up tvshow for genre " + genretitle, 2)
                        tvshow = utils.getJSON(
                            'VideoLibrary.GetTVShows',
                            '{ "sort": { "order": "descending", "method": "random" }, "filter": {"and": [{"operator":"is", "field":"genre", "value":"%s"}, {"operator":"is", "field":"playcount", "value":"0"}]}, "properties": [ %s ],"limits":{"end":1} }'
                            % (genretitle, self.fields_tvshows))
                    if not tvshow:
                        self.logMsg("Looking up tvshow without genre", 2)
                        tvshow = utils.getJSON(
                            'VideoLibrary.GetTVShows',
                            '{ "sort": { "order": "descending", "method": "random" }, "filter": {"and": [{"operator":"is", "field":"playcount", "value":"0"}]}, "properties": [ %s ],"limits":{"end":1} }'
                            % self.fields_tvshows)
                    self.logMsg("Got tvshow" + str(tvshow), 2)
                    tvshowid = tvshow[0]["tvshowid"]
                    episode = utils.getJSON(
                        'VideoLibrary.GetEpisodes',
                        '{ "tvshowid": %d, "sort": {"method":"episode"}, "filter": {"and": [ {"field": "playcount", "operator": "lessthan", "value":"1"}, {"field": "season", "operator": "greaterthan", "value": "0"} ]}, "properties": [ %s ], "limits":{"end":1}}'
                        % (tvshowid, self.fields_episodes))

                    if episode:
                        self.logMsg(
                            "Got details of next up episode %s" % str(episode),
                            2)
                        addonSettings = xbmcaddon.Addon(
                            id='service.nextup.notification')
                        unwatchedPage = UnwatchedInfo(
                            "script-nextup-notification-UnwatchedInfo.xml",
                            addonSettings.getAddonInfo('path'), "default",
                            "1080i")
                        unwatchedPage.setItem(episode[0])
                        self.logMsg("Calling display unwatched", 2)
                        unwatchedPage.show()
                        xbmc.sleep(10000)
                        self.logMsg("Calling close unwatched", 2)
                        unwatchedPage.close()

    def strm_query(self, result):
        try:
            self.logMsg('strm_query start')
            Myitemtype = result["result"]["item"]["type"]
            if Myitemtype == "episode":
                return True
            Myepisodenumber = result["result"]["item"]["episode"]
            Myseasonid = result["result"]["item"]["season"]
            Mytvshowid = result["result"]["item"]["tvshowid"]
            Myshowtitle = result["result"]["item"]["showtitle"]
            self.logMsg('strm_query end')

            if Mytvshowid == -1:
                return True

            else:
                return False
        except:
            self.logMsg('strm_query except')
            return False

    def autoPlayPlayback(self):
        currentFile = xbmc.Player().getPlayingFile()
        # Get the active player
        result = xbmc.executeJSONRPC(
            '{"jsonrpc": "2.0", "id": 1, "method": "Player.GetActivePlayers"}')
        result = unicode(result, 'utf-8', errors='ignore')
        self.logMsg("Got active player " + result, 2)
        result = json.loads(result)

        # Seems to work too fast loop whilst waiting for it to become active
        while not result["result"]:
            result = xbmc.executeJSONRPC(
                '{"jsonrpc": "2.0", "id": 1, "method": "Player.GetActivePlayers"}'
            )
            result = unicode(result, 'utf-8', errors='ignore')
            self.logMsg("Got active player " + result, 2)
            result = json.loads(result)

        if 'result' in result and result["result"][0] is not None:
            playerid = result["result"][0]["playerid"]

            # Get details of the playing media
            self.logMsg("Getting details of playing media", 1)
            result = xbmc.executeJSONRPC(
                '{"jsonrpc": "2.0", "id": 1, "method": "Player.GetItem", "params": {"playerid": '
                + str(playerid) +
                ', "properties": ["showtitle", "tvshowid", "episode", "season", "playcount"] } }'
            )
            result = unicode(result, 'utf-8', errors='ignore')
            self.logMsg("Got details of playing media" + result, 2)

            result = json.loads(result)
            if 'result' in result:
                itemtype = result["result"]["item"]["type"]

            if self.strm_query(result):
                addonSettings = xbmcaddon.Addon(
                    id='service.nextup.notification')
                playMode = addonSettings.getSetting("autoPlayMode")
                currentepisodenumber = result["result"]["item"]["episode"]
                currentseasonid = result["result"]["item"]["season"]
                currentshowtitle = result["result"]["item"]["showtitle"]
                tvshowid = result["result"]["item"]["tvshowid"]
                shortplayMode = addonSettings.getSetting("shortPlayMode")
                shortplayNotification = addonSettings.getSetting(
                    "shortPlayNotification")
                shortplayLength = int(
                    addonSettings.getSetting("shortPlayLength")) * 60

                if (itemtype == "episode"):
                    # Get the next up episode
                    currentepisodeid = result["result"]["item"]["id"]
                elif tvshowid == -1:
                    # I am a STRM ###
                    tvshowid, episodeid = self.iStream_fix(
                        tvshowid, currentshowtitle, currentepisodenumber,
                        currentseasonid)
                    currentepisodeid = episodeid
                else:
                    # wtf am i doing here error.. ####
                    self.logMsg("Error: cannot determine if episode", 1)
                    return

            self.currentepisodeid = currentepisodeid
            self.logMsg(
                "Getting details of next up episode for tvshow id: " +
                str(tvshowid), 1)
            if self.currenttvshowid != tvshowid:
                self.currenttvshowid = tvshowid
                self.playedinarow = 1

            result = xbmc.executeJSONRPC(
                '{"jsonrpc": "2.0", "method": "VideoLibrary.GetEpisodes", "params": {"tvshowid": %d, '
                '"properties": [ "title", "playcount", "season", "episode", "showtitle", "plot", '
                '"file", "rating", "resume", "tvshowid", "art", "firstaired", "runtime", "writer", '
                '"dateadded", "lastplayed" , "streamdetails"], "sort": {"method": "episode"}}, "id": 1}'
                % tvshowid)

            if result:
                result = unicode(result, 'utf-8', errors='ignore')
                result = json.loads(result)
                self.logMsg("Got details of next up episode %s" % str(result),
                            2)
                xbmc.sleep(100)

                # Find the next unwatched and the newest added episodes
                if "result" in result and "episodes" in result["result"]:
                    includeWatched = addonSettings.getSetting(
                        "includeWatched") == "true"
                    episode = self.findNextEpisode(result, currentFile,
                                                   includeWatched)

                    if episode is None:
                        # no episode get out of here
                        return
                    self.logMsg("episode details %s" % str(episode), 2)
                    self.episode = episode
                    episodeid = episode["episodeid"]

                    if includeWatched:
                        includePlaycount = True
                    else:
                        includePlaycount = episode["playcount"] == 0
                    if includePlaycount and currentepisodeid != episodeid:
                        # we have a next up episode
                        self.playbackonended = True
                        self.nextUpPage = NextUpInfo(
                            "script-nextup-notification-NextUpInfo.xml",
                            addonSettings.getAddonInfo('path'), "default",
                            "1080i")
                        self.nextUpPage.setItem(episode)
                        self.stillWatchingPage = StillWatchingInfo(
                            "script-nextup-notification-StillWatchingInfo.xml",
                            addonSettings.getAddonInfo('path'), "default",
                            "1080i")
                        self.stillWatchingPage.setItem(episode)
                        playedinarownumber = addonSettings.getSetting(
                            "playedInARow")
                        playTime = xbmc.Player().getTime()
                        self.totalTime = xbmc.Player().getTotalTime()
                        self.logMsg(
                            "played in a row settings %s" %
                            str(playedinarownumber), 2)
                        self.logMsg(
                            "played in a row %s" % str(self.playedinarow), 2)
                        if int(self.playedinarow) <= int(playedinarownumber):
                            self.logMsg(
                                "showing next up page as played in a row is %s"
                                % str(self.playedinarow), 2)
                            if (shortplayNotification == "false") and (
                                    shortplayLength >= self.totalTime) and (
                                        shortplayMode == "true"):
                                self.logMsg(
                                    "hiding notification for short videos")
                            else:
                                self.nextUpPage.show()
                        else:
                            self.logMsg(
                                "showing still watching page as played in a row %s"
                                % str(self.playedinarow), 2)
                            if (shortplayNotification == "false") and (
                                    shortplayLength >= self.totalTime) and (
                                        shortplayMode == "true"):
                                self.logMsg(
                                    "hiding notification for short videos")
                            else:
                                self.stillWatchingPage.show()
                        while xbmc.Player().isPlaying(
                        ) and not self.nextUpPage.isCancel(
                        ) and not self.nextUpPage.isWatchNow(
                        ) and not self.stillWatchingPage.isStillWatching(
                        ) and not self.stillWatchingPage.isCancel():
                            xbmc.sleep(100)
                            #try:
                            # playTime = xbmc.Player().getTime()
                            #  totalTime = xbmc.Player().getTotalTime()
                            #except:
                            # pass
                        if xbmc.Player().isPlaying():
                            if shortplayLength >= self.totalTime and shortplayMode == "true":
                                #play short video and don't add to playcount
                                self.playedinarow += 0
                                self.logMsg(
                                    "Continuing short video autoplay - %s")
                                if self.nextUpPage.isWatchNow(
                                ) or self.stillWatchingPage.isStillWatching():
                                    self.playedinarow = 1
                                shouldPlayDefault = not self.nextUpPage.isCancel(
                                )
                            else:
                                if int(self.playedinarow) <= int(
                                        playedinarownumber):
                                    self.nextUpPage.close()
                                    shouldPlayDefault = not self.nextUpPage.isCancel(
                                    )
                                    shouldPlayNonDefault = self.nextUpPage.isWatchNow(
                                    )
                                else:
                                    self.stillWatchingPage.close()
                                    shouldPlayDefault = self.stillWatchingPage.isStillWatching(
                                    )
                                    shouldPlayNonDefault = self.stillWatchingPage.isStillWatching(
                                    )

                                if self.nextUpPage.isWatchNow(
                                ) or self.stillWatchingPage.isStillWatching():
                                    self.playedinarow = 1
                                else:
                                    self.playedinarow += 1

                            if (shouldPlayDefault and playMode == "0") or (
                                    shouldPlayNonDefault and playMode == "1"):
                                self.logMsg(
                                    "playing media episode id %s" %
                                    str(episodeid), 2)
                                # Signal to trakt previous episode watched as playback ended early
                                AddonSignals.sendSignal(
                                    "NEXTUPWATCHEDSIGNAL",
                                    {'episodeid': self.currentepisodeid})

                                # Play media
                                xbmc.executeJSONRPC(
                                    '{ "jsonrpc": "2.0", "id": 0, "method": "Player.Open", '
                                    '"params": { "item": {"episodeid": ' +
                                    str(episode["episodeid"]) + '} } }')

    def onPlayBackEnded(self):
        # Will be called when kodi stops playing a file
        self.logMsg("ONPLAYBACK_ENDED", 2)
        addonSettings = xbmcaddon.Addon(id='service.nextup.notification')
        playMode = addonSettings.getSetting("autoPlayMode")
        playedinarownumber = addonSettings.getSetting("playedInARow")
        shortplayMode = addonSettings.getSetting("shortPlayMode")
        shortplayLength = int(addonSettings.getSetting("shortPlayLength")) * 60

        if self.playbackonended and self.episode:
            self.logMsg("playback ended and next up episode to show", 2)
            if shortplayLength >= self.totalTime and shortplayMode == "true":
                #play short video and don't add to playcount
                self.playedinarow += 0
                self.logMsg("Continuing short video autoplay - %s")
                if self.nextUpPage.isWatchNow(
                ) or self.stillWatchingPage.isStillWatching():
                    self.playedinarow = 1
                shouldPlayDefault = not self.nextUpPage.isCancel()
            else:
                if int(self.playedinarow) <= int(playedinarownumber):
                    self.nextUpPage.close()
                    shouldPlayDefault = not self.nextUpPage.isCancel()
                    shouldPlayNonDefault = self.nextUpPage.isWatchNow()
                else:
                    self.stillWatchingPage.close()
                    shouldPlayDefault = self.stillWatchingPage.isStillWatching(
                    )
                    shouldPlayNonDefault = self.stillWatchingPage.isStillWatching(
                    )

                if self.nextUpPage.isWatchNow(
                ) or self.stillWatchingPage.isStillWatching():
                    self.playedinarow = 1
                else:
                    self.playedinarow += 1

            if (shouldPlayDefault
                    and playMode == "0") or (shouldPlayNonDefault
                                             and playMode == "1"):
                episodeid = self.episode["episodeid"]
                self.logMsg(
                    "playing media episode onplaybackended id %s" %
                    str(episodeid), 2)
                # Play media
                xbmc.executeJSONRPC(
                    '{ "jsonrpc": "2.0", "id": 0, "method": "Player.Open", '
                    '"params": { "item": {"episodeid": ' + str(episodeid) +
                    '} } }')
示例#20
0
class TextureCache():

    addonName = ClientInformation().getAddonName()

    xbmc_host = 'localhost'
    xbmc_port = None
    xbmc_username = None
    xbmc_password = None
    enableTextureCache = utils.settings('enableTextureCache') == "true"

    def __init__(self):

        if not self.xbmc_port and self.enableTextureCache:
            self.setKodiWebServerDetails()

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

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

    def double_urlencode(self, text):
        text = self.single_urlencode(text)
        text = self.single_urlencode(text)

        return text

    def single_urlencode(self, text):
        blah = urllib.urlencode({'blahblahblah': text})
        blah = blah[13:]

        return blah

    def setKodiWebServerDetails(self):
        # Get the Kodi webserver details - used to set the texture cache
        json_response = xbmc.executeJSONRPC(
            '{"jsonrpc":"2.0", "id":1, "method":"Settings.GetSettingValue","params":{"setting":"services.webserver"}, "id":1}'
        )
        jsonobject = json.loads(json_response.decode('utf-8', 'replace'))
        if (jsonobject.has_key('result')):
            xbmc_webserver_enabled = jsonobject["result"]["value"]

        if not xbmc_webserver_enabled:
            #enable the webserver if not enabled
            xbmc.executeJSONRPC(
                '{"jsonrpc":"2.0", "id":1, "method":"Settings.SetSettingValue","params":{"setting":"services.webserverport","value":8080}, "id":1}'
            )
            self.xbmc_port = 8080
            xbmc.executeJSONRPC(
                '{"jsonrpc":"2.0", "id":1, "method":"Settings.SetSettingValue","params":{"setting":"services.webserver","value":true}, "id":1}'
            )
            self.xbmc_port = "kodi"

        json_response = xbmc.executeJSONRPC(
            '{"jsonrpc":"2.0", "id":1, "method":"Settings.GetSettingValue","params":{"setting":"services.webserverport"}, "id":1}'
        )
        jsonobject = json.loads(json_response.decode('utf-8', 'replace'))
        if (jsonobject.has_key('result')):
            self.xbmc_port = jsonobject["result"]["value"]

        json_response = xbmc.executeJSONRPC(
            '{"jsonrpc":"2.0", "id":1, "method":"Settings.GetSettingValue","params":{"setting":"services.webserverusername"}, "id":1}'
        )
        jsonobject = json.loads(json_response.decode('utf-8', 'replace'))
        if (jsonobject.has_key('result')):
            self.xbmc_username = jsonobject["result"]["value"]

        json_response = xbmc.executeJSONRPC(
            '{"jsonrpc":"2.0", "id":1, "method":"Settings.GetSettingValue","params":{"setting":"services.webserverpassword"}, "id":1}'
        )
        jsonobject = json.loads(json_response.decode('utf-8', 'replace'))
        if (jsonobject.has_key('result')):
            self.xbmc_password = jsonobject["result"]["value"]

    def FullTextureCacheSync(self):
        #this method can be called from the plugin to sync all Kodi textures to the texture cache.
        #Warning: this means that every image will be cached locally, this takes diskspace!

        # Remove all existing textures first
        path = "special://thumbnails/"
        if xbmcvfs.exists(path):
            allDirs, allFiles = xbmcvfs.listdir(path)
            for dir in allDirs:
                allDirs, allFiles = xbmcvfs.listdir(path + dir)
                for file in allFiles:
                    xbmcvfs.delete(os.path.join(path + dir, file))

        textureconnection = utils.KodiSQL('texture')
        texturecursor = textureconnection.cursor()
        texturecursor.execute(
            'SELECT tbl_name FROM sqlite_master WHERE type="table"')
        rows = texturecursor.fetchall()
        for row in rows:
            tableName = row[0]
            if (tableName != "version"):
                texturecursor.execute("DELETE FROM " + tableName)
        textureconnection.commit()
        texturecursor.close()

        # Cache all entries in video DB
        connection = utils.KodiSQL('video')
        cursor = connection.cursor()
        cursor.execute("SELECT url FROM art")
        result = cursor.fetchall()
        for url in result:
            self.CacheTexture(url[0])
        cursor.close()

        # Cache all entries in music DB
        connection = utils.KodiSQL('music')
        cursor = connection.cursor()
        cursor.execute("SELECT url FROM art")
        result = cursor.fetchall()
        for url in result:
            self.CacheTexture(url[0])
        cursor.close()

    def addArtwork(self, artwork, kodiId, mediaType, cursor):
        # Kodi conversion table
        kodiart = {
            'Primary': ["thumb", "poster"],
            'Banner': "banner",
            'Logo': "clearlogo",
            'Art': "clearart",
            'Thumb': "landscape",
            'Disc': "discart",
            'Backdrop': "fanart",
            'BoxRear': "poster"
        }

        # Artwork is a dictionary
        for art in artwork:

            if art == "Backdrop":
                # Backdrop entry is a list, process extra fanart for artwork downloader (fanart, fanart1, fanart2, etc.)
                backdrops = artwork[art]
                backdropsNumber = len(backdrops)

                cursor.execute(
                    "SELECT url FROM art WHERE media_id = ? AND media_type = ? AND type LIKE ?",
                    (
                        kodiId,
                        mediaType,
                        "fanart%",
                    ))
                rows = cursor.fetchall()

                if len(rows) > backdropsNumber:
                    # More backdrops in database than what we are going to process. Delete extra fanart.
                    cursor.execute(
                        "DELETE FROM art WHERE media_id = ? AND media_type = ? AND type LIKE ?",
                        (
                            kodiId,
                            mediaType,
                            "fanart_",
                        ))

                index = ""
                for backdrop in backdrops:
                    self.addOrUpdateArt(backdrop, kodiId, mediaType,
                                        "%s%s" % ("fanart", index), cursor)
                    if backdropsNumber > 1:
                        try:  # Will only fail on the first try, str to int.
                            index += 1
                        except TypeError:
                            index = 1

            elif art == "Primary":
                # Primary art is processed as thumb and poster for Kodi.
                for artType in kodiart[art]:
                    self.addOrUpdateArt(artwork[art], kodiId, mediaType,
                                        artType, cursor)

            elif kodiart.get(art):  # For banner, logo, art, thumb, disc
                # Only process artwork type that Kodi can use
                self.addOrUpdateArt(artwork[art], kodiId, mediaType,
                                    kodiart[art], cursor)

    def addOrUpdateArt(self, imageUrl, kodiId, mediaType, imageType, cursor):
        # Possible that the imageurl is an empty string
        if imageUrl:
            cacheimage = False

            cursor.execute(
                "SELECT url FROM art WHERE media_id = ? AND media_type = ? AND type = ?",
                (
                    kodiId,
                    mediaType,
                    imageType,
                ))
            try:  # Update the artwork
                url = cursor.fetchone()[0]

            except:  # Add the artwork
                cacheimage = True
                self.logMsg(
                    "Adding Art Link for kodiId: %s (%s)" % (kodiId, imageUrl),
                    2)
                query = "INSERT INTO art(media_id, media_type, type, url) values(?, ?, ?, ?)"
                cursor.execute(query, (kodiId, mediaType, imageType, imageUrl))

            else:  # Only cache artwork if it changed
                if url != imageUrl:
                    cacheimage = True

                    # Only for the main backdrop, poster
                    if imageType in ("fanart", "poster"):
                        # Delete current entry before updating with the new one
                        self.deleteCachedArtwork(url)

                    self.logMsg(
                        "Updating Art Link for kodiId: %s (%s) -> (%s)" %
                        (kodiId, url, imageUrl), 1)
                    query = "UPDATE art set url = ? WHERE media_id = ? AND media_type = ? AND type = ?"
                    cursor.execute(query,
                                   (imageUrl, kodiId, mediaType, imageType))

            # Cache fanart and poster in Kodi texture cache
            if cacheimage and imageType in ("fanart", "poster"):
                self.CacheTexture(imageUrl)

    def CacheTexture(self, url):
        # Cache a single image url to the texture cache
        if url and self.enableTextureCache:
            self.logMsg("Processing: %s" % url, 2)

            # Add image to texture cache by simply calling it at the http endpoint
            url = self.double_urlencode(url)
            try:  # Extreme short timeouts so we will have a exception, but we don't need the result so pass
                response = requests.head('http://%s:%s/image/image://%s' %
                                         (self.xbmc_host, self.xbmc_port, url),
                                         auth=(self.xbmc_username,
                                               self.xbmc_password),
                                         timeout=(0.01, 0.01))
            except:
                pass

    def deleteCachedArtwork(self, url):
        # Only necessary to remove and apply a new backdrop or poster
        connection = utils.KodiSQL('texture')
        cursor = connection.cursor()

        cursor.execute("SELECT cachedurl FROM texture WHERE url = ?", (url, ))
        try:
            cachedurl = cursor.fetchone()[0]

        except:
            self.logMsg("Could not find cached url.", 1)

        else:  # Delete thumbnail as well as the entry
            thumbnails = xbmc.translatePath("special://thumbnails/%s" %
                                            cachedurl)
            self.logMsg("Deleting cached thumbnail: %s" % thumbnails, 1)
            xbmcvfs.delete(thumbnails)

            cursor.execute("DELETE FROM texture WHERE url = ?", (url, ))
            connection.commit()

        finally:
            cursor.close()
示例#21
0
def addUser():

    doUtils = DownloadUtils()
    clientInfo = ClientInformation()
    currUser = WINDOW.getProperty("currUser")
    deviceId = clientInfo.getMachineId()
    deviceName = clientInfo.getDeviceName()

    # Get session
    url = "{server}/mediabrowser/Sessions?DeviceId=%s" % deviceId
    result = doUtils.downloadUrl(url)

    try:
        sessionId = result[0][u'Id']
        additionalUsers = result[0][u'AdditionalUsers']
        # Add user to session
        userlist = {}
        users = []
        url = "{server}/mediabrowser/Users?IsDisabled=false&IsHidden=false"
        result = doUtils.downloadUrl(url)

        # pull the list of users
        for user in result:
            name = user[u'Name']
            userId = user[u'Id']
            if currUser not in name:
                userlist[name] = userId
                users.append(name)

        # Display dialog if there's additional users
        if additionalUsers:

            option = xbmcgui.Dialog().select(
                "Add/Remove user from the session",
                ["Add user", "Remove user"])
            # Users currently in the session
            additionalUserlist = {}
            additionalUsername = []
            # Users currently in the session
            for user in additionalUsers:
                name = user[u'UserName']
                userId = user[u'UserId']
                additionalUserlist[name] = userId
                additionalUsername.append(name)

            if option == 1:
                # User selected Remove user
                resp = xbmcgui.Dialog().select("Remove user from the session",
                                               additionalUsername)
                if resp > -1:
                    selected = additionalUsername[resp]
                    selected_userId = additionalUserlist[selected]
                    url = "{server}/mediabrowser/Sessions/%s/Users/%s" % (
                        sessionId, selected_userId)
                    postdata = {}
                    doUtils.downloadUrl(url, postBody=postdata, type="DELETE")
                    xbmcgui.Dialog().notification(
                        "Success!",
                        "%s removed from viewing session" % selected,
                        time=1000)

                    # clear picture
                    position = WINDOW.getProperty(
                        'EmbyAdditionalUserPosition.' + selected_userId)
                    WINDOW.clearProperty('EmbyAdditionalUserImage.' +
                                         str(position))
                    return
                else:
                    return

            elif option == 0:
                # User selected Add user
                for adduser in additionalUsername:
                    try:  # Remove from selected already added users. It is possible they are hidden.
                        users.remove(adduser)
                    except:
                        pass

            elif option < 0:
                # User cancelled
                return

        # Subtract any additional users
        xbmc.log("Displaying list of users: %s" % users)
        resp = xbmcgui.Dialog().select("Add user to the session", users)
        # post additional user
        if resp > -1:
            selected = users[resp]
            selected_userId = userlist[selected]
            url = "{server}/mediabrowser/Sessions/%s/Users/%s" % (
                sessionId, selected_userId)
            postdata = {}
            doUtils.downloadUrl(url, postBody=postdata, type="POST")
            xbmcgui.Dialog().notification("Success!",
                                          "%s added to viewing session" %
                                          selected,
                                          time=1000)

    except:
        xbmc.log("Failed to add user to session.")
        xbmcgui.Dialog().notification(
            "Error", "Unable to add/remove user from the session.",
            xbmcgui.NOTIFICATION_ERROR)

    try:
        # Add additional user images
        #always clear the individual items first
        totalNodes = 10
        for i in range(totalNodes):
            if not WINDOW.getProperty('EmbyAdditionalUserImage.' + str(i)):
                break
            WINDOW.clearProperty('EmbyAdditionalUserImage.' + str(i))

        url = "{server}/mediabrowser/Sessions?DeviceId=%s" % deviceId
        result = doUtils.downloadUrl(url)
        additionalUsers = result[0][u'AdditionalUsers']
        count = 0
        for additionaluser in additionalUsers:
            url = "{server}/mediabrowser/Users/%s?format=json" % (
                additionaluser[u'UserId'])
            result = doUtils.downloadUrl(url)
            WINDOW.setProperty("EmbyAdditionalUserImage." + str(count),
                               API().getUserArtwork(result, "Primary"))
            WINDOW.setProperty(
                "EmbyAdditionalUserPosition." + str(additionaluser[u'UserId']),
                str(count))
            count += 1
    except:
        pass
示例#22
0
class ConnectionManager():

    clientInfo = ClientInformation()
    uc = UserClient()
    doUtils = DownloadUtils()

    addonName = clientInfo.getAddonName()
    addonId = clientInfo.getAddonId()
    addon = xbmcaddon.Addon(id=addonId)
    WINDOW = xbmcgui.Window(10000)

    logLevel = 0

    def __init__(self):

        self.className = self.__class__.__name__
        self.__language__ = self.addon.getLocalizedString
    
    def logMsg(self, msg, lvl=1):

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

    def checkServer(self):
        
        self.WINDOW.setProperty("Server_Checked", "True")
        self.logMsg("Connection Manager Called", 2)
        
        addon = self.addon
        server = self.uc.getServer()

        if (server != ""):
            self.logMsg("Server already set", 2)
            return
        
        serverInfo = self.getServerDetails()
        
        if (serverInfo == None):
            self.logMsg("getServerDetails failed", 1)
            xbmc.executebuiltin('Addon.OpenSettings(%s)' % self.addonId)
            return

        prefix,ip,port = serverInfo.split(":")
        setServer = xbmcgui.Dialog().yesno(self.__language__(30167), "Proceed with the following server?", self.__language__(30169) + serverInfo)
        
        if (setServer == 1):
            self.logMsg("Server selected. Saving information.", 1)
            addon.setSetting("ipaddress", ip.replace("/", ""))
            addon.setSetting("port", port)
            # If https is enabled
            if (prefix == 'https'):
                addon.setSetting('https', "true")
        else:
            self.logMsg("No server selected.", 1)
            xbmc.executebuiltin('Addon.OpenSettings(%s)' % self.addonId)
            return

        # Get List of public users
        self.logMsg("Getting user list", 1)
        server = ip.replace("/", "") + ":" + port
        url = "%s/mediabrowser/Users/Public?format=json" % serverInfo

        try:
            result = self.doUtils.downloadUrl(url, authenticate=False)
        except Exception, msg:
            error = "Unable to connect to %s: %s" % (server, msg)
            self.logMsg(error, 1)
            return ""
        
        if (result == ""):
            return
    
        self.logMsg("jsonData: %s" % result, 2)

        names = []
        userList = []
        for user in result:
            name = user[u'Name']
            userList.append(name)

            if(user[u'HasPassword'] == True):
                name = name + " (Secure)"
            names.append(name)
    
        self.logMsg("User List: %s" % names, 1)
        self.logMsg("User List: %s" % userList, 2)
        return_value = xbmcgui.Dialog().select(self.__language__(30200), names)
        
        if (return_value > -1):
            selected_user = userList[return_value]
            self.logMsg("Selected User: %s" % selected_user, 1)      
            self.addon.setSetting("username", selected_user)
        else:
            self.logMsg("No user selected.", 1)
            xbmc.executebuiltin('Addon.OpenSettings(%s)' % self.addonId)
            return
            
        # Option to play from http
        setPlayback = xbmcgui.Dialog().yesno("Playback option", "Play your files using HTTP?")
        if setPlayback == 1:
            self.logMsg("Playback will be set using HTTP.", 1)
            addon.setSetting("playFromStream", "true")
        else:
            self.logMsg("Playback will be set using SMB.", 1)
class Player(xbmc.Player):

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

    xbmcplayer = xbmc.Player()
    clientInfo = ClientInformation()

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

    logLevel = 0
    currenttvshowid = None
    currentepisodeid = None
    playedinarow = 1

    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 json_query(self, query, ret):
        try:
            xbmc_request = json.dumps(query)
            result = xbmc.executeJSONRPC(xbmc_request)
            result = unicode(result, 'utf-8', errors='ignore')
            if ret:
                return json.loads(result)['result']

            else:
                return json.loads(result)
        except:
            xbmc_request = json.dumps(query)
            result = xbmc.executeJSONRPC(xbmc_request)
            result = unicode(result, 'utf-8', errors='ignore')
            self.logMsg(json.loads(result), 1)
            return json.loads(result)

    def iStream_fix(self, show_npid, showtitle, episode_np, season_np):

        # streams from iStream dont provide the showid and epid for above
        # they come through as tvshowid = -1, but it has episode no and season no and show name
        # need to insert work around here to get showid from showname, and get epid from season and episode no's
        # then need to ignore prevcheck
        self.logMsg('fixing strm, data follows...')
        self.logMsg('show_npid = ' + str(show_npid))
        self.logMsg('showtitle = ' + str(showtitle))
        self.logMsg('episode_np = ' + str(episode_np))
        self.logMsg('season_np = ' + str(season_np))

        show_request_all = {
            "jsonrpc": "2.0",
            "method": "VideoLibrary.GetTVShows",
            "params": {
                "properties": ["title"]
            },
            "id": "1"
        }
        eps_query = {
            "jsonrpc": "2.0",
            "method": "VideoLibrary.GetEpisodes",
            "params": {
                "properties": [
                    "season", "episode", "runtime", "resume", "playcount",
                    "tvshowid", "lastplayed", "file"
                ],
                "tvshowid":
                "1"
            },
            "id": "1"
        }

        ep_npid = " "

        redo = True
        count = 0
        while redo and count < 2:  # this ensures the section of code only runs twice at most [ only runs once fine ?
            redo = False
            count += 1
            if show_npid == -1 and showtitle and episode_np and season_np:
                prevcheck = False
                tmp_shows = self.json_query(show_request_all, True)
                self.logMsg('tmp_shows = ' + str(tmp_shows))
                if 'tvshows' in tmp_shows:
                    for x in tmp_shows['tvshows']:
                        if x['label'] == showtitle:
                            show_npid = x['tvshowid']
                            eps_query['params']['tvshowid'] = show_npid
                            tmp_eps = self.json_query(eps_query, True)
                            self.logMsg('tmp eps = ' + str(tmp_eps))
                            if 'episodes' in tmp_eps:
                                for y in tmp_eps['episodes']:
                                    if (y['season']) == season_np and (
                                            y['episode']) == episode_np:
                                        ep_npid = y['episodeid']
                                        self.logMsg('playing epid stream = ' +
                                                    str(ep_npid))

        return show_npid, ep_npid

    def findNextEpisode(self, result):
        self.logMsg("Find next episode called", 1)
        position = 0
        for episode in result["result"]["episodes"]:
            # find position of current episode
            if self.currentepisodeid == episode["episodeid"]:
                # found a match so add 1 for the next and get out of here
                position = position + 1
                break
            else:
                # no match found continue
                position = position + 1
        # now return the episode
        self.logMsg(
            "Find next episode found next episode in position: " +
            str(position), 1)
        try:
            episode = result["result"]["episodes"][position]
        except:
            # no next episode found
            episode = None

        return episode

    def autoPlayPlayback(self):
        currentFile = xbmc.Player().getPlayingFile()

        # Get the active player
        result = xbmc.executeJSONRPC(
            '{"jsonrpc": "2.0", "id": 1, "method": "Player.GetActivePlayers"}')
        result = unicode(result, 'utf-8', errors='ignore')
        self.logMsg("Got active player " + result, 2)
        result = json.loads(result)

        # Seems to work too fast loop whilst waiting for it to become active
        while result["result"] == []:
            result = xbmc.executeJSONRPC(
                '{"jsonrpc": "2.0", "id": 1, "method": "Player.GetActivePlayers"}'
            )
            result = unicode(result, 'utf-8', errors='ignore')
            self.logMsg("Got active player " + result, 2)
            result = json.loads(result)

        if result.has_key('result') and result["result"][0] != None:
            playerid = result["result"][0]["playerid"]

            # Get details of the playing media
            self.logMsg("Getting details of playing media", 1)
            result = xbmc.executeJSONRPC(
                '{"jsonrpc": "2.0", "id": 1, "method": "Player.GetItem", "params": {"playerid": '
                + str(playerid) +
                ', "properties": ["showtitle", "tvshowid", "episode", "season", "playcount"] } }'
            )
            result = unicode(result, 'utf-8', errors='ignore')
            self.logMsg("Got details of playing media" + result, 2)

            result = json.loads(result)
            if result.has_key('result'):
                type = result["result"]["item"]["type"]
                if type == "episode":
                    # Get the next up episode
                    addonSettings = xbmcaddon.Addon(
                        id='service.nextup.notification')
                    playMode = addonSettings.getSetting("autoPlayMode")
                    tvshowid = result["result"]["item"]["tvshowid"]
                    currentepisodenumber = result["result"]["item"]["episode"]
                    currentseasonid = result["result"]["item"]["season"]
                    currentshowtitle = result["result"]["item"]["showtitle"]
                    tvshowid = result["result"]["item"]["tvshowid"]

                    # I am a STRM ###
                    if tvshowid == -1:
                        tvshowid, episodeid = self.iStream_fix(
                            tvshowid, currentshowtitle, currentepisodenumber,
                            currentseasonid)
                        currentepisodeid = episodeid
                    else:
                        currentepisodeid = result["result"]["item"]["id"]

                    self.currentepisodeid = currentepisodeid
                    self.logMsg(
                        "Getting details of next up episode for tvshow id: " +
                        str(tvshowid), 1)
                    if self.currenttvshowid != tvshowid:
                        self.currenttvshowid = tvshowid
                        self.playedinarow = 1
                    includeWatched = addonSettings.getSetting(
                        "includeWatched") == "true"
                    if includeWatched == True:
                        result = xbmc.executeJSONRPC(
                            '{"jsonrpc": "2.0", "method": "VideoLibrary.GetEpisodes", "params": {"tvshowid": %d, "properties": [ "title", "playcount", "season", "episode", "showtitle", "plot", "file", "rating", "resume", "tvshowid", "art", "firstaired", "runtime", "writer", "dateadded", "lastplayed" , "streamdetails"], "sort": {"method": "episode"}}, "id": 1}'
                            % tvshowid)
                    else:
                        result = xbmc.executeJSONRPC(
                            '{"jsonrpc": "2.0", "method": "VideoLibrary.GetEpisodes", "params": { "tvshowid": %d, "sort": {"method":"episode"}, "filter": {"field": "playcount", "operator": "lessthan", "value":"1"}, "properties": [ "title", "playcount", "season", "episode", "showtitle", "plot", "file", "rating", "resume", "tvshowid", "art", "firstaired", "runtime", "writer", "dateadded", "lastplayed" , "streamdetails"], "limits":{"start":1,"end":2}}, "id": "1"}'
                            % tvshowid)

                    if result:
                        result = unicode(result, 'utf-8', errors='ignore')
                        result = json.loads(result)
                        self.logMsg(
                            "Got details of next up episode %s" % str(result),
                            2)
                        xbmc.sleep(100)

                        # Find the next unwatched and the newest added episodes
                        if result.has_key("result") and result[
                                "result"].has_key("episodes"):
                            if includeWatched == True:
                                episode = self.findNextEpisode(result)
                            else:
                                episode = result["result"]["episodes"][0]

                            if episode == None:
                                # no episode get out of here
                                return
                            self.logMsg("episode details %s" % str(episode), 2)
                            episodeid = episode["episodeid"]
                            includePlaycount = True
                            if includeWatched == True:
                                includePlaycount = True
                            else:
                                includePlaycount = episode["playcount"] == 0
                            if includePlaycount and currentepisodeid != episodeid:
                                # we have a next up episode
                                nextUpPage = NextUpInfo(
                                    "script-nextup-notification-NextUpInfo.xml",
                                    addonSettings.getAddonInfo('path'),
                                    "default", "1080i")
                                nextUpPage.setItem(episode)
                                stillWatchingPage = StillWatchingInfo(
                                    "script-nextup-notification-StillWatchingInfo.xml",
                                    addonSettings.getAddonInfo('path'),
                                    "default", "1080i")
                                stillWatchingPage.setItem(episode)
                                playTime = xbmc.Player().getTime()
                                totalTime = xbmc.Player().getTotalTime()
                                playedinarownumber = addonSettings.getSetting(
                                    "playedInARow")
                                self.logMsg(
                                    "played in a row settings %s" %
                                    str(playedinarownumber), 2)
                                self.logMsg(
                                    "played in a row %s" %
                                    str(self.playedinarow), 2)
                                if int(self.playedinarow) <= int(
                                        playedinarownumber):
                                    self.logMsg(
                                        "showing next up page as played in a row is %s"
                                        % str(self.playedinarow), 2)
                                    nextUpPage.show()
                                else:
                                    self.logMsg(
                                        "showing still watching page as played in a row %s"
                                        % str(self.playedinarow), 2)
                                    stillWatchingPage.show()
                                playTime = xbmc.Player().getTime()
                                totalTime = xbmc.Player().getTotalTime()
                                while xbmc.Player().isPlaying() and (
                                        totalTime - playTime > 1
                                ) and not nextUpPage.isCancel(
                                ) and not nextUpPage.isWatchNow(
                                ) and not stillWatchingPage.isStillWatching(
                                ) and not stillWatchingPage.isCancel():
                                    xbmc.sleep(100)
                                    try:
                                        playTime = xbmc.Player().getTime()
                                        totalTime = xbmc.Player().getTotalTime(
                                        )
                                    except:
                                        pass

                                if int(self.playedinarow) <= int(
                                        playedinarownumber):
                                    nextUpPage.close()
                                    shouldPlayDefault = not nextUpPage.isCancel(
                                    )
                                    shouldPlayNonDefault = nextUpPage.isWatchNow(
                                    )
                                else:
                                    stillWatchingPage.close()
                                    shouldPlayDefault = stillWatchingPage.isStillWatching(
                                    )
                                    shouldPlayNonDefault = stillWatchingPage.isStillWatching(
                                    )

                                if nextUpPage.isWatchNow(
                                ) or stillWatchingPage.isStillWatching():
                                    self.playedinarow = 1
                                else:
                                    self.playedinarow = self.playedinarow + 1
                                if (shouldPlayDefault and playMode
                                        == "0") or (shouldPlayNonDefault
                                                    and playMode == "1"):
                                    self.logMsg(
                                        "playing media episode id %s" %
                                        str(episodeid), 2)
                                    # Play media
                                    xbmc.executeJSONRPC(
                                        '{ "jsonrpc": "2.0", "id": 0, "method": "Player.Open", "params": { "item": {"episodeid": '
                                        + str(episode["episodeid"]) + '} } }')
示例#24
0
class DownloadUtils():

    # Borg - multiple instances, shared state
    _shared_state = {}
    clientInfo = ClientInformation()

    addonName = clientInfo.getAddonName()
    addon = xbmcaddon.Addon()
    WINDOW = xbmcgui.Window(10000)

    # Requests session
    s = None
    timeout = 60

    def __init__(self):

        self.__dict__ = self._shared_state

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

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

    def setUsername(self, username):
        # Reserved for UserClient only
        self.username = username
        self.logMsg("Set username: %s" % username, 2)

    def setUserId(self, userId):
        # Reserved for UserClient only
        self.userId = userId
        self.logMsg("Set userId: %s" % userId, 2)

    def setServer(self, server):
        # Reserved for UserClient only
        self.server = server
        self.logMsg("Set server: %s" % server, 2)

    def setToken(self, token):
        # Reserved for UserClient only
        self.token = token
        self.logMsg("Set token: %s" % token, 2)

    def setSSL(self, ssl, sslclient):
        # Reserved for UserClient only
        self.sslverify = ssl
        self.sslclient = sslclient
        self.logMsg("Verify SSL host certificate: %s" % ssl, 2)
        self.logMsg("SSL client side certificate: %s" % sslclient, 2)

    def postCapabilities(self, deviceId):

        # Post settings to session
        url = "{server}/mediabrowser/Sessions/Capabilities/Full"
        data = {
            'PlayableMediaTypes':
            "Audio,Video",
            'SupportsMediaControl':
            True,
            'SupportedCommands':
            ("MoveUp,MoveDown,MoveLeft,MoveRight,Select,"
             "Back,ToggleContextMenu,ToggleFullscreen,ToggleOsdMenu,"
             "GoHome,PageUp,NextLetter,GoToSearch,"
             "GoToSettings,PageDown,PreviousLetter,TakeScreenshot,"
             "VolumeUp,VolumeDown,ToggleMute,SendString,DisplayMessage,"
             "SetAudioStreamIndex,SetSubtitleStreamIndex,"
             "Mute,Unmute,SetVolume,"
             "Play,Playstate,PlayNext")
        }

        self.logMsg("Capabilities URL: %s" % url, 2)
        self.logMsg("PostData: %s" % data, 2)

        try:
            self.downloadUrl(url, postBody=data, type="POST")
            self.logMsg("Posted capabilities to %s" % self.server, 1)
        except:
            self.logMsg("Posted capabilities failed.")

        # Attempt at getting sessionId
        url = "{server}/mediabrowser/Sessions?DeviceId=%s&format=json" % deviceId

        try:
            result = self.downloadUrl(url)
            self.logMsg("Session: %s" % result, 2)

            sessionId = result[0][u'Id']
            self.logMsg("SessionId: %s" % sessionId)
            self.WINDOW.setProperty("sessionId%s" % self.username, sessionId)
        except:
            self.logMsg("Failed to retrieve sessionId.", 1)
        else:
            # Post any permanent additional users
            additionalUsers = utils.settings('additionalUsers').split(',')
            self.logMsg(
                "List of permanent users that should be added to the session: %s"
                % str(additionalUsers), 1)
            # Get the user list from server to get the userId
            url = "{server}/mediabrowser/Users?format=json"
            result = self.downloadUrl(url)

            if result:
                for user in result:
                    username = user['Name'].lower()
                    userId = user['Id']
                    for additional in additionalUsers:
                        addUser = additional.decode('utf-8').lower()
                        if username in addUser:
                            url = "{server}/mediabrowser/Sessions/%s/Users/%s" % (
                                sessionId, userId)
                            postdata = {}
                            self.downloadUrl(url,
                                             postBody=postdata,
                                             type="POST")
                            #xbmcgui.Dialog().notification("Success!", "%s added to viewing session" % username, time=1000)

    def startSession(self):

        self.deviceId = self.clientInfo.getMachineId()

        # User is identified from this point
        # Attach authenticated header to the session
        verify = None
        cert = None
        header = self.getHeader()

        # If user enabled host certificate verification
        try:
            verify = self.sslverify
            cert = self.sslclient
        except:
            self.logMsg("Could not load SSL settings.", 1)

        # Start session
        self.s = requests.Session()
        self.s.headers = header
        self.s.verify = verify
        self.s.cert = cert
        # Retry connections to the server
        self.s.mount("http://", requests.adapters.HTTPAdapter(max_retries=1))
        self.s.mount("https://", requests.adapters.HTTPAdapter(max_retries=1))

        self.logMsg("Requests session started on: %s" % self.server)

    def stopSession(self):
        try:
            self.s.close()
        except:
            self.logMsg("Requests session could not be terminated.", 1)

    def getHeader(self, authenticate=True):

        clientInfo = self.clientInfo

        deviceName = clientInfo.getDeviceName()
        deviceId = clientInfo.getMachineId()
        version = clientInfo.getVersion()

        if not authenticate:
            # If user is not authenticated
            auth = 'MediaBrowser Client="Kodi", Device="%s", DeviceId="%s", Version="%s"' % (
                deviceName, deviceId, version)
            header = {
                'Content-type': 'application/json',
                'Accept-encoding': 'gzip',
                'Accept-Charset': 'UTF-8,*',
                'Authorization': auth
            }

            self.logMsg("Header: %s" % header, 2)
            return header

        else:
            userId = self.userId
            token = self.token
            # Attached to the requests session
            auth = 'MediaBrowser UserId="%s", Client="Kodi", Device="%s", DeviceId="%s", Version="%s"' % (
                userId, deviceName, deviceId, version)
            header = {
                'Content-type': 'application/json',
                'Accept-encoding': 'gzip',
                'Accept-Charset': 'UTF-8,*',
                'Authorization': auth,
                'X-MediaBrowser-Token': token
            }

            self.logMsg("Header: %s" % header, 2)
            return header

    def downloadUrl(self, url, postBody=None, type="GET", authenticate=True):

        self.logMsg("=== ENTER downloadUrl ===", 2)

        WINDOW = self.WINDOW
        timeout = self.timeout
        default_link = ""

        try:

            # If user is authenticated
            if (authenticate):
                # Get requests session
                try:
                    s = self.s
                    # Replace for the real values and append api_key
                    url = url.replace("{server}", self.server, 1)
                    url = url.replace("{UserId}", self.userId, 1)

                    self.logMsg("URL: %s" % url, 2)
                    # Prepare request
                    if type == "GET":
                        r = s.get(url, json=postBody, timeout=timeout)
                    elif type == "POST":
                        r = s.post(url, json=postBody, timeout=timeout)
                    elif type == "DELETE":
                        r = s.delete(url, json=postBody, timeout=timeout)

                except AttributeError:

                    # Get user information
                    self.username = WINDOW.getProperty('currUser')
                    self.userId = WINDOW.getProperty('userId%s' %
                                                     self.username)
                    self.server = WINDOW.getProperty('server%s' %
                                                     self.username)
                    self.token = WINDOW.getProperty('accessToken%s' %
                                                    self.username)
                    header = self.getHeader()
                    verifyssl = False
                    cert = None

                    # IF user enables ssl verification
                    try:
                        if utils.settings('sslverify') == "true":
                            verifyssl = True
                        if utils.settings('sslcert') != "None":
                            cert = utils.settings('sslcert')
                    except:
                        self.logMsg("Could not load SSL settings.", 1)
                        pass

                    # Replace for the real values and append api_key
                    url = url.replace("{server}", self.server, 1)
                    url = url.replace("{UserId}", self.userId, 1)

                    self.logMsg("URL: %s" % url, 2)
                    # Prepare request
                    if type == "GET":
                        r = requests.get(url,
                                         json=postBody,
                                         headers=header,
                                         timeout=timeout,
                                         cert=cert,
                                         verify=verifyssl)
                    elif type == "POST":
                        r = requests.post(url,
                                          json=postBody,
                                          headers=header,
                                          timeout=timeout,
                                          cert=cert,
                                          verify=verifyssl)
                    elif type == "DELETE":
                        r = requests.delete(url,
                                            json=postBody,
                                            headers=header,
                                            timeout=timeout,
                                            cert=cert,
                                            verify=verifyssl)

            # If user is not authenticated
            elif not authenticate:

                self.logMsg("URL: %s" % url, 2)
                header = self.getHeader(authenticate=False)
                verifyssl = False

                # If user enables ssl verification
                try:
                    verifyssl = self.sslverify
                except AttributeError:
                    pass

                # Prepare request
                if type == "GET":
                    r = requests.get(url,
                                     json=postBody,
                                     headers=header,
                                     timeout=timeout,
                                     verify=verifyssl)
                elif type == "POST":
                    r = requests.post(url,
                                      json=postBody,
                                      headers=header,
                                      timeout=timeout,
                                      verify=verifyssl)

            # Process the response
            if r.status_code == 204:
                # No body in the response
                self.logMsg("====== 204 Success ======", 2)
                return default_link

            elif r.status_code == requests.codes.ok:
                try:
                    # UTF-8 - JSON object
                    r = r.json()
                    self.logMsg("====== 200 Success ======", 2)
                    self.logMsg("Response: %s" % r, 2)
                    return r
                except:
                    if r.headers['content-type'] == "text/html":
                        pass
                    else:
                        self.logMsg(
                            "Unable to convert the response for: %s" % url, 1)
            else:
                r.raise_for_status()

            return default_link

        # TO REVIEW EXCEPTIONS
        except requests.exceptions.ConnectionError as e:
            # Make the addon aware of status
            if WINDOW.getProperty("Server_online") != "false":
                self.logMsg("Server unreachable at: %s" % url, 0)
                self.logMsg(e, 2)
                WINDOW.setProperty("Server_online", "false")
            pass

        except requests.exceptions.ConnectTimeout as e:
            self.logMsg("Server timeout at: %s" % url, 0)
            self.logMsg(e, 1)

        except requests.exceptions.HTTPError as e:

            if r.status_code == 401:
                # Unauthorized
                status = WINDOW.getProperty("Server_status")

                if 'x-application-error-code' in r.headers:
                    if r.headers[
                            'X-Application-Error-Code'] == "ParentalControl":
                        # Parental control - access restricted
                        WINDOW.setProperty("Server_status", "restricted")
                        xbmcgui.Dialog().notification(
                            "Emby server",
                            "Access restricted.",
                            xbmcgui.NOTIFICATION_ERROR,
                            time=5000)
                        return False
                    elif r.headers[
                            'X-Application-Error-Code'] == "UnauthorizedAccessException":
                        # User tried to do something his emby account doesn't allow - admin restricted in some way
                        pass

                elif (status == "401") or (status == "Auth"):
                    pass

                else:
                    # Tell UserClient token has been revoked.
                    WINDOW.setProperty("Server_status", "401")
                    self.logMsg("HTTP Error: %s" % e, 0)
                    xbmcgui.Dialog().notification("Error connecting",
                                                  "Unauthorized.",
                                                  xbmcgui.NOTIFICATION_ERROR)
                    return 401

            elif (r.status_code == 301) or (r.status_code == 302):
                # Redirects
                pass
            elif r.status_code == 400:
                # Bad requests
                pass

        except requests.exceptions.SSLError as e:
            self.logMsg("Invalid SSL certificate for: %s" % url, 0)
            self.logMsg(e, 1)

        except requests.exceptions.RequestException as e:
            self.logMsg("Unknown error connecting to: %s" % url, 0)
            self.logMsg(e, 1)

        return default_link
示例#25
0
def addUser():

    doUtils = DownloadUtils()
    clientInfo = ClientInformation()
    currUser = WINDOW.getProperty("currUser")
    deviceId = clientInfo.getMachineId()
    deviceName = clientInfo.getDeviceName()

    # Get session
    url = "{server}/mediabrowser/Sessions?DeviceId=%s" % deviceId
    result = doUtils.downloadUrl(url)
    
    try:
        sessionId = result[0][u'Id']
        additionalUsers = result[0][u'AdditionalUsers']
        # Add user to session
        userlist = {}
        users = []
        url = "{server}/mediabrowser/Users?IsDisabled=false&IsHidden=false"
        result = doUtils.downloadUrl(url)

        # pull the list of users
        for user in result:
            name = user[u'Name']
            userId = user[u'Id']
            if currUser not in name:
                userlist[name] = userId
                users.append(name)

        # Display dialog if there's additional users
        if additionalUsers:

            option = xbmcgui.Dialog().select("Add/Remove user from the session", ["Add user", "Remove user"])
            # Users currently in the session
            additionalUserlist = {}
            additionalUsername = []
            # Users currently in the session
            for user in additionalUsers:
                name = user[u'UserName']
                userId = user[u'UserId']
                additionalUserlist[name] = userId
                additionalUsername.append(name)

            if option == 1:
                # User selected Remove user
                resp = xbmcgui.Dialog().select("Remove user from the session", additionalUsername)
                if resp > -1:
                    selected = additionalUsername[resp]
                    selected_userId = additionalUserlist[selected]
                    url = "{server}/mediabrowser/Sessions/%s/Users/%s" % (sessionId, selected_userId)
                    postdata = {}
                    doUtils.downloadUrl(url, postBody=postdata, type="DELETE")
                    xbmcgui.Dialog().notification("Success!", "%s removed from viewing session" % selected, time=1000)

                    # clear picture
                    position = WINDOW.getProperty('EmbyAdditionalUserPosition.' + selected_userId)
                    WINDOW.clearProperty('EmbyAdditionalUserImage.' + str(position))
                    return
                else:
                    return

            elif option == 0:
                # User selected Add user
                for adduser in additionalUsername:
                    try: # Remove from selected already added users. It is possible they are hidden.
                        users.remove(adduser)
                    except: pass

            elif option < 0:
                # User cancelled
                return

        # Subtract any additional users
        xbmc.log("Displaying list of users: %s" % users)
        resp = xbmcgui.Dialog().select("Add user to the session", users)
        # post additional user
        if resp > -1:
            selected = users[resp]
            selected_userId = userlist[selected]
            url = "{server}/mediabrowser/Sessions/%s/Users/%s" % (sessionId, selected_userId)
            postdata = {}
            doUtils.downloadUrl(url, postBody=postdata, type="POST")
            xbmcgui.Dialog().notification("Success!", "%s added to viewing session" % selected, time=1000)

    except:
        xbmc.log("Failed to add user to session.")
        xbmcgui.Dialog().notification("Error", "Unable to add/remove user from the session.", xbmcgui.NOTIFICATION_ERROR)

    try:
        # Add additional user images
        #always clear the individual items first
        totalNodes = 10
        for i in range(totalNodes):
            if not WINDOW.getProperty('EmbyAdditionalUserImage.' + str(i)):
                break
            WINDOW.clearProperty('EmbyAdditionalUserImage.' + str(i))

        url = "{server}/mediabrowser/Sessions?DeviceId=%s" % deviceId
        result = doUtils.downloadUrl(url)
        additionalUsers = result[0][u'AdditionalUsers']
        count = 0
        for additionaluser in additionalUsers:
            url = "{server}/mediabrowser/Users/%s?format=json" % (additionaluser[u'UserId'])
            result = doUtils.downloadUrl(url)
            WINDOW.setProperty("EmbyAdditionalUserImage." + str(count),API().getUserArtwork(result,"Primary"))
            WINDOW.setProperty("EmbyAdditionalUserPosition." + str(additionaluser[u'UserId']),str(count))
            count +=1
    except:
        pass
示例#26
0
class PlaybackUtils():
    
    clientInfo = ClientInformation()
    doUtils = DownloadUtils()
    api = API()

    addon = xbmcaddon.Addon()
    language = addon.getLocalizedString
    addonName = clientInfo.getAddonName()

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

    def PLAY(self, result, setup = "service"):

        self.logMsg("PLAY Called", 1)

        api = self.api
        doUtils = self.doUtils
        username = utils.window('currUser')
        server = utils.window('server%s' % username)

        id = result['Id']
        userdata = result['UserData']
        # Get the playurl - direct play, direct stream or transcoding
        playurl = PlayUtils().getPlayUrl(server, id, result)
        listItem = xbmcgui.ListItem()

        if utils.window('playurlFalse') == "true":
            # Playurl failed - set in PlayUtils.py
            utils.window('playurlFalse', clear=True)
            self.logMsg("Failed to retrieve the playback path/url or dialog was cancelled.", 1)
            return xbmcplugin.setResolvedUrl(int(sys.argv[1]), False, listItem)

        ############### RESUME POINT ################
        
        # Resume point for widget only
        timeInfo = api.getTimeInfo(result)
        jumpBackSec = int(utils.settings('resumeJumpBack'))
        seekTime = round(float(timeInfo.get('ResumeTime')), 6)
        if seekTime > jumpBackSec:
            # To avoid negative bookmark
            seekTime = seekTime - jumpBackSec

        # Show the additional resume dialog if launched from a widget
        if xbmc.getCondVisibility('Window.IsActive(home)') and seekTime:
            # Dialog presentation
            displayTime = str(datetime.timedelta(seconds=(int(seekTime))))
            display_list = ["%s %s" % (self.language(30106), displayTime), self.language(30107)]
            resume_result = xbmcgui.Dialog().select(self.language(30105), display_list)

            if resume_result == 0:
                # User selected to resume, append resume point to listitem
                listItem.setProperty('StartOffset', str(seekTime))
            
            elif resume_result > 0:
                # User selected to start from beginning
                seekTime = 0

            else: # User cancelled the dialog
                self.logMsg("User cancelled resume dialog.", 1)
                return xbmcplugin.setResolvedUrl(int(sys.argv[1]), False, listItem)

        ############### ORGANIZE CURRENT PLAYLIST ################

        # In order, intros, original item requested and any additional part
        playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO)
        startPos = max(playlist.getposition(), 0) # Can return -1
        sizePlaylist = playlist.size()
        currentPosition = startPos

        self.logMsg("Playlist start position: %s" % startPos, 2)
        self.logMsg("Playlist current position: %s" % currentPosition, 2)
        self.logMsg("Playlist size: %s" % sizePlaylist, 2)
        
        # Properties to ensure we have have proper playlists with additional items.
        introsPlaylist = False
        introProperty = utils.window('PlaylistIntroSet') == "true"
        dummyProperty = utils.window('PlaylistsetDummy') == "true"
        additionalProperty = utils.window('PlaylistAdditional') == "true"

        ############### -- CHECK FOR INTROS ################

        if utils.settings('disableCinema') == "false" and not introProperty and not seekTime:
            # if we have any play them when the movie/show is not being resumed
            url = "{server}/mediabrowser/Users/{UserId}/Items/%s/Intros?format=json&ImageTypeLimit=1&Fields=Etag" % id    
            
            intros = doUtils.downloadUrl(url)
            if intros['TotalRecordCount'] != 0:
                # The server randomly returns one custom intro
                intro = intros['Items'][0]
                introId = intro['Id']
                introListItem = xbmcgui.ListItem()
                introPlayurl = PlayUtils().getPlayUrl(server, introId, intro)

                self.logMsg("Intro play: %s" % introPlayurl, 1)

                self.setProperties(introPlayurl, intro, introListItem)
                self.setListItemProps(server, introId, introListItem, intro)
                
                introsPlaylist = True
                utils.window('PlaylistIntroSet', value="true")
                playlist.add(introPlayurl, introListItem, index=currentPosition)
                currentPosition += 1
        
        elif introProperty:
            # Play main item, do not play the intro since we already played it. Reset property for next time.
            utils.window('PlaylistIntroSet', clear=True)
            self.logMsg("Clear intro property.", 2)

        ############### -- SETUP MAIN ITEM ################
        
        ##### Set listitem and properties for main item
        self.logMsg("Returned playurl: %s" % playurl, 1)
        listItem.setPath(playurl)
        self.setProperties(playurl, result, listItem)

        mainArt = API().getArtwork(result, "Primary")
        listItem.setThumbnailImage(mainArt)
        listItem.setIconImage(mainArt)

        if introsPlaylist and not sizePlaylist:
            # Extend our current playlist with the actual item to play only if there's no playlist first
            self.logMsg("No playlist detected at the start. Creating playlist with intro and play item.", 1)
            self.logMsg("Playlist current position: %s" % (currentPosition), 1)
            playlist.add(playurl, listItem, index=currentPosition)
            currentPosition += 1

        ############### -- CHECK FOR ADDITIONAL PARTS ################

        if result.get('PartCount') and not additionalProperty:
            # Only add to the playlist after intros have played
            url = "{server}/mediabrowser/Videos/%s/AdditionalParts" % id
            
            parts = doUtils.downloadUrl(url)
            for part in parts['Items']:
                partId = part['Id']
                additionalPlayurl = PlayUtils().getPlayUrl(server, partId, part)
                additionalListItem = xbmcgui.ListItem()

                # Set listitem and properties for each additional parts
                self.logMsg("Adding to playlist: %s position: %s" % (additionalPlayurl, currentPosition), 1)
                self.setProperties(additionalPlayurl, part, additionalListItem)
                self.setListItemProps(server, partId, additionalListItem, part)

                # Add item to playlist, after the main item
                utils.window('PlaylistAdditional', value="true")
                playlist.add(additionalPlayurl, additionalListItem, index=currentPosition+1)
                currentPosition += 1
        
        elif additionalProperty:
            # Additional parts are already set, reset property for next time
            utils.window('PlaylistAdditional', clear=True)
            self.logMsg("Clear additional property", 2)

        ############### PLAYBACK ################

        if setup == "service" or xbmc.getCondVisibility('Window.IsActive(home)'):
            # Sent via websocketclient.py or default.py but via widgets
            self.logMsg("Detecting playback happening via service.py or home menu.", 1)
            self.setListItemProps(server, id, listItem, result)

            playlistPlayer = False

            if introsPlaylist and not sizePlaylist:
                # Extend our current playlist with the actual item to play only if there's no playlist first
                playlistPlayer = True

            elif sizePlaylist > 0 and not dummyProperty:
                # Playlist will fail on the current position. Adding dummy url
                playlist.add(playurl, index=startPos)
                self.logMsg("Adding dummy path as replacement for position: %s" % startPos, 2)
                utils.window('PlaylistsetDummy', value="true")
                playlistPlayer = True

            elif dummyProperty:
                # Already failed, play the item as a single item
                utils.window('PlaylistsetDummy', clear=True)
                self.logMsg("Clear dummy property.", 2)


            if playlistPlayer:
                self.logMsg("Processed as a playlist.", 1)
                return xbmc.Player().play(playlist)
            else:
                self.logMsg("Processed as a single item.", 1)
                return xbmc.Player().play(playurl, listItem)

        elif setup == "default":
            self.logMsg("Detecting playback happening via default.py.", 1)
            playlistPlayer = False

            if sizePlaylist > 0 and not dummyProperty:
                # Playlist will fail on the current position. Adding dummy url
                playlist.add(playurl, index=startPos)
                self.logMsg("Adding dummy path as replacement for position: %s" % startPos, 2)
                utils.window('PlaylistsetDummy', value="true")
                playlistPlayer = True

            elif dummyProperty:
                # Already failed, play the item as a single item
                utils.window('PlaylistsetDummy', clear=True)
                self.logMsg("Clear dummy property.", 2)

            
            if playlistPlayer:
                self.logMsg("Processed as a playlist.", 1)
                return xbmc.Player().play(playlist, startpos=startPos)
            else: # Sent via default.py
                self.logMsg("Processed as a single item.", 1)
                return xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, listItem)


    def externalSubs(self, id, playurl, mediaSources):

        username = utils.window('currUser')
        server = utils.window('server%s' % username)
        externalsubs = []
        mapping = {}

        mediaStream = mediaSources[0].get('MediaStreams')
        kodiindex = 0
        for stream in mediaStream:
            
            index = stream['Index']
            # Since Emby returns all possible tracks together, have to pull only external subtitles.
            # IsTextSubtitleStream if true, is available to download from emby.
            if "Subtitle" in stream['Type'] and stream['IsExternal'] and stream['IsTextSubtitleStream']:
                
                playmethod = utils.window("%splaymethod" % playurl)

                if "DirectPlay" in playmethod:
                    # Direct play, get direct path
                    url = PlayUtils().directPlay(stream)
                elif "DirectStream" in playmethod: # Direct stream
                    url = "%s/Videos/%s/%s/Subtitles/%s/Stream.srt" % (server, id, id, index)
                
                # map external subtitles for mapping
                mapping[kodiindex] = index
                externalsubs.append(url)
                kodiindex += 1
        
        mapping = json.dumps(mapping)
        utils.window('%sIndexMapping' % playurl, value=mapping)

        return externalsubs

    def setProperties(self, playurl, result, listItem):
        # Set runtimeticks, type, refresh_id and item_id
        id = result.get('Id')
        type = result.get('Type', "")

        utils.window("%sruntimeticks" % playurl, value=str(result.get('RunTimeTicks')))
        utils.window("%stype" % playurl, value=type)
        utils.window("%sitem_id" % playurl, value=id)

        if type == "Episode":
            utils.window("%srefresh_id" % playurl, value=result.get('SeriesId'))
        else:
            utils.window("%srefresh_id" % playurl, value=id)

        if utils.window("%splaymethod" % playurl) != "Transcode":
            # Only for direct play and direct stream
            # Append external subtitles to stream
            subtitleList = self.externalSubs(id, playurl, result['MediaSources'])
            listItem.setSubtitles(subtitleList)

    def setArt(self, list, name, path):
        
        if name in {"thumb", "fanart_image", "small_poster", "tiny_poster", "medium_landscape", "medium_poster", "small_fanartimage", "medium_fanartimage", "fanart_noindicators"}:
            list.setProperty(name, path)
        else:
            list.setArt({name:path})
        
        return list
    
    def setListItemProps(self, server, id, listItem, result):
        # Set up item and item info
        api = self.api

        type = result.get('Type')
        people = api.getPeople(result)
        studios = api.getStudios(result)

        metadata = {
            
            'title': result.get('Name', "Missing name"),
            'year': result.get('ProductionYear'),
            'plot': api.getOverview(result),
            'director': people.get('Director'),
            'writer': people.get('Writer'),
            'mpaa': api.getMpaa(result),
            'genre': api.getGenre(result),
            'studio': " / ".join(studios),
            'aired': api.getPremiereDate(result),
            'rating': result.get('CommunityRating'),
            'votes': result.get('VoteCount')
        }

        if "Episode" in type:
            # Only for tv shows
            thumbId = result.get('SeriesId')
            season = result.get('ParentIndexNumber', -1)
            episode = result.get('IndexNumber', -1)
            show = result.get('SeriesName', "")

            metadata['TVShowTitle'] = show
            metadata['season'] = season
            metadata['episode'] = episode

        listItem.setProperty('IsPlayable', 'true')
        listItem.setProperty('IsFolder', 'false')
        listItem.setInfo('video', infoLabels=metadata)

        # Set artwork for listitem
        self.setArt(listItem,'poster', API().getArtwork(result, "Primary"))
        self.setArt(listItem,'tvshow.poster', API().getArtwork(result, "SeriesPrimary"))
        self.setArt(listItem,'clearart', API().getArtwork(result, "Art"))
        self.setArt(listItem,'tvshow.clearart', API().getArtwork(result, "Art"))
        self.setArt(listItem,'clearlogo', API().getArtwork(result, "Logo"))
        self.setArt(listItem,'tvshow.clearlogo', API().getArtwork(result, "Logo"))
        self.setArt(listItem,'discart', API().getArtwork(result, "Disc"))
        self.setArt(listItem,'fanart_image', API().getArtwork(result, "Backdrop"))
        self.setArt(listItem,'landscape', API().getArtwork(result, "Thumb"))
    
    def seekToPosition(self, seekTo):
        # Set a loop to wait for positive confirmation of playback
        count = 0
        while not xbmc.Player().isPlaying():
            count += 1
            if count >= 10:
                return
            else:
                xbmc.sleep(500)
            
        # Jump to seek position
        count = 0
        while xbmc.Player().getTime() < (seekToTime - 5) and count < 11: # only try 10 times
            count += 1
            xbmc.Player().seekTime(seekTo)
            xbmc.sleep(100)
    
    def PLAYAllItems(self, items, startPositionTicks):
        
        self.logMsg("== ENTER: PLAYAllItems ==")
        self.logMsg("Items: %s" % items)

        doUtils = self.doUtils

        playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO)
        playlist.clear()
        started = False

        for itemId in items:
            self.logMsg("Adding Item to playlist: %s" % itemId, 1)
            url = "{server}/mediabrowser/Users/{UserId}/Items/%s?format=json" % itemId
            result = doUtils.downloadUrl(url)

            addition = self.addPlaylistItem(playlist, result)
            if not started and addition:
                started = True
                self.logMsg("Starting Playback Pre", 1)
                xbmc.Player().play(playlist)

        if not started:
            self.logMsg("Starting Playback Post", 1)
            xbmc.Player().play(playlist)

        # Seek to position
        if startPositionTicks:
            seekTime = startPositionTicks / 10000000.0
            self.seekToPosition(seekTime)
    
    def AddToPlaylist(self, itemIds):

        self.logMsg("== ENTER: PLAYAllItems ==")
        
        doUtils = self.doUtils
        playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO)

        for itemId in itemIds:
            self.logMsg("Adding Item to Playlist: %s" % itemId)
            url = "{server}/mediabrowser/Users/{UserId}/Items/%s?format=json" % itemId
            result = doUtils.downloadUrl(url)

            self.addPlaylistItem(playlist, result)
        
        return playlist
    
    def addPlaylistItem(self, playlist, item):

        id = item['Id']
        username = utils.window('currUser')
        server = utils.window('server%s' % username)

        playurl = PlayUtils().getPlayUrl(server, id, item)
        
        if utils.window('playurlFalse') == "true":
            # Playurl failed - set in PlayUtils.py
            utils.window('playurlFalse', clear=True)
            self.logMsg("Failed to retrieve the playback path/url or dialog was cancelled.", 1)
            return

        self.logMsg("Playurl: %s" % playurl)

        thumb = API().getArtwork(item, "Primary")
        listItem = xbmcgui.ListItem(path=playurl, iconImage=thumb, thumbnailImage=thumb)
        self.setListItemProps(server, id, listItem, item)
        self.setProperties(playurl, item)

        playlist.add(playurl, listItem)

    # Not currently being used
    '''def PLAYAllEpisodes(self, items):
示例#27
0
import xbmc
import xbmcgui
import xbmcaddon

import json
import threading
from datetime import datetime
from DownloadUtils import DownloadUtils
from ClientInformation import ClientInformation
import urllib
import sys
import os

#define our global download utils
downloadUtils = DownloadUtils()
clientInfo = ClientInformation()


###########################################################################
class PlayUtils():
    def getPlayUrl(self, server, id, result):

        addonSettings = xbmcaddon.Addon(id='plugin.video.xbmb3c')
        # if the path is local and depending on the video quality play we can direct play it do so-
        xbmc.log("XBMB3C getPlayUrl")
        if self.fileExists(result) or self.isDirectPlay(result) == True:
            xbmc.log("XBMB3C getPlayUrl -> Direct Play")
            playurl = result.get("Path")
            if playurl != None:
                #We have a path to play so play it
                USER_AGENT = 'QuickTime/7.7.4'
示例#28
0
class Service():
    

    newWebSocketThread = None
    newUserClient = None

    clientInfo = ClientInformation()
    addonName = clientInfo.getAddonName()
    className = None
    
    def __init__(self, *args ):
        self.KodiMonitor = KodiMonitor.Kodi_Monitor()
        addonName = self.addonName

        self.logMsg("Starting Monitor", 0)
        self.logMsg("======== START %s ========" % addonName, 0)
        self.logMsg("KODI Version: %s" % xbmc.getInfoLabel("System.BuildVersion"), 0)
        self.logMsg("%s Version: %s" % (addonName, self.clientInfo.getVersion()), 0)

    def logMsg(self, msg, lvl=1):
        
        self.className = self.__class__.__name__
        utils.logMsg("%s %s" % (self.addonName, self.className), str(msg), int(lvl))
            
    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
            else:
示例#29
0
class Service():

    clientInfo = ClientInformation()
    addonName = clientInfo.getAddonName()
    WINDOW = xbmcgui.Window(10000)

    def __init__(self, *args):
        addonName = self.addonName

        self.logMsg("Starting NextUp Service", 0)
        self.logMsg("======== START %s ========" % addonName, 0)
        self.logMsg(
            "KODI Version: %s" % xbmc.getInfoLabel("System.BuildVersion"), 0)
        self.logMsg(
            "%s Version: %s" % (addonName, self.clientInfo.getVersion()), 0)
        self.logMsg("Platform: %s" % (self.clientInfo.getPlatform()), 0)

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

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

    def ServiceEntryPoint(self):
        lastProgressUpdate = datetime.today()
        player = Player()

        lastFile = None

        while (not xbmc.abortRequested):
            xbmc.sleep(1000)
            if xbmc.Player().isPlaying():
                try:
                    playTime = xbmc.Player().getTime()

                    totalTime = xbmc.Player().getTotalTime()

                    currentFile = xbmc.Player().getPlayingFile()

                    addonSettings = xbmcaddon.Addon(
                        id='service.nextup.notification')
                    notificationtime = addonSettings.getSetting(
                        "autoPlaySeasonTime")
                    nextUpDisabled = addonSettings.getSetting(
                        "disableNextUp") == "true"

                    if xbmcgui.Window(10000).getProperty(
                            "PseudoTVRunning"
                    ) != "True" and not nextUpDisabled:
                        if (totalTime - playTime <= int(notificationtime) and
                            (lastFile == None
                             or lastFile != currentFile)) and totalTime != 0:
                            lastFile = currentFile
                            self.logMsg(
                                "Calling autoplayback totaltime - playtime is %s"
                                % (totalTime - playTime), 2)
                            player.autoPlayPlayback()
                            self.logMsg("Netflix style autoplay succeeded.", 2)

                    xbmc.sleep(1000)

                except Exception, e:
                    self.logMsg("Exception in Playback Monitor Service: %s" %
                                e)
                    pass
            else:
                xbmc.sleep(5000)

        self.logMsg("======== STOP %s ========" % self.addonName, 0)
示例#30
0
class Player(xbmc.Player):
    # Borg - multiple instances, shared state
    _shared_state = {}

    xbmcplayer = xbmc.Player()
    clientInfo = ClientInformation()

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

    logLevel = 0
    currenttvshowid = None
    currentepisodeid = None
    playedinarow = 1
    fields_base = '"dateadded", "file", "lastplayed","plot", "title", "art", "playcount",'
    fields_file = fields_base + '"streamdetails", "director", "resume", "runtime",'
    fields_tvshows = fields_base + '"sorttitle", "mpaa", "premiered", "year", "episode", "watchedepisodes", "votes", "rating", "studio", "season", "genre", "episodeguide", "tag", "originaltitle", "imdbnumber"'
    fields_episodes = fields_file + '"cast", "productioncode", "rating", "votes", "episode", "showtitle", "tvshowid", "season", "firstaired", "writer", "originaltitle"'
    postplaywindow = None

    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 json_query(self, query, ret):
        try:
            xbmc_request = json.dumps(query)
            result = xbmc.executeJSONRPC(xbmc_request)
            result = unicode(result, 'utf-8', errors='ignore')
            if ret:
                return json.loads(result)['result']

            else:
                return json.loads(result)
        except:
            xbmc_request = json.dumps(query)
            result = xbmc.executeJSONRPC(xbmc_request)
            result = unicode(result, 'utf-8', errors='ignore')
            self.logMsg(json.loads(result), 1)
            return json.loads(result)

    def getNowPlaying(self):
        # Get the active player
        result = xbmc.executeJSONRPC(
            '{"jsonrpc": "2.0", "id": 1, "method": "Player.GetActivePlayers"}')
        result = unicode(result, 'utf-8', errors='ignore')
        self.logMsg("Got active player " + result, 2)
        result = json.loads(result)

        # Seems to work too fast loop whilst waiting for it to become active
        while not result["result"]:
            result = xbmc.executeJSONRPC(
                '{"jsonrpc": "2.0", "id": 1, "method": "Player.GetActivePlayers"}'
            )
            result = unicode(result, 'utf-8', errors='ignore')
            self.logMsg("Got active player " + result, 2)
            result = json.loads(result)

        if 'result' in result and result["result"][0] is not None:
            playerid = result["result"][0]["playerid"]

            # Get details of the playing media
            self.logMsg("Getting details of now  playing media", 1)
            result = xbmc.executeJSONRPC(
                '{"jsonrpc": "2.0", "id": 1, "method": "Player.GetItem", "params": {"playerid": '
                + str(playerid) +
                ', "properties": ["showtitle", "tvshowid", "episode", "season", "playcount","genre"] } }'
            )
            result = unicode(result, 'utf-8', errors='ignore')
            self.logMsg("Got details of now playing media" + result, 2)

            result = json.loads(result)
            return result

    def onPlayBackStarted(self):
        # Will be called when xbmc starts playing a file
        addon = xbmcaddon.Addon(id='service.nextup.notification')
        self.postplaywindow = None
        WINDOW = xbmcgui.Window(10000)
        WINDOW.clearProperty("NextUpNotification.NowPlaying.DBID")
        WINDOW.clearProperty("NextUpNotification.NowPlaying.Type")
        # Get the active player
        result = self.getNowPlaying()
        if 'result' in result:
            itemtype = result["result"]["item"]["type"]
            if itemtype == "episode":
                itemtitle = result["result"]["item"]["showtitle"].encode(
                    'utf-8')
                itemtitle = utils.unicodetoascii(itemtitle)
                WINDOW.setProperty("NextUpNotification.NowPlaying.Type",
                                   itemtype)
                tvshowid = result["result"]["item"]["tvshowid"]
                WINDOW.setProperty("NextUpNotification.NowPlaying.DBID",
                                   str(tvshowid))
                if int(tvshowid) == -1:
                    tvshowid = self.showtitle_to_id(title=itemtitle)
                    self.logMsg("Fetched missing tvshowid " + str(tvshowid), 2)
                    WINDOW.setProperty("NextUpNotification.NowPlaying.DBID",
                                       str(tvshowid))
            elif itemtype == "movie":
                WINDOW.setProperty("NextUpNotification.NowPlaying.Type",
                                   itemtype)
                id = result["result"]["item"]["id"]
                WINDOW.setProperty("NextUpNotification.NowPlaying.DBID",
                                   str(id))

    def showtitle_to_id(self, title):
        query = {
            "jsonrpc": "2.0",
            "method": "VideoLibrary.GetTVShows",
            "params": {
                "properties": ["title"]
            },
            "id": "libTvShows"
        }
        try:
            json_result = json.loads(
                xbmc.executeJSONRPC(json.dumps(query, encoding='utf-8')))
            if 'result' in json_result and 'tvshows' in json_result['result']:
                json_result = json_result['result']['tvshows']
                for tvshow in json_result:
                    if tvshow['label'] == title:
                        return tvshow['tvshowid']
            return '-1'
        except Exception:
            return '-1'

    def get_episode_id(self, showid, showseason, showepisode):
        showseason = int(showseason)
        showepisode = int(showepisode)
        episodeid = 0
        query = {
            "jsonrpc": "2.0",
            "method": "VideoLibrary.GetEpisodes",
            "params": {
                "properties": ["season", "episode"],
                "tvshowid": int(showid)
            },
            "id": "1"
        }
        try:
            json_result = json.loads(
                xbmc.executeJSONRPC(json.dumps(query, encoding='utf-8')))
            if 'result' in json_result and 'episodes' in json_result['result']:
                json_result = json_result['result']['episodes']
                for episode in json_result:
                    if episode['season'] == showseason and episode[
                            'episode'] == showepisode:
                        if 'episodeid' in episode:
                            episodeid = episode['episodeid']
            return episodeid
        except Exception:
            return episodeid

    def onPlayBackEnded(self):
        self.logMsg("playback ended ", 2)
        if self.postplaywindow is not None:
            self.showPostPlay()

    def findNextEpisode(self, result, currentFile, includeWatched):
        self.logMsg("Find next episode called", 1)
        position = 0
        for episode in result["result"]["episodes"]:
            # find position of current episode
            if self.currentepisodeid == episode["episodeid"]:
                # found a match so add 1 for the next and get out of here
                position += 1
                break
            position += 1
        # check if it may be a multi-part episode
        while result["result"]["episodes"][position]["file"] == currentFile:
            position += 1
        # skip already watched episodes?
        while not includeWatched and result["result"]["episodes"][position][
                "playcount"] > 1:
            position += 1

        # now return the episode
        self.logMsg(
            "Find next episode found next episode in position: " +
            str(position), 1)
        try:
            episode = result["result"]["episodes"][position]
        except:
            # no next episode found
            episode = None

        return episode

    def findCurrentEpisode(self, result, currentFile):
        self.logMsg("Find current episode called", 1)
        position = 0
        for episode in result["result"]["episodes"]:
            # find position of current episode
            if self.currentepisodeid == episode["episodeid"]:
                # found a match so get out of here
                break
            position += 1

        # now return the episode
        self.logMsg(
            "Find current episode found episode in position: " + str(position),
            1)
        try:
            episode = result["result"]["episodes"][position]
        except:
            # no next episode found
            episode = None

        return episode

    def displayRandomUnwatched(self):
        # Get the active player
        result = self.getNowPlaying()
        if 'result' in result:
            itemtype = result["result"]["item"]["type"]
            if itemtype == "episode":
                # playing an episode so find a random unwatched show from the same genre
                genres = result["result"]["item"]["genre"]
                if genres:
                    genretitle = genres[0]
                    self.logMsg("Looking up tvshow for genre " + genretitle, 2)
                    tvshow = utils.getJSON(
                        'VideoLibrary.GetTVShows',
                        '{ "sort": { "order": "descending", "method": "random" }, "filter": {"and": [{"operator":"is", "field":"genre", "value":"%s"}, {"operator":"is", "field":"playcount", "value":"0"}]}, "properties": [ %s ],"limits":{"end":1} }'
                        % (genretitle, self.fields_tvshows))
                if not tvshow:
                    self.logMsg("Looking up tvshow without genre", 2)
                    tvshow = utils.getJSON(
                        'VideoLibrary.GetTVShows',
                        '{ "sort": { "order": "descending", "method": "random" }, "filter": {"and": [{"operator":"is", "field":"playcount", "value":"0"}]}, "properties": [ %s ],"limits":{"end":1} }'
                        % self.fields_tvshows)
                self.logMsg("Got tvshow" + str(tvshow), 2)
                tvshowid = tvshow[0]["tvshowid"]
                if int(tvshowid) == -1:
                    tvshowid = self.showtitle_to_id(title=itemtitle)
                    self.logMsg("Fetched missing tvshowid " + str(tvshowid), 2)
                episode = utils.getJSON(
                    'VideoLibrary.GetEpisodes',
                    '{ "tvshowid": %d, "sort": {"method":"episode"}, "filter": {"and": [ {"field": "playcount", "operator": "lessthan", "value":"1"}, {"field": "season", "operator": "greaterthan", "value": "0"} ]}, "properties": [ %s ], "limits":{"end":1}}'
                    % (tvshowid, self.fields_episodes))

                if episode:
                    self.logMsg(
                        "Got details of next up episode %s" % str(episode), 2)
                    addonSettings = xbmcaddon.Addon(
                        id='service.nextup.notification')
                    unwatchedPage = UnwatchedInfo(
                        "script-nextup-notification-UnwatchedInfo.xml",
                        addonSettings.getAddonInfo('path'), "default", "1080i")
                    unwatchedPage.setItem(episode[0])
                    self.logMsg("Calling display unwatched", 2)
                    unwatchedPage.show()
                    monitor = xbmc.Monitor()
                    monitor.waitForAbort(10)
                    self.logMsg("Calling close unwatched", 2)
                    unwatchedPage.close()
                    del monitor

    def postPlayPlayback(self):
        currentFile = xbmc.Player().getPlayingFile()

        # Get the active player
        result = self.getNowPlaying()
        if 'result' in result:
            itemtype = result["result"]["item"]["type"]
            addonSettings = xbmcaddon.Addon(id='service.nextup.notification')
            playMode = addonSettings.getSetting("autoPlayMode")
            currentepisodenumber = result["result"]["item"]["episode"]
            currentseasonid = result["result"]["item"]["season"]
            currentshowtitle = result["result"]["item"]["showtitle"].encode(
                'utf-8')
            currentshowtitle = utils.unicodetoascii(currentshowtitle)
            tvshowid = result["result"]["item"]["tvshowid"]
            shortplayMode = addonSettings.getSetting("shortPlayMode")
            shortplayNotification = addonSettings.getSetting(
                "shortPlayNotification")
            shortplayLength = int(
                addonSettings.getSetting("shortPlayLength")) * 60

        # Try to get tvshowid by showtitle from kodidb if tvshowid is -1 like in strm streams which are added to kodi db
        if int(tvshowid) == -1:
            tvshowid = self.showtitle_to_id(title=currentshowtitle)
            self.logMsg("Fetched missing tvshowid " + str(tvshowid), 2)

        if (itemtype == "episode"):
            # Get current episodeid
            currentepisodeid = self.get_episode_id(
                showid=str(tvshowid),
                showseason=currentseasonid,
                showepisode=currentepisodenumber)
        else:
            # wtf am i doing here error.. ####
            self.logMsg("Error: cannot determine if episode", 1)
            return

        self.currentepisodeid = currentepisodeid
        self.logMsg(
            "Getting details of next up episode for tvshow id: " +
            str(tvshowid), 1)
        if self.currenttvshowid != tvshowid:
            self.currenttvshowid = tvshowid
            self.playedinarow = 1

        result = xbmc.executeJSONRPC(
            '{"jsonrpc": "2.0", "method": "VideoLibrary.GetEpisodes", "params": {"tvshowid": %d, '
            '"properties": [ "title", "playcount", "season", "episode", "showtitle", "plot", '
            '"file", "rating", "resume", "tvshowid", "art", "firstaired", "runtime", "writer", '
            '"dateadded", "lastplayed" , "streamdetails"], "sort": {"method": "episode"}}, "id": 1}'
            % tvshowid)

        if result:
            result = unicode(result, 'utf-8', errors='ignore')
            result = json.loads(result)
            self.logMsg("Got details of next up episode %s" % str(result), 2)
            xbmc.sleep(100)

            # Find the next unwatched and the newest added episodes
            if "result" in result and "episodes" in result["result"]:
                includeWatched = addonSettings.getSetting(
                    "includeWatched") == "true"
                episode = self.findNextEpisode(result, currentFile,
                                               includeWatched)
                current_episode = self.findCurrentEpisode(result, currentFile)
                self.logMsg("episode details %s" % str(episode), 2)
                episodeid = episode["episodeid"]

                if current_episode:
                    # we have something to show
                    postPlayPage = PostPlayInfo(
                        "script-nextup-notification-PostPlayInfo.xml",
                        addonSettings.getAddonInfo('path'), "default", "1080i")
                    postPlayPage.setItem(episode)
                    postPlayPage.setPreviousItem(current_episode)
                    upnextitems = self.parse_tvshows_recommended(6)
                    postPlayPage.setUpNextList(upnextitems)
                    playedinarownumber = addonSettings.getSetting(
                        "playedInARow")
                    playTime = xbmc.Player().getTime()
                    totalTime = xbmc.Player().getTotalTime()
                    self.logMsg(
                        "played in a row settings %s" %
                        str(playedinarownumber), 2)
                    self.logMsg("played in a row %s" % str(self.playedinarow),
                                2)
                    if int(self.playedinarow) <= int(playedinarownumber):
                        if (shortplayNotification
                                == "false") and (shortplayLength >=
                                                 totalTime) and (shortplayMode
                                                                 == "true"):
                            self.logMsg("hiding notification for short videos")
                        else:
                            postPlayPage.setStillWatching(False)
                    else:
                        if (shortplayNotification
                                == "false") and (shortplayLength >=
                                                 totalTime) and (shortplayMode
                                                                 == "true"):
                            self.logMsg("hiding notification for short videos")
                        else:
                            postPlayPage.setStillWatching(True)

                    self.postplaywindow = postPlayPage

    def showPostPlay(self):
        self.logMsg("showing postplay window")
        p = self.postplaywindow.doModal()
        autoplayed = xbmcgui.Window(10000).getProperty(
            "NextUpNotification.AutoPlayed")
        self.logMsg("showing postplay window completed autoplayed? " +
                    str(autoplayed))
        if autoplayed:
            self.playedinarow += 1
        else:
            self.playedinarow = 1
        del p

    def parse_tvshows_recommended(self, limit):
        items = []
        prefix = "recommended-episodes"
        json_query = LIBRARY._fetch_recommended_episodes()

        if json_query:
            # First unplayed episode of recent played tvshows
            self.logMsg("getting next up tvshows " + json_query, 2)
            json_query = json.loads(json_query)
            if "result" in json_query and 'tvshows' in json_query['result']:
                count = -1
                for item in json_query['result']['tvshows']:
                    if xbmc.abortRequested:
                        break
                    if count == -1:
                        count += 1
                        continue
                    json_query2 = xbmcgui.Window(10000).getProperty(
                        prefix + "-data-" + str(item['tvshowid']))
                    if json_query2:
                        self.logMsg("getting next up episodes " + json_query2,
                                    2)
                        json_query2 = json.loads(json_query2)
                        if "result" in json_query2 and json_query2[
                                'result'] is not None and 'episodes' in json_query2[
                                    'result']:
                            for item2 in json_query2['result']['episodes']:
                                episode = "%.2d" % float(item2['episode'])
                                season = "%.2d" % float(item2['season'])
                                episodeno = "s%se%s" % (season, episode)
                                break
                            plot = item2['plot']
                            episodeid = str(item2['episodeid'])
                            if len(item['studio']) > 0:
                                studio = item['studio'][0]
                            else:
                                studio = ""
                            if "director" in item2:
                                director = " / ".join(item2['director'])
                            if "writer" in item2:
                                writer = " / ".join(item2['writer'])

                            liz = xbmcgui.ListItem(item2['title'])
                            liz.setPath(item2['file'])
                            liz.setProperty('IsPlayable', 'true')
                            liz.setInfo(type="Video",
                                        infoLabels={
                                            "Title": item2['title'],
                                            "Episode": item2['episode'],
                                            "Season": item2['season'],
                                            "Studio": studio,
                                            "Premiered": item2['firstaired'],
                                            "Plot": plot,
                                            "TVshowTitle": item2['showtitle'],
                                            "Rating":
                                            str(float(item2['rating'])),
                                            "MPAA": item['mpaa'],
                                            "Playcount": item2['playcount'],
                                            "Director": director,
                                            "Writer": writer,
                                            "mediatype": "episode"
                                        })
                            liz.setProperty("episodeid", episodeid)
                            liz.setProperty("episodeno", episodeno)
                            liz.setProperty("resumetime",
                                            str(item2['resume']['position']))
                            liz.setProperty("totaltime",
                                            str(item2['resume']['total']))
                            liz.setProperty("type", 'episode')
                            liz.setProperty(
                                "fanart_image",
                                item2['art'].get('tvshow.fanart', ''))
                            liz.setProperty("dbid", str(item2['episodeid']))
                            liz.setArt(item2['art'])
                            liz.setThumbnailImage(item2['art'].get(
                                'thumb', ''))
                            liz.setIconImage('DefaultTVShows.png')
                            hasVideo = False
                            for key, value in item2['streamdetails'].iteritems(
                            ):
                                for stream in value:
                                    if 'video' in key:
                                        hasVideo = True
                                    liz.addStreamInfo(key, stream)

                            # if duration wasnt in the streaminfo try adding the scraped one
                            if not hasVideo:
                                stream = {'duration': item2['runtime']}
                                liz.addStreamInfo("video", stream)

                            items.append(liz)

                            count += 1
                            if count == limit:
                                break
                    if count == limit:
                        break
            del json_query
        self.logMsg("getting next up episodes completed ", 2)
        return items

    def autoPlayPlayback(self):
        currentFile = xbmc.Player().getPlayingFile()

        # Get the active player
        result = self.getNowPlaying()
        if 'result' in result:
            itemtype = result["result"]["item"]["type"]
            addonSettings = xbmcaddon.Addon(id='service.nextup.notification')
            playMode = addonSettings.getSetting("autoPlayMode")
            currentepisodenumber = result["result"]["item"]["episode"]
            currentseasonid = result["result"]["item"]["season"]
            currentshowtitle = result["result"]["item"]["showtitle"].encode(
                'utf-8')
            currentshowtitle = utils.unicodetoascii(currentshowtitle)
            tvshowid = result["result"]["item"]["tvshowid"]
            shortplayMode = addonSettings.getSetting("shortPlayMode")
            shortplayNotification = addonSettings.getSetting(
                "shortPlayNotification")
            shortplayLength = int(
                addonSettings.getSetting("shortPlayLength")) * 60
            showpostplaypreview = addonSettings.getSetting(
                "showPostPlayPreview") == "true"
            showpostplay = addonSettings.getSetting("showPostPlay") == "true"
            shouldshowpostplay = showpostplay and showpostplaypreview

            # Try to get tvshowid by showtitle from kodidb if tvshowid is -1 like in strm streams which are added to kodi db
            if int(tvshowid) == -1:
                tvshowid = self.showtitle_to_id(title=currentshowtitle)
                self.logMsg("Fetched missing tvshowid " + str(tvshowid), 2)

            if (itemtype == "episode"):
                # Get current episodeid
                currentepisodeid = self.get_episode_id(
                    showid=str(tvshowid),
                    showseason=currentseasonid,
                    showepisode=currentepisodenumber)
            else:
                # wtf am i doing here error.. ####
                self.logMsg("Error: cannot determine if episode", 1)
                return

        else:
            # wtf am i doing here error.. ####
            self.logMsg("Error: cannot determine if episode", 1)
            return

        self.currentepisodeid = currentepisodeid
        self.logMsg(
            "Getting details of next up episode for tvshow id: " +
            str(tvshowid), 1)
        if self.currenttvshowid != tvshowid:
            self.currenttvshowid = tvshowid
            self.playedinarow = 1

        result = xbmc.executeJSONRPC(
            '{"jsonrpc": "2.0", "method": "VideoLibrary.GetEpisodes", "params": {"tvshowid": %d, '
            '"properties": [ "title", "playcount", "season", "episode", "showtitle", "plot", '
            '"file", "rating", "resume", "tvshowid", "art", "firstaired", "runtime", "writer", '
            '"dateadded", "lastplayed" , "streamdetails"], "sort": {"method": "episode"}}, "id": 1}'
            % tvshowid)

        if result:
            result = unicode(result, 'utf-8', errors='ignore')
            result = json.loads(result)
            self.logMsg("Got details of next up episode %s" % str(result), 2)
            xbmc.sleep(100)

            # Find the next unwatched and the newest added episodes
            if "result" in result and "episodes" in result["result"]:
                includeWatched = addonSettings.getSetting(
                    "includeWatched") == "true"
                episode = self.findNextEpisode(result, currentFile,
                                               includeWatched)

                if episode is None:
                    # no episode get out of here
                    return
                self.logMsg("episode details %s" % str(episode), 2)
                episodeid = episode["episodeid"]

                if includeWatched:
                    includePlaycount = True
                else:
                    includePlaycount = episode["playcount"] == 0
                if includePlaycount and currentepisodeid != episodeid:
                    # we have a next up episode
                    nextUpPage = NextUpInfo(
                        "script-nextup-notification-NextUpInfo.xml",
                        addonSettings.getAddonInfo('path'), "default", "1080i")
                    nextUpPage.setItem(episode)
                    stillWatchingPage = StillWatchingInfo(
                        "script-nextup-notification-StillWatchingInfo.xml",
                        addonSettings.getAddonInfo('path'), "default", "1080i")
                    stillWatchingPage.setItem(episode)
                    playedinarownumber = addonSettings.getSetting(
                        "playedInARow")
                    playTime = xbmc.Player().getTime()
                    totalTime = xbmc.Player().getTotalTime()
                    self.logMsg(
                        "played in a row settings %s" %
                        str(playedinarownumber), 2)
                    self.logMsg("played in a row %s" % str(self.playedinarow),
                                2)

                    if int(self.playedinarow) <= int(playedinarownumber):
                        self.logMsg(
                            "showing next up page as played in a row is %s" %
                            str(self.playedinarow), 2)
                        if (shortplayNotification
                                == "false") and (shortplayLength >=
                                                 totalTime) and (shortplayMode
                                                                 == "true"):
                            self.logMsg("hiding notification for short videos")
                        else:
                            nextUpPage.show()
                    else:
                        self.logMsg(
                            "showing still watching page as played in a row %s"
                            % str(self.playedinarow), 2)
                        if (shortplayNotification
                                == "false") and (shortplayLength >=
                                                 totalTime) and (shortplayMode
                                                                 == "true"):
                            self.logMsg("hiding notification for short videos")
                        else:
                            stillWatchingPage.show()
                    if shouldshowpostplay:
                        self.postPlayPlayback()

                    while xbmc.Player().isPlaying() and (
                            totalTime - playTime >
                            1) and not nextUpPage.isCancel(
                            ) and not nextUpPage.isWatchNow(
                            ) and not stillWatchingPage.isStillWatching(
                            ) and not stillWatchingPage.isCancel():
                        xbmc.sleep(100)
                        try:
                            playTime = xbmc.Player().getTime()
                            totalTime = xbmc.Player().getTotalTime()
                        except:
                            pass
                    if shortplayLength >= totalTime and shortplayMode == "true":
                        #play short video and don't add to playcount
                        self.playedinarow += 0
                        self.logMsg("Continuing short video autoplay - %s")
                        if nextUpPage.isWatchNow(
                        ) or stillWatchingPage.isStillWatching():
                            self.playedinarow = 1
                        shouldPlayDefault = not nextUpPage.isCancel()
                    else:
                        if int(self.playedinarow) <= int(playedinarownumber):
                            nextUpPage.close()
                            shouldPlayDefault = not nextUpPage.isCancel()
                            shouldPlayNonDefault = nextUpPage.isWatchNow()
                        else:
                            stillWatchingPage.close()
                            shouldPlayDefault = stillWatchingPage.isStillWatching(
                            )
                            shouldPlayNonDefault = stillWatchingPage.isStillWatching(
                            )

                        if nextUpPage.isWatchNow(
                        ) or stillWatchingPage.isStillWatching():
                            self.playedinarow = 1
                        else:
                            self.playedinarow += 1

                    if (shouldPlayDefault and not shouldshowpostplay
                            and playMode == "0") or (
                                shouldPlayNonDefault and shouldshowpostplay
                                and playMode == "0") or (shouldPlayNonDefault
                                                         and playMode == "1"):
                        self.logMsg(
                            "playing media episode id %s" % str(episodeid), 2)
                        # Signal to trakt previous episode watched
                        AddonSignals.sendSignal(
                            "NEXTUPWATCHEDSIGNAL",
                            {'episodeid': self.currentepisodeid})

                        # if in postplaypreview mode clear the post play window as its not needed now
                        if shouldshowpostplay:
                            self.postplaywindow = None

                        # Play media
                        xbmc.executeJSONRPC(
                            '{ "jsonrpc": "2.0", "id": 0, "method": "Player.Open", '
                            '"params": { "item": {"episodeid": ' +
                            str(episode["episodeid"]) + '} } }')
示例#31
0
    def stopAll(self):

        if(len(self.played_information) == 0):
            return 
            
        addonSettings = xbmcaddon.Addon(id='plugin.video.emby')
        self.printDebug("emby Service -> played_information : " + str(self.played_information))
        
        for item_url in self.played_information:
            data = self.played_information.get(item_url)
            
            if(data != None):
                self.printDebug("emby Service -> item_url  : " + item_url)
                self.printDebug("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.printDebug("emby Service -> runtimeticks:" + str(runtimeTicks))
                    percentComplete = (currentPosition * 10000000) / runtimeTicks
                    markPlayedAt = float(90) / 100    

                    self.printDebug("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,type)
                    
                # if its an episode see if autoplay is enabled
                if addonSettings.getSetting("autoPlaySeason")=="true" and type=="Episode":
                    port = addonSettings.getSetting('port')
                    host = addonSettings.getSetting('ipaddress')
                    server = host + ":" + port
                    userid = self.downloadUtils.getUserId()
                    # add remaining unplayed episodes if applicable
                    MB3Episode = ReadEmbyDB().getItem(item_id)
                    userData = MB3Episode["UserData"]
                    if userData!=None and userData["Played"]==True:
                        
                        pDialog = xbmcgui.DialogProgress()
                        pDialog.create("Auto Play","Further Episode(s) in "+MB3Episode["SeasonName"]+" for "+MB3Episode["SeriesName"]+ " found","Cancel to stop automatic play of remaining episodes")
                        count = 0
                        while(pDialog.iscanceled==False or count < 10):
                            xbmc.sleep(1000)
                            count += 1
                            progress = count * 10
                            remainingsecs = 10 - count
                            pDialog.update(progress,"Further Episode(s) in "+MB3Episode["SeasonName"]+" for "+MB3Episode["SeriesName"]+ " found","Cancel to stop automatic play of remaining episodes", str(remainingsecs) + " second(s) until auto dismiss")
                        
                        if pDialog.iscanceled()==False:
                            seasonId = MB3Episode["SeasonId"]
                            jsonData = self.downloadUtils.downloadUrl("http://" + server + "/mediabrowser/Users/" + userid + "/Items?ParentId=" + seasonId + "&ImageTypeLimit=1&SortBy=SortName&SortOrder=Ascending&Filters=IsUnPlayed&IncludeItemTypes=Episode&IsVirtualUnaired=false&Recursive=true&IsMissing=False&format=json", suppress=False, popup=1 )     
                            if(jsonData != ""):
                                seasonData = json.loads(jsonData)
                                if seasonData.get("Items") != None:
                                    PlaybackUtils().PLAYAllEpisodes(seasonData.get("Items"))  
                
        self.played_information.clear()

        # stop transcoding - todo check we are actually transcoding?
        clientInfo = ClientInformation()
        txt_mac = clientInfo.getMachineId()
        url = ("http://%s:%s/mediabrowser/Videos/ActiveEncodings" % (addonSettings.getSetting('ipaddress'), addonSettings.getSetting('port')))  
        url = url + '?DeviceId=' + txt_mac
        self.downloadUtils.downloadUrl(url, type="DELETE")           
class Service():
    clientInfo = ClientInformation()
    addonName = clientInfo.getAddonName()
    WINDOW = xbmcgui.Window(10000)
    lastMetricPing = time.time()

    def __init__(self, *args):
        addonName = self.addonName

        self.logMsg("Starting NextUp Service", 0)
        self.logMsg("========  START %s  ========" % addonName, 0)
        self.logMsg("KODI Version: %s" % xbmc.getInfoLabel("System.BuildVersion"), 0)
        self.logMsg("%s Version: %s" % (addonName, self.clientInfo.getVersion()), 0)

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

    def ServiceEntryPoint(self):
        player = Player()
        monitor = xbmc.Monitor()
        
        lastFile = None
        lastUnwatchedFile = None

        while not monitor.abortRequested():
            # check every 5 sec
            if monitor.waitForAbort(5):
                # 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()

                    addonSettings = xbmcaddon.Addon(id='service.nextup.notification')
                    notificationtime = addonSettings.getSetting("autoPlaySeasonTime")
                    nextUpDisabled = addonSettings.getSetting("disableNextUp") == "true"
                    randomunwatchedtime = addonSettings.getSetting("displayRandomUnwatchedTime")
                    displayrandomunwatched = addonSettings.getSetting("displayRandomUnwatched") == "true"
                    showpostplay = addonSettings.getSetting("showPostPlay") == "true"
                    showpostplaypreview = addonSettings.getSetting("showPostPlayPreview") == "true"

                    if xbmcgui.Window(10000).getProperty("PseudoTVRunning") != "True" and not nextUpDisabled:

                        if (not showpostplay or (showpostplaypreview and showpostplay)) and (totalTime - playTime <= int(notificationtime) and (
                                        lastFile is None or lastFile != currentFile)) and totalTime != 0:
                            lastFile = currentFile
                            self.logMsg("Calling autoplayback totaltime - playtime is %s" % (totalTime - playTime), 2)
                            player.autoPlayPlayback()
                            self.logMsg("Netflix style autoplay succeeded.", 2)

                        if (showpostplay and not showpostplaypreview) and (totalTime - playTime <= 10) and totalTime != 0:
                            self.logMsg("Calling post playback", 2)
                            player.postPlayPlayback()

                        if displayrandomunwatched and (int(playTime) >= int(randomunwatchedtime)) and (int(playTime) < int(int(randomunwatchedtime)+100)) and (
                                        lastUnwatchedFile is None or lastUnwatchedFile != currentFile):
                            self.logMsg("randomunwatchedtime is %s" % (int(randomunwatchedtime)), 2)
                            self.logMsg("Calling display unwatched", 2)
                            lastUnwatchedFile = currentFile
                            player.displayRandomUnwatched()


                except Exception as e:
                    self.logMsg("Exception in Playback Monitor Service: %s" % e)

        self.logMsg("======== STOP %s ========" % self.addonName, 0)
def stopAll(played_information):

    if (len(played_information) == 0):
        return

    addonSettings = xbmcaddon.Addon(id='plugin.video.xbmb3c')
    printDebug("XBMB3C Service -> played_information : " +
               str(played_information))

    for item_url in played_information:
        data = played_information.get(item_url)
        if (data != None):
            printDebug("XBMB3C Service -> item_url  : " + item_url)
            printDebug("XBMB3C Service -> item_data : " + str(data))

            watchedurl = data.get("watchedurl")
            positionurl = data.get("positionurl")
            deleteurl = data.get("deleteurl")
            runtime = data.get("runtime")
            currentPossition = data.get("currentPossition")
            item_id = data.get("item_id")
            refresh_id = data.get("refresh_id")
            currentFile = data.get("currentfile")
            BackgroundDataUpdaterThread().updateItem(refresh_id)
            if (currentPossition != None and hasData(runtime)
                    and hasData(positionurl) and hasData(watchedurl)):
                runtimeTicks = int(runtime)
                printDebug("XBMB3C Service -> runtimeticks:" +
                           str(runtimeTicks))
                percentComplete = (currentPossition * 10000000) / runtimeTicks
                markPlayedAt = float(
                    addonSettings.getSetting("markPlayedAt")) / 100

                printDebug("XBMB3C Service -> Percent Complete:" +
                           str(percentComplete) + " Mark Played At:" +
                           str(markPlayedAt))
                stopPlayback(currentFile,
                             str(int(currentPossition * 10000000)))
                if (percentComplete > markPlayedAt):
                    gotDeleted = 0
                    if (deleteurl != None and deleteurl != ""):
                        printDebug("XBMB3C Service -> Offering Delete:" +
                                   str(deleteurl))
                        gotDeleted = deleteItem(deleteurl)

    if (newNextUpThread != None):
        newNextUpThread.updateNextUp()

    if (artworkRotationThread != None):
        artworkRotationThread.updateActionUrls()

    played_information.clear()

    # stop transcoding - todo check we are actually transcoding?
    clientInfo = ClientInformation()
    txt_mac = clientInfo.getMachineId()
    url = ("http://%s:%s/mediabrowser/Videos/ActiveEncodings" %
           (addonSettings.getSetting('ipaddress'),
            addonSettings.getSetting('port')))
    url = url + '?DeviceId=' + txt_mac
    stopTranscoding(url)
示例#34
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")
示例#35
0
    def authenticate(self, retreive=True):

        WINDOW = xbmcgui.Window(10000)
        self.addonSettings = xbmcaddon.Addon(id='plugin.video.xbmb3c')
        username = self.addonSettings.getSetting('username')

        token = WINDOW.getProperty("AccessToken" + username)
        if (token != None and token != ""):
            self.logMsg(
                "DownloadUtils -> Returning saved (WINDOW) AccessToken for user:"******" token:" + token)
            return token

        token = self.addonSettings.getSetting("AccessToken" + username)
        if (token != None and token != ""):
            WINDOW.setProperty("AccessToken" + username, token)
            self.logMsg(
                "DownloadUtils -> Returning saved (SETTINGS) AccessToken for user:"******" token:" + token)
            return token

        port = self.addonSettings.getSetting("port")
        host = self.addonSettings.getSetting("ipaddress")
        if (host == None or host == "" or host == "<none>" or port == None
                or port == ""):
            return ""

        if (retreive == False):
            return ""

        url = "http://" + host + ":" + port + "/mediabrowser/Users/AuthenticateByName?format=json"

        clientInfo = ClientInformation()
        txt_mac = clientInfo.getMachineId()
        version = clientInfo.getVersion()

        # get user info
        jsonData = self.downloadUrl("http://" + host + ":" + port +
                                    "/mediabrowser/Users/Public?format=json",
                                    authenticate=False)
        users = []
        if (jsonData != ""):
            users = json.loads(jsonData)
        userHasPassword = False
        for user in users:
            name = user.get("Name")
            if (username == name):
                if (user.get("HasPassword") == True):
                    userHasPassword = True
                break

        password = ""
        if (userHasPassword):
            password = xbmcgui.Dialog().input("Enter Password for user : "******""):
            sha1 = hashlib.sha1(password)
            sha1 = sha1.hexdigest()
        else:
            sha1 = 'da39a3ee5e6b4b0d3255bfef95601890afd80709'

        messageData = "username="******"&password="******"POST",
                                authenticate=False)

        result = None
        accessToken = None
        try:
            xbmc.log("Auth_Reponce: " + str(resp))
            result = json.loads(resp)
            accessToken = result.get("AccessToken")
        except:
            pass

        if (result != None and accessToken != None):
            userID = result.get("User").get("Id")
            self.logMsg("User Authenticated : " + accessToken)
            WINDOW.setProperty("AccessToken" + username, accessToken)
            WINDOW.setProperty("userid" + username, userID)
            self.addonSettings.setSetting("AccessToken" + username,
                                          accessToken)
            self.addonSettings.setSetting("userid" + username, userID)
            return accessToken
        else:
            self.logMsg("User NOT Authenticated")
            WINDOW.setProperty("AccessToken" + username, "")
            WINDOW.setProperty("userid" + username, "")
            self.addonSettings.setSetting("AccessToken" + username, "")
            self.addonSettings.setSetting("userid" + username, "")
            return ""
示例#36
0
def addUser():

    doUtils = DownloadUtils()
    clientInfo = ClientInformation()
    currUser = WINDOW.getProperty("currUser")
    deviceId = clientInfo.getMachineId()
    deviceName = clientInfo.getDeviceName()

    # Get session
    url = "{server}/mediabrowser/Sessions?DeviceId=%s" % deviceId
    result = doUtils.downloadUrl(url)
    
    try:
        sessionId = result[0][u'Id']
        additionalUsers = result[0][u'AdditionalUsers']
        # Add user to session
        userlist = {}
        users = []
        url = "{server}/mediabrowser/Users?IsDisabled=false&IsHidden=false"
        result = doUtils.downloadUrl(url)

        # pull the list of users
        for user in result:
            name = user[u'Name']
            userId = user[u'Id']
            if currUser not in name:
                userlist[name] = userId
                users.append(name)

        # Display dialog if there's additional users
        if additionalUsers:

            option = xbmcgui.Dialog().select("Add/Remove user from the session", ["Add user", "Remove user"])
            # Users currently in the session
            additionalUserlist = {}
            additionalUsername = []
            # Users currently in the session
            for user in additionalUsers:
                name = user[u'UserName']
                userId = user[u'UserId']
                additionalUserlist[name] = userId
                additionalUsername.append(name)

            if option == 1:
                # User selected Remove user
                resp = xbmcgui.Dialog().select("Remove user from the session", additionalUsername)
                if resp > -1:
                    selected = additionalUsername[resp]
                    selected_userId = additionalUserlist[selected]
                    url = "{server}/mediabrowser/Sessions/%s/Users/%s" % (sessionId, selected_userId)
                    postdata = {}
                    doUtils.downloadUrl(url, postBody=postdata, type="DELETE")
                    xbmcgui.Dialog().notification("Success!", "%s removed from viewing session" % selected, time=1000)
                    return
                else:
                    return

            elif option == 0:
                # User selected Add user
                for adduser in additionalUsername:
                    xbmc.log(str(adduser))
                    users.remove(adduser)

            elif option < 0:
                # User cancelled
                return

        # Subtract any additional users
        xbmc.log("Displaying list of users: %s" % users)
        resp = xbmcgui.Dialog().select("Add user to the session", users)
        # post additional user
        if resp > -1:
            selected = users[resp]
            selected_userId = userlist[selected]
            url = "{server}/mediabrowser/Sessions/%s/Users/%s" % (sessionId, selected_userId)
            postdata = {}
            doUtils.downloadUrl(url, postBody=postdata, type="POST")
            xbmcgui.Dialog().notification("Success!", "%s added to viewing session" % selected, time=1000)

    except:
        xbmc.log("Failed to add user to session.")
        xbmcgui.Dialog().notification("Error", "Unable to add/remove user from the session.", xbmcgui.NOTIFICATION_ERROR)
示例#37
0
class WriteKodiMusicDB():
    
    textureCache = TextureCache()
    kodiversion = int(xbmc.getInfoLabel("System.BuildVersion")[:2])
    
    addonName = ClientInformation().getAddonName()
    WINDOW = xbmcgui.Window(10000)

    username = WINDOW.getProperty('currUser')
    userid = WINDOW.getProperty('userId%s' % username)
    server = WINDOW.getProperty('server%s' % username)

    directpath = utils.settings('useDirectPaths') == "true"

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

        className = self.__class__.__name__
        utils.logMsg("%s %s" % (self.addonName, className), msg, int(lvl))
        
    def addOrUpdateArtistToKodiLibrary(self, MBitem, connection, cursor):
        
        # If the item already exist in the local Kodi DB we'll perform a full item update
        # If the item doesn't exist, we'll add it to the database
        kodiVersion = self.kodiversion
        embyId = MBitem["Id"]
        
        cursor.execute("SELECT kodi_id FROM emby WHERE emby_id = ?", (embyId,))
        try:
            artistid = cursor.fetchone()[0]
        except:
            artistid = None
        
        ##### The artist details #####
        lastScraped = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        dateadded = API().getDateCreated(MBitem)
        checksum = API().getChecksum(MBitem)

        name = MBitem['Name']
        musicBrainzId = API().getProvider(MBitem, "musicBrainzArtist")
        genres = " / ".join(MBitem.get('Genres'))
        bio = API().getOverview(MBitem)

        # Associate artwork
        artworks = API().getAllArtwork(MBitem)
        thumb = artworks['Primary']
        backdrops = artworks['Backdrop'] # List

        if thumb:
            thumb = "<thumb>%s</thumb>" % thumb
        if backdrops:
            fanart = "<fanart>%s</fanart>" % backdrops[0]
        else:
            fanart = ""

        ##### UPDATE THE ARTIST #####
        if artistid:
            self.logMsg("UPDATE artist to Kodi library, Id: %s - Artist: %s" % (embyId, name), 1)

            if kodiVersion == 16:
                query = "UPDATE artist SET strArtist = ?, strMusicBrainzArtistID = ?, strGenres = ?, strBiography = ?, strImage = ?, strFanart = ?, lastScraped = ? WHERE idArtist = ?"
                cursor.execute(query, (name, musicBrainzId, genres, bio, thumb, fanart, lastScraped, artistid))
            else:
                query = "UPDATE artist SET strArtist = ?, strMusicBrainzArtistID = ?, strGenres = ?, strBiography = ?, strImage = ?, strFanart = ?, lastScraped = ?, dateadded = ? WHERE idArtist = ?"
                cursor.execute(query, (name, musicBrainzId, genres, bio, thumb, fanart, lastScraped, dateadded, artistid))

            # Update the checksum in emby table
            query = "UPDATE emby SET checksum = ? WHERE emby_id = ?"
            cursor.execute(query, (checksum, embyId))

        ##### OR ADD THE ARTIST #####
        else:
            self.logMsg("ADD artist to Kodi library, Id: %s - Artist: %s" % (embyId, name), 1)
            
            #safety checks: It looks like Emby supports the same artist multiple times in the database while Kodi doesn't allow that. In case that happens we just merge the artist in the Kodi database.
            
            # Safety check 1: does the artist already exist?
            cursor.execute("SELECT idArtist FROM artist WHERE strArtist = ? COLLATE NOCASE", (name,))
            try:
                artistid = cursor.fetchone()[0]
                self.logMsg("Artist already exists in Kodi library - appending to existing object, Id: %s - Artist: %s - MusicBrainzId: %s - existing Kodi Id: %s" % (embyId, name, musicBrainzId, str(artistid)), 1)
            except: pass
            
            # Safety check 2: does the MusicBrainzArtistId already exist?
            cursor.execute("SELECT idArtist FROM artist WHERE strMusicBrainzArtistID = ?", (musicBrainzId,))
            try:
                artistid = cursor.fetchone()[0]
                self.logMsg("Artist already exists in Kodi library - appending to existing object, Id: %s - Artist: %s - MusicBrainzId: %s - existing Kodi Id: %s" % (embyId, name, musicBrainzId, str(artistid)), 1)
            except: pass
                
            if not artistid:
                # Create the artist
                cursor.execute("select coalesce(max(idArtist),0) as artistid from artist")
                artistid = cursor.fetchone()[0] + 1
                if kodiVersion == 16:
                    query = "INSERT INTO artist(idArtist, strArtist, strMusicBrainzArtistID, strGenres, strBiography, strImage, strFanart, lastScraped) values(?, ?, ?, ?, ?, ?, ?, ?)"
                    cursor.execute(query, (artistid, name, musicBrainzId, genres, bio, thumb, fanart, lastScraped))
                else:
                    query = "INSERT INTO artist(idArtist, strArtist, strMusicBrainzArtistID, strGenres, strBiography, strImage, strFanart, lastScraped, dateAdded) values(?, ?, ?, ?, ?, ?, ?, ?, ?)"
                    cursor.execute(query, (artistid, name, musicBrainzId, genres, bio, thumb, fanart, lastScraped, dateadded))

            # Create the reference in emby table
            query = "INSERT INTO emby(emby_id, kodi_id, media_type, checksum) values(?, ?, ?, ?)"
            cursor.execute(query, (embyId, artistid, "artist", checksum))

        # Update artwork
        self.textureCache.addArtwork(artworks, artistid, "artist", cursor)

    def addOrUpdateAlbumToKodiLibrary(self, MBitem, connection, cursor):
        
        kodiVersion = self.kodiversion
        
        embyId = MBitem["Id"]
        
        # If the item already exist in the local Kodi DB we'll perform a full item update
        # If the item doesn't exist, we'll add it to the database
        
        cursor.execute("SELECT kodi_id FROM emby WHERE emby_id = ?", (embyId,))
        try:
            albumid = cursor.fetchone()[0]
        except:
            albumid = None

        genres = MBitem.get('Genres')

        ##### The album details #####
        lastScraped = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        dateadded = API().getDateCreated(MBitem)
        checksum = API().getChecksum(MBitem)

        name = MBitem['Name']
        musicBrainzId = API().getProvider(MBitem, "musicBrainzAlbum")
        year = MBitem.get('ProductionYear')
        genre = " / ".join(genres)
        bio = API().getOverview(MBitem)
        
        MBartists = []
        for item in MBitem['AlbumArtists']:
            MBartists.append(item['Name'])
        artists = " / ".join(MBartists)

        # Associate the artwork
        artworks = API().getAllArtwork(MBitem)
        thumb = artworks['Primary']
        if thumb:
            thumb = "<thumb>%s</thumb>" % thumb

        
        ##### UPDATE THE ALBUM #####
        if albumid:
            self.logMsg("UPDATE album to Kodi library, Id: %s - Title: %s" % (embyId, name), 1)

            if kodiVersion == 15:
                # Kodi Isengard
                query = "UPDATE album SET strAlbum = ?, strMusicBrainzAlbumID = ?, strArtists = ?, iYear = ?, strGenres = ?, strReview = ?, strImage = ?, lastScraped = ?, dateAdded = ?, strReleaseType = ? WHERE idAlbum = ?"
                cursor.execute(query, (name, musicBrainzId, artists, year, genre, bio, thumb, lastScraped, dateadded, "album", albumid))
            elif kodiVersion == 16:
                query = "UPDATE album SET strAlbum = ?, strMusicBrainzAlbumID = ?, strArtists = ?, iYear = ?, strGenres = ?, strReview = ?, strImage = ?, lastScraped = ?, strReleaseType = ? WHERE idAlbum = ?"
                cursor.execute(query, (name, musicBrainzId, artists, year, genre, bio, thumb, lastScraped, "album", albumid))
            else:
                # Kodi Gotham and Helix
                query = "UPDATE album SET strAlbum = ?, strMusicBrainzAlbumID = ?, strArtists = ?, iYear = ?, strGenres = ?, strReview = ?, strImage = ?, lastScraped = ?, dateAdded = ? WHERE idAlbum = ?"
                cursor.execute(query, (name, musicBrainzId, artists, year, genre, bio, thumb, lastScraped, dateadded, albumid))

            # Update the checksum in emby table
            query = "UPDATE emby SET checksum = ? WHERE emby_id = ?"
            cursor.execute(query, (checksum, embyId))

        ##### OR ADD THE ALBUM #####
        else:
            self.logMsg("ADD album to Kodi library, Id: %s - Title: %s" % (embyId, name), 1)
            
            # Safety check: does the strMusicBrainzAlbumID already exist?
            cursor.execute("SELECT idAlbum FROM album WHERE strMusicBrainzAlbumID = ?", (musicBrainzId,))
            try:
                albumid = cursor.fetchone()[0]
            except:
                # Create the album
                cursor.execute("select coalesce(max(idAlbum),0) as albumid from album")
                albumid = cursor.fetchone()[0] + 1
                if kodiVersion == 15:
                    # Kodi Isengard
                    query = "INSERT INTO album(idAlbum, strAlbum, strMusicBrainzAlbumID, strArtists, iYear, strGenres, strReview, strImage, lastScraped, dateAdded, strReleaseType) values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
                    cursor.execute(query, (albumid, name, musicBrainzId, artists, year, genre, bio, thumb, lastScraped, dateadded, "album"))
                elif kodiVersion == 16:
                    query = "INSERT INTO album(idAlbum, strAlbum, strMusicBrainzAlbumID, strArtists, iYear, strGenres, strReview, strImage, lastScraped, strReleaseType) values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
                    cursor.execute(query, (albumid, name, musicBrainzId, artists, year, genre, bio, thumb, lastScraped, "album"))
                else:
                    # Kodi Gotham and Helix
                    query = "INSERT INTO album(idAlbum, strAlbum, strMusicBrainzAlbumID, strArtists, iYear, strGenres, strReview, strImage, lastScraped, dateAdded) values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
                    cursor.execute(query, (albumid, name, musicBrainzId, artists, year, genre, bio, thumb, lastScraped, dateadded))

            # Create the reference in emby table
            query = "INSERT INTO emby(emby_id, kodi_id, media_type, checksum) values(?, ?, ?, ?)"
            cursor.execute(query, (embyId, albumid, "album", checksum))


        # Add genres
        self.AddGenresToMedia(albumid, genres, "album", cursor)

        # Update artwork
        self.textureCache.addArtwork(artworks, albumid, "album", cursor)
        
        # Link album to artists
        if MBartists:
            album_artists = MBitem['AlbumArtists']
        else:
            album_artists = MBitem.get('ArtistItems', [])

        for artist in album_artists:
            cursor.execute("SELECT kodi_id FROM emby WHERE emby_id = ?", (artist['Id'],))
            try:
                artistid = cursor.fetchone()[0]
            except: pass
            else:
                query = "INSERT OR REPLACE INTO album_artist(idArtist, idAlbum, strArtist) values(?, ?, ?)"
                cursor.execute(query, (artistid, albumid, artist['Name']))
                # Update discography
                query = "INSERT OR REPLACE INTO discography(idArtist, strAlbum, strYear) values(?, ?, ?)"
                cursor.execute(query, (artistid, name, str(year)))
        
    def addOrUpdateSongToKodiLibrary(self, MBitem, connection, cursor):

        kodiVersion = self.kodiversion
        
        embyId = MBitem["Id"]
        
        # If the item already exist in the local Kodi DB we'll perform a full item update
        # If the item doesn't exist, we'll add it to the database
        
        cursor.execute("SELECT kodi_id FROM emby WHERE emby_id = ?", (embyId,))
        try:
            songid = cursor.fetchone()[0]
        except:
            songid = None
        
        timeInfo = API().getTimeInfo(MBitem)
        userData = API().getUserData(MBitem)
        genres = MBitem.get('Genres')

        ##### The song details #####
        playcount = userData.get('PlayCount')
        lastplayed = userData.get('LastPlayedDate')
        dateadded = API().getDateCreated(MBitem)
        checksum = API().getChecksum(MBitem)
        
        name = MBitem['Name']
        musicBrainzId = API().getProvider(MBitem, "musicBrainzTrackId")
        genre = " / ".join(genres)
        artists = " / ".join(MBitem.get('Artists'))
        track = MBitem.get('IndexNumber')
        year = MBitem.get('ProductionYear')
        bio = API().getOverview(MBitem)
        duration = timeInfo.get('TotalTime')


        if utils.settings('directstreammusic') == "true":
            WINDOW = xbmcgui.Window(10000)
            username = WINDOW.getProperty('currUser')
            server = WINDOW.getProperty('server%s' % username)

            playurl = PlayUtils().directStream(MBitem, server, embyId, "Audio")
            filename = "stream.mp3"
            path = playurl.replace(filename, "")
        else:
            # Get the path and filename
            playurl = PlayUtils().directPlay(MBitem)
            path, filename = ntsplit(playurl)
            if "/" in playurl:
                path = "%s/" % path
            elif "\\" in playurl:
                path = "%s\\" % path


        # Validate the path in database
        cursor.execute("SELECT idPath as pathid FROM path WHERE strPath = ?", (path,))
        try:
            pathid = cursor.fetchone()[0]
        except:
            cursor.execute("select coalesce(max(idPath),0) as pathid from path")
            pathid = cursor.fetchone()[0] + 1
            query = "INSERT INTO path(idPath, strPath) values(?, ?)"
            cursor.execute(query, (pathid, path))

        # Get the album
        cursor.execute("SELECT kodi_id FROM emby WHERE emby_id = ?", (MBitem.get("AlbumId"),))
        try:
            albumid = cursor.fetchone()[0]
        except:
            # No album found, create a single's album
            cursor.execute("select coalesce(max(idAlbum),0) as albumid from album")
            albumid = cursor.fetchone()[0] + 1
            if kodiVersion == 15:
                # Kodi Isengard
                query = "INSERT INTO album(idAlbum, strArtists, strGenres, iYear, dateAdded, strReleaseType) values(?, ?, ?, ?, ?, ?)"
                cursor.execute(query, (albumid, artists, genre, year, dateadded, "single"))
            elif kodiVersion == 16:
                query = "INSERT INTO album(idAlbum, strArtists, strGenres, iYear, strReleaseType) values(?, ?, ?, ?, ?)"
                cursor.execute(query, (albumid, artists, genre, year, "single"))
            else:
                # Kodi Gotham and Helix
                query = "INSERT INTO album(idAlbum, strArtists, strGenres, iYear, dateAdded) values(?, ?, ?, ?, ?)"
                cursor.execute(query, (albumid, artists, genre, year, dateadded))

            # Link album to artists
            for artist in MBitem['ArtistItems']:
                cursor.execute("SELECT kodi_id FROM emby WHERE emby_id = ?", (artist['Id'],))
                try:
                    artistid = cursor.fetchone()[0]
                except: pass
                else:
                    query = "INSERT OR REPLACE INTO album_artist(idArtist, idAlbum, strArtist) values(?, ?, ?)"
                    cursor.execute(query, (artistid, albumid, artist['Name']))


        ##### UPDATE THE SONG #####
        if songid:
            self.logMsg("UPDATE song to Kodi library, Id: %s - Title: %s" % (embyId, name), 1)

            query = "UPDATE song SET idAlbum = ?, strArtists = ?, strGenres = ?, strTitle = ?, iTrack = ?, iDuration = ?, iYear = ?, strFilename = ?, strMusicBrainzTrackID = ?, iTimesPlayed = ?, lastplayed = ? WHERE idSong = ?"
            cursor.execute(query, (albumid, artists, genre, name, track, duration, year, filename, musicBrainzId, playcount, lastplayed, songid))

            # Update the checksum in emby table
            query = "UPDATE emby SET checksum = ? WHERE emby_id = ?"
            cursor.execute(query, (checksum, embyId))

        ##### OR ADD THE SONG #####
        else:
            self.logMsg("ADD song to Kodi library, Id: %s - Title: %s" % (embyId, name), 1)

            # Create the song
            cursor.execute("select coalesce(max(idSong),0) as songid from song")
            songid = cursor.fetchone()[0] + 1
            query = "INSERT INTO song(idSong, idAlbum, idPath, strArtists, strGenres, strTitle, iTrack, iDuration, iYear, strFileName, strMusicBrainzTrackID, iTimesPlayed, lastplayed) values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
            cursor.execute(query, (songid, albumid, pathid, artists, genre, name, track, duration, year, filename, musicBrainzId, playcount, lastplayed))

            # Create the reference in emby table
            query = "INSERT INTO emby(emby_id, kodi_id, media_type, checksum) values(?, ?, ?, ?)"
            cursor.execute(query, (embyId, songid, "song", checksum))

        
        # Add genres
        self.AddGenresToMedia(songid, genres, "song", cursor)
        
        # Link song to album
        if albumid:
            query = "INSERT OR REPLACE INTO albuminfosong(idAlbumInfoSong, idAlbumInfo, iTrack, strTitle, iDuration) values(?, ?, ?, ?, ?)"
            cursor.execute(query, (songid, albumid, track, name, duration))
        
        # Link song to artist
        for artist in MBitem.get('ArtistItems'):
            cursor.execute("SELECT kodi_id FROM emby WHERE emby_id = ?", (artist['Id'],))
            try:
                artistid = cursor.fetchone()[0]
            except: pass
            else:
                query = "INSERT OR REPLACE INTO song_artist(idArtist, idSong, strArtist) values(?, ?, ?)"
                cursor.execute(query, (artistid, songid, artist['Name']))
        
        # Update artwork
        self.textureCache.addArtwork(API().getAllArtwork(MBitem), songid, "song", cursor)
    
    def deleteItemFromKodiLibrary(self, id, connection, cursor):
        
        cursor.execute("SELECT kodi_id, media_type FROM emby WHERE emby_id=?", (id,))
        try:
            result = cursor.fetchone()
            kodi_id = result[0]
            media_type = result[1]
        except: pass
        else:
            if "artist" in media_type:
                self.logMsg("Deleting artist from Kodi library, Id: %s" % id, 1)
                cursor.execute("DELETE FROM artist WHERE idArtist = ?", (kodi_id,))
            elif "song" in media_type:
                self.logMsg("Deleting song from Kodi library, Id: %s" % id, 1)
                cursor.execute("DELETE FROM song WHERE idSong = ?", (kodi_id,))
            elif "album" in media_type:
                self.logMsg("Deleting album from Kodi library, Id: %s" % id, 1)
                cursor.execute("DELETE FROM album WHERE idAlbum = ?", (kodi_id,))

            # Delete the record in emby table
            cursor.execute("DELETE FROM emby WHERE emby_id = ?", (id,))
                          
    def addOrUpdateArt(self, imageUrl, kodiId, mediaType, imageType, cursor):

        if imageUrl:

            cacheimage = False

            cursor.execute("SELECT url FROM art WHERE media_id = ? AND media_type = ? AND type = ?", (kodiId, mediaType, imageType,))
            try:
                url = cursor.fetchone()[0]
            except: # Image does not exists
                cacheimage = True
                self.logMsg("Adding Art Link for kodiId: %s (%s)" % (kodiId, imageUrl), 1)
                query = "INSERT INTO art(media_id, media_type, type, url) values(?, ?, ?, ?)"
                cursor.execute(query, (kodiId, mediaType, imageType, imageUrl))
            else:
                if url != imageUrl:
                    cacheimage = True
                    self.logMsg("Updating Art Link for kodiId: %s (%s) -> (%s)" % (kodiId, url, imageUrl), 1)
                    query = "UPDATE art SET url = ? WHERE media_id = ? and media_type = ? and type = ?"
                    cursor.execute(query, (imageUrl, kodiId, mediaType, imageType))
            
            # Cache fanart textures in Kodi texture cache
            if cacheimage and "fanart" in imageType:
                self.textureCache.CacheTexture(imageUrl)
                     
    def AddGenresToMedia(self, id, genres, mediatype, cursor):

        if genres:
            
            for genre in genres:

                cursor.execute("SELECT idGenre as idGenre FROM genre WHERE strGenre = ? COLLATE NOCASE", (genre,))
                try:
                    idGenre = cursor.fetchone()[0]
                except: # Create the genre
                    cursor.execute("select coalesce(max(idGenre),0) as idGenre from genre")
                    idGenre = cursor.fetchone()[0] + 1
                    query = "INSERT INTO genre(idGenre, strGenre) values(?, ?)"
                    cursor.execute(query, (idGenre, genre))
                finally: # Assign the genre to item
                    if "album" in mediatype:
                        query = "INSERT OR REPLACE INTO album_genre(idGenre, idAlbum) values(?, ?)"
                        cursor.execute(query, (idGenre, id))
                    elif "song" in mediatype:
                        query = "INSERT OR REPLACE INTO song_genre(idGenre, idSong) values(?, ?)"
                        cursor.execute(query, (idGenre, id))

    def updateUserdata(self, userdata, connection, cursor):
        # This updates: LastPlayedDate, Playcount
        embyId = userdata['ItemId']
        MBitem = ReadEmbyDB().getItem(embyId)

        if not MBitem:
            self.logMsg("UPDATE userdata to Kodi library FAILED, Item %s not found on server!" % embyId, 1)
            return

        # Get details
        checksum = API().getChecksum(MBitem)
        userdata = API().getUserData(MBitem)

        # Find the Kodi Id
        cursor.execute("SELECT kodi_id, media_type FROM emby WHERE emby_id = ?", (embyId,))
        try:
            result = cursor.fetchone()
            kodiid = result[0]
            mediatype = result[1]
            self.logMsg("Found embyId: %s in database - kodiId: %s type: %s" % (embyId, kodiid, mediatype), 1)
        except:
            self.logMsg("Id: %s not found in the emby database table." % embyId, 1)
        else:
            if mediatype in ("song"):
                playcount = userdata['PlayCount']
                dateplayed = userdata['LastPlayedDate']

                query = "UPDATE song SET iTimesPlayed = ?, lastplayed = ? WHERE idSong = ?"
                cursor.execute(query, (playcount, dateplayed, kodiid))

                #update the checksum in emby table
                query = "UPDATE emby SET checksum = ? WHERE emby_id = ?"
                cursor.execute(query, (checksum, embyId))
示例#38
0
    def getPlayUrl(self, server, id, result):

        addonSettings = xbmcaddon.Addon(id='plugin.video.xbmb3c')
        # if the path is local and depending on the video quality play we can direct play it do so-
        xbmc.log("XBMB3C getPlayUrl")
        if self.isDirectPlay(result) == True:
            xbmc.log("XBMB3C getPlayUrl -> Direct Play")
            playurl = result.get("Path")
            if playurl != None:
                #We have a path to play so play it
                USER_AGENT = 'QuickTime/7.7.4'

                # If the file it is not a media stub
                if (result.get("IsPlaceHolder") != True):
                    if (result.get("VideoType") == "Dvd"):
                        playurl = playurl + "/VIDEO_TS/VIDEO_TS.IFO"
                    elif (result.get("VideoType") == "BluRay"):
                        playurl = playurl + "/BDMV/index.bdmv"
                if addonSettings.getSetting('smbusername') == '':
                    playurl = playurl.replace("\\\\", "smb://")
                else:
                    playurl = playurl.replace(
                        "\\\\",
                        "smb://" + addonSettings.getSetting('smbusername') +
                        ':' + addonSettings.getSetting('smbpassword') + '@')
                playurl = playurl.replace("\\", "/")

                if ("apple.com" in playurl):
                    playurl += '?|User-Agent=%s' % USER_AGENT
                if addonSettings.getSetting('playFromStream') == "true":
                    playurl = 'http://' + server + '/mediabrowser/Videos/' + id + '/stream?static=true'
                    mediaSources = result.get("MediaSources")
                    if (mediaSources != None):
                        if mediaSources[0].get(
                                'DefaultAudioStreamIndex') != None:
                            playurl = playurl + "&AudioStreamIndex=" + str(
                                mediaSources[0].get('DefaultAudioStreamIndex'))
                        if mediaSources[0].get(
                                'DefaultSubtitleStreamIndex') != None:
                            playurl = playurl + "&SubtitleStreamIndex=" + str(
                                mediaSources[0].get('DefaultAudioStreamIndex'))

        else:
            #No path or has a path but not sufficient network so transcode
            xbmc.log("XBMB3C getPlayUrl -> Transcode")
            if result.get("Type") == "Audio":
                playurl = 'http://' + server + '/mediabrowser/Audio/' + id + '/stream.mp3'
            else:
                clientInfo = ClientInformation()
                txt_mac = clientInfo.getMachineId()
                playurl = 'http://' + server + '/mediabrowser/Videos/' + id + '/master.m3u8?mediaSourceId=' + id
                playurl = playurl + '&videoCodec=h264'
                playurl = playurl + '&AudioCodec=aac,ac3'
                playurl = playurl + '&deviceId=' + txt_mac
                playurl = playurl + '&VideoBitrate=' + str(
                    int(self.getVideoBitRate()) * 1000)
                mediaSources = result.get("MediaSources")
                if (mediaSources != None):
                    if mediaSources[0].get('DefaultAudioStreamIndex') != None:
                        playurl = playurl + "&AudioStreamIndex=" + str(
                            mediaSources[0].get('DefaultAudioStreamIndex'))
                    if mediaSources[0].get(
                            'DefaultSubtitleStreamIndex') != None:
                        playurl = playurl + "&SubtitleStreamIndex=" + str(
                            mediaSources[0].get('DefaultSubtitleStreamIndex'))
        return playurl.encode('utf-8')
示例#39
0
class PlayUtils():

    clientInfo = ClientInformation()
    addonName = clientInfo.getAddonName()

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

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

    def getPlayUrl(self, server, id, result):

        if self.isDirectPlay(result, True):
            # Try direct play
            playurl = self.directPlay(result)
            if playurl:
                self.logMsg("File is direct playing.", 1)
                utils.window("%splaymethod" % playurl.encode('utf-8'),
                             value="DirectPlay")

        elif self.isDirectStream(result):
            # Try direct stream
            playurl = self.directStream(result, server, id)
            if playurl:
                self.logMsg("File is direct streaming.", 1)
                utils.window("%splaymethod" % playurl, value="DirectStream")

        elif self.isTranscoding(result):
            # Try transcoding
            playurl = self.transcoding(result, server, id)
            if playurl:
                self.logMsg("File is transcoding.", 1)
                utils.window("%splaymethod" % playurl, value="Transcode")

        else:  # Error
            utils.window("playurlFalse", value="true")
            return

        return playurl.encode('utf-8')

    def isDirectPlay(self, result, dialog=False):
        # Requirements for Direct play:
        # FileSystem, Accessible path
        if utils.settings('playFromStream') == "true":
            # User forcing to play via HTTP instead of SMB
            self.logMsg("Can't direct play: Play from HTTP is enabled.", 1)
            return False

        canDirectPlay = result['MediaSources'][0]['SupportsDirectPlay']
        # Make sure it's supported by server
        if not canDirectPlay:
            self.logMsg(
                "Can't direct play: Server does not allow or support it.", 1)
            return False

        location = result['LocationType']
        # File needs to be "FileSystem"
        if 'FileSystem' in location:
            # Verify if path is accessible
            if self.fileExists(result):
                return True
            else:
                self.logMsg(
                    "Unable to direct play. Verify the following path is accessible by the device: %s. You might also need to add SMB credentials in the add-on settings."
                    % result['MediaSources'][0]['Path'], 1)
                if dialog:

                    failCount = int(utils.settings('directSteamFailedCount'))
                    self.logMsg("Direct Play failCount: %s." % failCount, 1)

                    if failCount < 2:
                        # Let user know that direct play failed
                        utils.settings('directSteamFailedCount',
                                       value=str(failCount + 1))
                        xbmcgui.Dialog().notification(
                            "Emby server",
                            "Unable to direct play. Verify your log for more information.",
                            icon=
                            "special://home/addons/plugin.video.emby/icon.png",
                            sound=False)
                    elif utils.settings('playFromStream') != "true":
                        # Permanently set direct stream as true
                        utils.settings('playFromStream', value="true")
                        xbmcgui.Dialog().notification(
                            "Emby server",
                            "Enabled play from HTTP in add-on settings.",
                            icon=
                            "special://home/addons/plugin.video.emby/icon.png",
                            sound=False)

                return False

    def directPlay(self, result):

        try:
            playurl = result['MediaSources'][0]['Path']
        except KeyError:
            playurl = result['Path']

        if 'VideoType' in result:
            # Specific format modification
            if 'Dvd' in result['VideoType']:
                playurl = "%s/VIDEO_TS/VIDEO_TS.IFO" % playurl
            elif 'BluRay' in result['VideoType']:
                playurl = "%s/BDMV/index.bdmv" % playurl

        # Network - SMB protocol
        if "\\\\" in playurl:
            smbuser = utils.settings('smbusername')
            smbpass = utils.settings('smbpassword')
            # Network share
            if smbuser:
                playurl = playurl.replace("\\\\",
                                          "smb://%s:%s@" % (smbuser, smbpass))
            else:
                playurl = playurl.replace("\\\\", "smb://")
            playurl = playurl.replace("\\", "/")

        if "apple.com" in playurl:
            USER_AGENT = "QuickTime/7.7.4"
            playurl += "?|User-Agent=%s" % USER_AGENT

        return playurl

    def isDirectStream(self, result):
        # Requirements for Direct stream:
        # FileSystem or Remote, BitRate, supported encoding
        canDirectStream = result['MediaSources'][0]['SupportsDirectStream']
        # Make sure it's supported by server
        if not canDirectStream:
            return False

        location = result['LocationType']
        # File can be FileSystem or Remote, not Virtual
        if 'Virtual' in location:
            self.logMsg("File location is virtual. Can't proceed.", 1)
            return False

        # Verify BitRate
        if not self.isNetworkQualitySufficient(result):
            self.logMsg(
                "The network speed is insufficient to playback the file.", 1)
            return False

        return True

    def directStream(self, result, server, id, type="Video"):

        if result['Path'].endswith('.strm'):
            # Allow strm loading when direct streaming
            playurl = self.directPlay(result)
            return playurl

        if "ThemeVideo" in type:
            playurl = "%s/mediabrowser/Videos/%s/stream?static=true" % (server,
                                                                        id)

        elif "Video" in type:
            playurl = "%s/mediabrowser/Videos/%s/stream?static=true" % (server,
                                                                        id)

        elif "Audio" in type:
            playurl = "%s/mediabrowser/Audio/%s/stream.mp3" % (server, id)

        return playurl

    def isTranscoding(self, result):
        # Last resort, no requirements
        # BitRate
        canTranscode = result['MediaSources'][0]['SupportsTranscoding']
        # Make sure it's supported by server
        if not canTranscode:
            return False

        location = result['LocationType']
        # File can be FileSystem or Remote, not Virtual
        if 'Virtual' in location:
            return False

        return True

    def transcoding(self, result, server, id):

        if result['Path'].endswith('.strm'):
            # Allow strm loading when transcoding
            playurl = self.directPlay(result)
            return playurl

        # Play transcoding
        deviceId = self.clientInfo.getMachineId()
        playurl = "%s/mediabrowser/Videos/%s/master.m3u8?mediaSourceId=%s" % (
            server, id, id)
        playurl = "%s&VideoCodec=h264&AudioCodec=ac3&MaxAudioChannels=6&deviceId=%s&VideoBitrate=%s" % (
            playurl, deviceId, self.getVideoBitRate() * 1000)

        playurl = self.audioSubsPref(playurl, result.get('MediaSources'))
        self.logMsg("Playurl: %s" % playurl, 1)

        return playurl

    def isNetworkQualitySufficient(self, result):
        # Works out if the network quality can play directly or if transcoding is needed
        settingsVideoBitRate = self.getVideoBitRate()
        settingsVideoBitRate = settingsVideoBitRate * 1000

        try:
            mediaSources = result['MediaSources']
            sourceBitRate = int(mediaSources[0]['Bitrate'])
        except KeyError:
            self.logMsg("Bitrate value is missing.", 1)
        else:
            self.logMsg(
                "The video quality selected is: %s, the video bitrate required to direct stream is: %s."
                % (settingsVideoBitRate, sourceBitRate), 1)
            if settingsVideoBitRate < sourceBitRate:
                return False

        return True

    def getVideoBitRate(self):
        # get the addon video quality
        videoQuality = utils.settings('videoBitRate')
        bitrate = {
            '0': 664,
            '1': 996,
            '2': 1320,
            '3': 2000,
            '4': 3200,
            '5': 4700,
            '6': 6200,
            '7': 7700,
            '8': 9200,
            '9': 10700,
            '10': 12200,
            '11': 13700,
            '12': 15200,
            '13': 16700,
            '14': 18200,
            '15': 20000,
            '16': 40000,
            '17': 100000,
            '18': 1000000
        }

        # max bit rate supported by server (max signed 32bit integer)
        return bitrate.get(videoQuality, 2147483)

    def fileExists(self, result):

        if 'Path' not in result:
            # File has no path in server
            return False

        # Convert Emby path to a path we can verify
        path = self.directPlay(result)

        try:
            pathexists = xbmcvfs.exists(path)
        except:
            pathexists = False

        # Verify the device has access to the direct path
        if pathexists:
            # Local or Network path
            self.logMsg("Path exists.", 2)
            return True
        elif ":" not in path:
            # Give benefit of the doubt for nfs.
            self.logMsg(
                "Can't verify path (assumed NFS). Still try direct play.", 2)
            return True
        else:
            self.logMsg(
                "Path is detected as follow: %s. Try direct streaming." % path,
                2)
            return False

    def audioSubsPref(self, url, mediaSources):
        # For transcoding only
        # Present the list of audio to select from
        audioStreamsList = {}
        audioStreams = []
        audioStreamsChannelsList = {}
        subtitleStreamsList = {}
        subtitleStreams = ['No subtitles']
        selectAudioIndex = ""
        selectSubsIndex = ""
        playurlprefs = "%s" % url

        mediaStream = mediaSources[0].get('MediaStreams')
        for stream in mediaStream:
            # Since Emby returns all possible tracks together, have to sort them.
            index = stream['Index']
            type = stream['Type']

            if 'Audio' in type:
                codec = stream['Codec']
                channelLayout = stream['ChannelLayout']

                try:
                    track = "%s - %s - %s %s" % (index, stream['Language'],
                                                 codec, channelLayout)
                except:
                    track = "%s - %s %s" % (index, codec, channelLayout)

                audioStreamsChannelsList[index] = stream['Channels']
                audioStreamsList[track] = index
                audioStreams.append(track)

            elif 'Subtitle' in type:
                try:
                    track = "%s - %s" % (index, stream['Language'])
                except:
                    track = "%s - %s" % (index, stream['Codec'])

                default = stream['IsDefault']
                forced = stream['IsForced']
                if default:
                    track = "%s - Default" % track
                if forced:
                    track = "%s - Forced" % track

                subtitleStreamsList[track] = index
                subtitleStreams.append(track)

        if len(audioStreams) > 1:
            resp = xbmcgui.Dialog().select("Choose the audio stream",
                                           audioStreams)
            if resp > -1:
                # User selected audio
                selected = audioStreams[resp]
                selectAudioIndex = audioStreamsList[selected]
                playurlprefs += "&AudioStreamIndex=%s" % selectAudioIndex
            else:  # User backed out of selection
                playurlprefs += "&AudioStreamIndex=%s" % mediaSources[0][
                    'DefaultAudioStreamIndex']
        else:  # There's only one audiotrack.
            selectAudioIndex = audioStreamsList[audioStreams[0]]
            playurlprefs += "&AudioStreamIndex=%s" % selectAudioIndex

        if len(subtitleStreams) > 1:
            resp = xbmcgui.Dialog().select("Choose the subtitle stream",
                                           subtitleStreams)
            if resp == 0:
                # User selected no subtitles
                pass
            elif resp > -1:
                # User selected subtitles
                selected = subtitleStreams[resp]
                selectSubsIndex = subtitleStreamsList[selected]
                playurlprefs += "&SubtitleStreamIndex=%s" % selectSubsIndex
            else:  # User backed out of selection
                playurlprefs += "&SubtitleStreamIndex=%s" % mediaSources[
                    0].get('DefaultSubtitleStreamIndex', "")

        # Get number of channels for selected audio track
        audioChannels = audioStreamsChannelsList.get(selectAudioIndex, 0)
        if audioChannels > 2:
            playurlprefs += "&AudioBitrate=384000"
        else:
            playurlprefs += "&AudioBitrate=192000"

        return playurlprefs
    def authenticate(self):
        WINDOW = xbmcgui.Window(10000)
        self.addonSettings = xbmcaddon.Addon(id='plugin.video.xbmb3c')
        token = WINDOW.getProperty("AccessToken" +
                                   self.addonSettings.getSetting('username'))
        if (token != None and token != ""):
            self.logMsg(
                "DownloadUtils -> Returning saved AccessToken for user : "******" token: " + token)
            return token

        port = self.addonSettings.getSetting("port")
        host = self.addonSettings.getSetting("ipaddress")
        if (host == None or host == "" or port == None or port == ""):
            return ""

        url = "http://" + self.addonSettings.getSetting(
            "ipaddress") + ":" + self.addonSettings.getSetting(
                "port") + "/mediabrowser/Users/AuthenticateByName?format=json"

        clientInfo = ClientInformation()
        txt_mac = clientInfo.getMachineId()
        version = clientInfo.getVersion()

        deviceName = self.addonSettings.getSetting('deviceName')
        deviceName = deviceName.replace("\"", "_")

        authString = "Mediabrowser Client=\"Kodi\",Device=\"" + deviceName + "\",DeviceId=\"" + txt_mac + "\",Version=\"" + version + "\""
        headers = {'Accept-encoding': 'gzip', 'Authorization': authString}

        if self.addonSettings.getSetting(
                'password') != None and self.addonSettings.getSetting(
                    'password') != '':
            sha1 = hashlib.sha1(self.addonSettings.getSetting('password'))
            sha1 = sha1.hexdigest()
        else:
            sha1 = 'da39a3ee5e6b4b0d3255bfef95601890afd80709'

        messageData = "username="******"&password="******"POST",
                                authenticate=False,
                                suppress=True)

        accessToken = None
        try:
            result = json.loads(resp)
            accessToken = result.get("AccessToken")
        except:
            pass

        if (accessToken != None):
            self.logMsg("User Authenticated : " + accessToken)
            WINDOW.setProperty(
                "AccessToken" + self.addonSettings.getSetting('username'),
                accessToken)
            WINDOW.setProperty(
                "userid" + self.addonSettings.getSetting('username'),
                result.get("User").get("Id"))
            return accessToken
        else:
            self.logMsg("User NOT Authenticated")
            WINDOW.setProperty(
                "AccessToken" + self.addonSettings.getSetting('username'), "")
            return ""
示例#41
0
class ConnectionManager():

    clientInfo = ClientInformation()
    user = UserClient()
    doUtils = DownloadUtils()

    addonName = clientInfo.getAddonName()
    addonId = clientInfo.getAddonId()
    addon = xbmcaddon.Addon()
    WINDOW = xbmcgui.Window(10000)

    def __init__(self):

        self.__language__ = self.addon.getLocalizedString

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

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

    def checkServer(self):

        self.WINDOW.setProperty("Server_Checked", "True")
        self.logMsg("Connection Manager Called", 2)

        server = self.user.getServer()

        if server != "":
            self.logMsg("Server already set", 2)
            return

        serverInfo = self.getServerDetails()

        try:
            prefix, ip, port = serverInfo.split(":")
            setServer = xbmcgui.Dialog().yesno(
                self.__language__(30167), "Proceed with the following server?",
                self.__language__(30169) + serverInfo)
        except:  # serverInfo is None
            self.logMsg("getServerDetails failed", 1)
            xbmc.executebuiltin('Addon.OpenSettings(%s)' % self.addonId)
            return

        if setServer == 1:
            self.logMsg("Server selected. Saving information.", 1)
            utils.settings("ipaddress", ip.replace("/", ""))
            utils.settings("port", port)
            # If https, enable the setting
            if (prefix == 'https'):
                utils.settings('https', "true")
        else:
            self.logMsg("No server selected.", 1)
            xbmc.executebuiltin('Addon.OpenSettings(%s)' % self.addonId)
            return

        # Get List of public users
        self.logMsg("Getting user list", 1)
        server = "%s:%s" % (ip.replace("/", ""), port)
        url = "%s/mediabrowser/Users/Public?format=json" % serverInfo

        result = self.doUtils.downloadUrl(url, authenticate=False)
        if result == "":
            self.logMsg("Unable to connect to %s." % server, 1)
            return

        self.logMsg("Result: %s" % result, 2)

        # Process the list returned
        names = []
        userList = []
        for user in result:
            name = user['Name']
            userList.append(name)

            if user['HasPassword']:
                name = "%s (Secure)" % name
            names.append(name)

        self.logMsg("User list: %s" % names, 1)
        resp = xbmcgui.Dialog().select(self.__language__(30200), names)
        if resp > -1:
            selected_user = userList[resp]
            self.logMsg("Selected User: %s" % selected_user, 1)
            utils.settings("username", selected_user)
        else:
            self.logMsg("No user selected.", 1)
            xbmc.executebuiltin('Addon.OpenSettings(%s)' % self.addonId)
            return

        musicDisabled = xbmcgui.Dialog().yesno("Music Setting",
                                               "Disable music library?")
        if musicDisabled:
            self.logMsg("User opted to disable music library.", 1)
            utils.settings('enableMusicSync', "false")
        else:
            # Music is enabled, prompt for direct stream
            musicPath = xbmcgui.Dialog().yesno(
                "Music Setting", "Direct stream the music library?",
                "Select this option only if you plan on listening to music outside your network."
            )
            if musicPath:
                self.logMsg("User option to direct stream music library.", 1)
                utils.settings('directstreammusic', "true")

        return

    def getServerDetails(self):

        self.logMsg("Getting Server Details from Network")

        MULTI_GROUP = ("<broadcast>", 7359)
        MESSAGE = "who is EmbyServer?"

        sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        sock.settimeout(6.0)

        sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, 20)

        sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
        sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_LOOP, 1)
        sock.setsockopt(socket.IPPROTO_IP, socket.SO_REUSEADDR, 1)

        self.logMsg("MutliGroup      : %s" % str(MULTI_GROUP), 2)
        self.logMsg("Sending UDP Data: %s" % MESSAGE, 2)
        sock.sendto(MESSAGE, MULTI_GROUP)

        try:
            data, addr = sock.recvfrom(1024)  # buffer size is 1024 bytes
            self.logMsg("Received Response: %s" % data)
            # Get the address
            data = json.loads(data)
            return data['Address']
        except:
            self.logMsg("No UDP Response")
            pass

        return None
示例#42
0
class Service():

    KodiMonitor = KodiMonitor.Kodi_Monitor()
    clientInfo = ClientInformation()

    addonName = clientInfo.getAddonName()
    logLevel = UserClient().getLogLevel()
    WINDOW = xbmcgui.Window(10000)

    newWebSocketThread = None
    newUserClient = None
    newLibraryThread = None
    warn_auth = True
    welcome_msg = True
    server_online = True

    def __init__(self, *args):

        addonName = self.addonName
        clientInfo = self.clientInfo
        logLevel = self.logLevel

        utils.window('getLogLevel', value=str(logLevel))
        utils.window('kodiProfile_emby', value=xbmc.translatePath("special://profile"))

        # Initial logging
        self.logMsg("Starting Monitor", 0)
        self.logMsg("======== START %s ========" % addonName, 0)
        self.logMsg("Platform: %s" % (clientInfo.getPlatform()), 0)
        self.logMsg("KODI Version: %s" % xbmc.getInfoLabel('System.BuildVersion'), 0)
        self.logMsg("%s Version: %s" % (addonName, clientInfo.getVersion()), 0)
        self.logMsg("Using plugin paths: %s" % (utils.settings('useDirectPaths') != "true"), 0)
        self.logMsg("Log Level: %s" % logLevel, 0)

        # Reset window props for profile switch
        utils.window('Server_online', clear=True)
        utils.window('Server_status', clear=True)
        utils.window('startup', clear=True)
        utils.window('OnWakeSync', clear=True)
        utils.window('kodiScan', clear=True)
        utils.window('minDBVersionCheck', clear=True)
        
        # Set min DB version
        utils.window('minDBVersion', value="1.1.52")

        embyProperty = utils.window('Emby.nodes.total')
        propNames = [
        
            "index","path","title","content",
            "inprogress.content","inprogress.title",
            "inprogress.content","inprogress.path",
            "nextepisodes.title","nextepisodes.content",
            "nextepisodes.path","unwatched.title",
            "unwatched.content","unwatched.path",
            "recent.title","recent.content","recent.path",
            "recentepisodes.title","recentepisodes.content",
            "recentepisodes.path","inprogressepisodes.title",
            "inprogressepisodes.content","inprogressepisodes.path"
        ]

        if embyProperty:
            totalNodes = int(embyProperty)
            for i in range(totalNodes):
                for prop in propNames:
                    utils.window('Emby.nodes.%s.%s' % (str(i), prop), clear=True)

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

        className = self.__class__.__name__
        utils.logMsg("%s %s" % (self.addonName, className), msg, int(lvl))
       
    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)
示例#43
0
class UserClient(threading.Thread):

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

    clientInfo = ClientInformation()
    doUtils = DownloadUtils()
    KodiMonitor = KodiMonitor.Kodi_Monitor()

    addonName = clientInfo.getAddonName()
    addon = xbmcaddon.Addon()
    WINDOW = xbmcgui.Window(10000)

    stopClient = False
    logLevel = int(addon.getSetting('logLevel'))
    auth = True
    retry = 0

    currUser = None
    currUserId = None
    currServer = None
    currToken = None
    HasAccess = True
    AdditionalUser = []

    def __init__(self, *args):

        self.__dict__ = self._shared_state
        threading.Thread.__init__(self, *args)

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

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

    def getUsername(self):

        username = utils.settings('username')

        if (username == ""):
            self.logMsg("No username saved.", 2)
            return ""

        return username

    def getAdditionalUsers(self):

        additionalUsers = utils.settings('additionalUsers')

        if additionalUsers:
            self.AdditionalUser = additionalUsers.split(',')

    def getLogLevel(self):

        try:
            logLevel = int(utils.settings('logLevel'))
        except:
            logLevel = 0

        return logLevel

    def getUserId(self):

        username = self.getUsername()
        w_userId = self.WINDOW.getProperty('userId%s' % username)
        s_userId = utils.settings('userId%s' % username)

        # Verify the window property
        if (w_userId != ""):
            self.logMsg(
                "Returning userId from WINDOW for username: %s UserId: %s" %
                (username, w_userId), 2)
            return w_userId
        # Verify the settings
        elif (s_userId != ""):
            self.logMsg(
                "Returning userId from SETTINGS for username: %s userId: %s" %
                (username, s_userId), 2)
            return s_userId
        # No userId found
        else:
            self.logMsg("No userId saved for username: %s." % username)
            return

    def getServer(self, prefix=True):

        alternate = utils.settings('altip') == "true"

        # For https support
        HTTPS = utils.settings('https')
        host = utils.settings('ipaddress')
        port = utils.settings('port')
        # Alternate host
        if alternate:
            HTTPS = utils.settings('secondhttps')
            host = utils.settings('secondipaddress')
            port = utils.settings('secondport')

        server = host + ":" + port

        if host == "":
            self.logMsg("No server information saved.", 2)
            return ""

        # If https is true
        if prefix and (HTTPS == "true"):
            server = "https://%s" % server
            return server
        # If https is false
        elif prefix and (HTTPS == "false"):
            server = "http://%s" % server
            return server
        # If only the host:port is required
        elif (prefix == False):
            return server

    def getToken(self):

        username = self.getUsername()
        w_token = self.WINDOW.getProperty('accessToken%s' % username)
        s_token = utils.settings('accessToken')

        # Verify the window property
        if (w_token != ""):
            self.logMsg(
                "Returning accessToken from WINDOW for username: %s accessToken: %s"
                % (username, w_token), 2)
            return w_token
        # Verify the settings
        elif (s_token != ""):
            self.logMsg(
                "Returning accessToken from SETTINGS for username: %s accessToken: %s"
                % (username, s_token), 2)
            self.WINDOW.setProperty('accessToken%s' % username, s_token)
            return s_token
        else:
            self.logMsg("No token found.")
            return ""

    def getSSLverify(self):
        # Verify host certificate
        s_sslverify = utils.settings('sslverify')
        if utils.settings('altip') == "true":
            s_sslverify = utils.settings('secondsslverify')

        if s_sslverify == "true":
            return True
        else:
            return False

    def getSSL(self):
        # Client side certificate
        s_cert = utils.settings('sslcert')
        if utils.settings('altip') == "true":
            s_cert = utils.settings('secondsslcert')

        if s_cert == "None":
            return None
        else:
            return s_cert

    def setUserPref(self):

        player = Player()
        server = self.getServer()
        userId = self.getUserId()

        url = "{server}/mediabrowser/Users/{UserId}?format=json"
        result = self.doUtils.downloadUrl(url)

        # Set user image for skin display
        self.WINDOW.setProperty("EmbyUserImage",
                                API().getUserArtwork(result, "Primary"))

        # Load the resume point from Emby and set as setting
        url = "{server}/mediabrowser/System/Configuration?format=json"
        result = self.doUtils.downloadUrl(url)

        utils.settings('markPlayed', value=str(result['MaxResumePct']))

        return True

    def getPublicUsers(self):

        server = self.getServer()

        # Get public Users
        url = "%s/mediabrowser/Users/Public?format=json" % server
        result = self.doUtils.downloadUrl(url, authenticate=False)

        users = []

        if (result != ""):
            users = result
        else:
            # Server connection failed
            return False

        return users

    def hasAccess(self):

        url = "{server}/mediabrowser/Users"
        result = self.doUtils.downloadUrl(url)

        if result is False:
            # Access is restricted
            self.logMsg("Access is restricted.")
            self.HasAccess = False
            return
        elif self.WINDOW.getProperty('Server_online') != "true":
            # Server connection failed
            return

        if self.WINDOW.getProperty("Server_status") == "restricted":
            self.logMsg("Access is granted.")
            self.HasAccess = True
            self.WINDOW.setProperty("Server_status", "")
            xbmcgui.Dialog().notification("Emby server", "Access is enabled.")
        return

    def loadCurrUser(self, authenticated=False):

        WINDOW = self.WINDOW
        doUtils = self.doUtils
        username = self.getUsername()

        # Only to be used if token exists
        self.currUserId = self.getUserId()
        self.currServer = self.getServer()
        self.currToken = self.getToken()
        self.ssl = self.getSSLverify()
        self.sslcert = self.getSSL()

        # Test the validity of current token
        if authenticated == False:
            url = "%s/mediabrowser/Users/%s" % (self.currServer,
                                                self.currUserId)
            WINDOW.setProperty("currUser", username)
            WINDOW.setProperty("accessToken%s" % username, self.currToken)
            result = doUtils.downloadUrl(url)
            if result == 401:
                # Token is no longer valid
                self.resetClient()
                return False

        # Set to windows property
        WINDOW.setProperty("currUser", username)
        WINDOW.setProperty("accessToken%s" % username, self.currToken)
        WINDOW.setProperty("server%s" % username, self.currServer)
        WINDOW.setProperty("server_%s" % username,
                           self.getServer(prefix=False))
        WINDOW.setProperty("userId%s" % username, self.currUserId)

        # Set DownloadUtils values
        doUtils.setUsername(username)
        doUtils.setUserId(self.currUserId)
        doUtils.setServer(self.currServer)
        doUtils.setToken(self.currToken)
        doUtils.setSSL(self.ssl, self.sslcert)
        # parental control - let's verify if access is restricted
        self.hasAccess()
        # Start DownloadUtils session
        doUtils.startSession()
        self.getAdditionalUsers()

        # Set user preferences in settings
        self.setUserPref()

        self.currUser = username

    def authenticate(self):

        WINDOW = self.WINDOW
        addon = self.addon

        username = self.getUsername()
        server = self.getServer()
        addondir = xbmc.translatePath(
            self.addon.getAddonInfo('profile')).decode('utf-8')
        hasSettings = xbmcvfs.exists("%ssettings.xml" % addondir)

        # If there's no settings.xml
        if (hasSettings == 0):
            self.logMsg("No settings.xml found.")
            self.auth = False
            return
        # If no user information
        if (server == "") or (username == ""):
            self.logMsg("Missing server information.")
            self.auth = False
            return
        # If there's a token
        if (self.getToken() != ""):
            result = self.loadCurrUser()

            if result == False:
                pass
            else:
                self.logMsg("Current user: %s" % self.currUser, 0)
                self.logMsg("Current userId: %s" % self.currUserId, 0)
                self.logMsg("Current accessToken: %s" % self.currToken, 0)
                return

        users = self.getPublicUsers()
        password = ""

        # Find user in list
        for user in users:
            name = user[u'Name']
            userHasPassword = False

            if (unicode(username, 'utf-8') in name):
                # Verify if user has a password
                if (user.get("HasPassword") == True):
                    userHasPassword = True
                # If user has password
                if (userHasPassword):
                    password = xbmcgui.Dialog().input(
                        "Enter password for user: %s" % username,
                        option=xbmcgui.ALPHANUM_HIDE_INPUT)
                    # If password dialog is cancelled
                    if (password == ""):
                        self.logMsg("No password entered.", 0)
                        self.WINDOW.setProperty("Server_status", "Stop")
                        self.auth = False
                        return
                break
        else:
            # Manual login, user is hidden
            password = xbmcgui.Dialog().input(
                "Enter password for user: %s" % username,
                option=xbmcgui.ALPHANUM_HIDE_INPUT)

        sha1 = hashlib.sha1(password)
        sha1 = sha1.hexdigest()

        # Authenticate username and password
        url = "%s/mediabrowser/Users/AuthenticateByName?format=json" % server
        data = {'username': username, 'password': sha1}
        self.logMsg(data, 2)

        result = self.doUtils.downloadUrl(url,
                                          postBody=data,
                                          type="POST",
                                          authenticate=False)

        accessToken = None
        try:
            self.logMsg("Auth_Reponse: %s" % result, 1)
            accessToken = result[u'AccessToken']
        except:
            pass

        if (result != None and accessToken != None):
            self.currUser = username
            xbmcgui.Dialog().notification("Emby server",
                                          "Welcome %s!" % self.currUser)
            userId = result[u'User'][u'Id']
            utils.settings("accessToken", accessToken)
            utils.settings("userId%s" % username, userId)
            self.logMsg("User Authenticated: %s" % accessToken)
            self.loadCurrUser(authenticated=True)
            self.WINDOW.setProperty("Server_status", "")
            self.retry = 0
            return
        else:
            self.logMsg("User authentication failed.")
            utils.settings("accessToken", "")
            utils.settings("userId%s" % username, "")
            xbmcgui.Dialog().ok("Error connecting",
                                "Invalid username or password.")

            # Give two attempts at entering password
            self.retry += 1
            if self.retry == 2:
                self.logMsg(
                    "Too many retries. You can retry by selecting the option in the addon settings."
                )
                self.WINDOW.setProperty("Server_status", "Stop")
                xbmcgui.Dialog().ok(
                    "Error connecting",
                    "Failed to authenticate too many times. You can retry by selecting the option in the addon settings."
                )

            self.auth = False
            return

    def resetClient(self):

        username = self.getUsername()
        self.logMsg("Reset UserClient authentication.", 1)
        if (self.currToken != None):
            # In case of 401, removed saved token
            utils.settings("accessToken", "")
            self.WINDOW.setProperty("accessToken%s" % username, "")
            self.currToken = None
            self.logMsg("User token has been removed.", 1)

        self.auth = True
        self.currUser = None
        return

    def run(self):

        self.logMsg("|---- Starting UserClient ----|", 0)

        while not self.KodiMonitor.abortRequested():

            # Verify the log level
            currLogLevel = self.getLogLevel()
            if self.logLevel != currLogLevel:
                # Set new log level
                self.logLevel = currLogLevel
                self.logMsg("New Log Level: %s" % currLogLevel, 0)
                self.WINDOW.setProperty('getLogLevel', str(currLogLevel))

            if (self.WINDOW.getProperty("Server_status") != ""):
                status = self.WINDOW.getProperty("Server_status")

                if status == "restricted":
                    # Parental control is restricting access
                    self.HasAccess = False

                elif status == "401":
                    self.WINDOW.setProperty("Server_status", "Auth")
                    # Revoked token
                    self.resetClient()

            if self.auth and (self.currUser == None):
                status = self.WINDOW.getProperty("Server_status")

                if (status == "") or (status == "Auth"):
                    self.auth = False
                    self.authenticate()

            if (self.auth == False) and (self.currUser == None):
                # Only if there's information found to login
                server = self.getServer()
                username = self.getUsername()
                status = self.WINDOW.getProperty("Server_status")

                # If user didn't enter a password when prompted
                if status == "Stop":
                    pass

                elif (server != "") and (username != ""):
                    self.logMsg("Server found: %s" % server)
                    self.logMsg("Username found: %s" % username)
                    self.auth = True

            # If stopping the client didn't work
            if self.stopClient == True:
                break

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

        self.doUtils.stopSession()
        self.logMsg("|---- UserClient Stopped ----|", 0)

    def stopClient(self):
        # As last resort
        self.stopClient = True