Ejemplo n.º 1
0
    def refreshManualConnections(self):
        manualConnections = self.getManualConnections()
        if not manualConnections:
            return

        util.LOG("Refreshing {0} manual connections".format(
            len(manualConnections)))

        for conn in manualConnections:
            # Default to http, as the server will need to be signed in for https to work,
            # so the client should too. We'd also have to allow hostname entry, instead of
            # IP address for the cert to validate.

            proto = "http"
            port = conn.port or "32400"
            serverAddress = "{0}://{1}:{2}".format(proto, conn.connection,
                                                   port)

            request = http.HttpRequest(serverAddress + "/identity")
            context = request.createRequestContext(
                "manual_connections",
                callback.Callable(self.onManualConnectionsResponse))
            context.serverAddress = serverAddress
            context.address = conn.connection
            context.proto = proto
            context.port = port
            context.timeout = 10000
            plexapp.APP.startRequest(request, context)
Ejemplo n.º 2
0
    def testReachability(self, server, allowFallback=False):
        # Check if we will allow the connection test. If this is a fallback connection,
        # then we will defer it until we "allowFallback" (test insecure connections
        # after secure tests have completed and failed). Insecure connections will be
        # tested if the policy "always" allows them, or if set to "same_network" and
        # the current connection is local and server has (publicAddressMatches=1).

        allowConnectionTest = not self.isFallback
        if not allowConnectionTest:
            insecurePolicy = plexapp.INTERFACE.getPreference("allow_insecure")
            if insecurePolicy == "always" or (insecurePolicy == "same_network"
                                              and server.sameNetwork
                                              and self.isLocal):
                allowConnectionTest = allowFallback
                server.hasFallback = not allowConnectionTest
                util.LOG('{0} for {1}'.format(
                    allowConnectionTest
                    and "Continuing with insecure connection testing"
                    or "Insecure connection testing is deferred", server))
            else:
                util.LOG(
                    "Insecure connections not allowed. Ignore insecure connection test for {0}"
                    .format(server))
                self.state = self.STATE_INSECURE
                callable = callback.Callable(server.onReachabilityResult,
                                             [self], random.randint(0, 256))
                callable.deferCall()
                return True

        if allowConnectionTest:
            if not self.isSecure and (
                    not allowFallback and server.hasSecureConnections()
                    or server.activeConnection
                    and server.activeConnection.state != self.STATE_REACHABLE
                    and server.activeConnection.isSecure):
                util.DEBUG_LOG("Invalid insecure connection test in progress")
            self.request = http.HttpRequest(self.buildUrl(server, "/"))
            context = self.request.createRequestContext(
                "reachability", callback.Callable(self.onReachabilityResponse))
            context.server = server
            context.timeout = 10000
            util.addPlexHeaders(self.request, server.getToken())
            self.hasPendingRequest = plexapp.APP.startRequest(
                self.request, context)
            return True

        return False
Ejemplo n.º 3
0
    def validateToken(self, token, switchUser=False):
        self.authToken = token
        self.switchUser = switchUser

        request = myplexrequest.MyPlexRequest("/users/sign_in.xml")
        context = request.createRequestContext("sign_in", callback.Callable(self.onAccountResponse))
        context.timeout = self.isOffline and 1000 or 10000
        plexapp.APP.startRequest(request, context, {})
Ejemplo n.º 4
0
 def removeItem(self, item):
     request = plexrequest.PlexRequest(
         self.server, "/playQueues/" + str(self.id) + "/items/" +
         item.get("playQueueItemID", "-1"), "DELETE")
     self.addRequestOptions(request)
     context = request.createRequestContext(
         "delete", callback.Callable(self.onResponse))
     plexapp.APP.startRequest(request, context)
Ejemplo n.º 5
0
    def __init__(self):
        signalsmixin.SignalsMixin.__init__(self)
        # obj.Append(ListenersMixin())
        self.serversByUuid = {}
        self.selectedServer = None
        self.transcodeServer = None
        self.channelServer = None
        self.deferReachabilityTimer = None

        self.startSelectedServerSearch()
        self.loadState()

        plexapp.APP.on("change:user", callback.Callable(self.onAccountChange))
        plexapp.APP.on("change:allow_insecure",
                       callback.Callable(self.onSecurityChange))
        plexapp.APP.on("change:manual_connections",
                       callback.Callable(self.onManualConnectionChange))
Ejemplo n.º 6
0
    def createRequestContext(self, requestType, callback_=None):
        context = RequestContext()
        context.requestType = requestType

        if callback_:
            context.callback = callback.Callable(self.onResponse)
            context.completionCallback = callback_
            context.callbackCtx = callback_.context

        return context
Ejemplo n.º 7
0
 def addItem(self, item, addNext=False, excludeSeedItem=False):
     request = plexrequest.PlexRequest(self.server,
                                       "/playQueues/" + str(self.id), "PUT")
     request.addParam("uri", item.getItemUri())
     request.addParam("next", addNext and "1" or "0")
     request.addParam("excludeSeedItem", excludeSeedItem and "1" or "0")
     self.addRequestOptions(request)
     context = request.createRequestContext(
         "add", callback.Callable(self.onResponse))
     plexapp.APP.startRequest(request, context)
Ejemplo n.º 8
0
    def sendTimelineToServer(self, timelineType, timeline, time):
        if not hasattr(timeline.item,
                       'getServer') or not timeline.item.getServer():
            return

        serverTimeline = self.getServerTimeline(timelineType)

        # Only send timeline if it's the first, item changes, playstate changes or timer pops
        itemsEqual = timeline.item and serverTimeline.item and timeline.item.ratingKey == serverTimeline.item.ratingKey
        if itemsEqual and timeline.state == serverTimeline.state and not serverTimeline.isExpired(
        ):
            return

        serverTimeline.reset()
        serverTimeline.item = timeline.item
        serverTimeline.state = timeline.state

        # Ignore sending timelines for multi part media with no duration
        obj = timeline.choice
        if obj and obj.part and obj.part.duration.asInt(
        ) == 0 and obj.media.parts and len(obj.media.parts) > 1:
            util.WARN_LOG(
                "Timeline not supported: the current part doesn't have a valid duration"
            )
            return

        # It's possible with timers and in player seeking for the time to be greater than the
        # duration, which causes a 400, so in that case we'll set the time to the duration.
        duration = timeline.item.duration.asInt() or timeline.duration
        if time > duration:
            time = duration

        params = util.AttributeDict()
        params["time"] = time
        params["duration"] = duration
        params["state"] = timeline.state
        params["guid"] = timeline.item.guid
        params["ratingKey"] = timeline.item.ratingKey
        params["url"] = timeline.item.url
        params["key"] = timeline.item.key
        params["containerKey"] = timeline.item.container.address
        if timeline.playQueue:
            params["playQueueItemID"] = timeline.playQueue.selectedId

        path = "/:/timeline"
        for paramKey in params:
            if params[paramKey]:
                path = http.addUrlParam(
                    path, paramKey + "=" + urllib.quote(str(params[paramKey])))

        request = plexrequest.PlexRequest(timeline.item.getServer(), path)
        context = request.createRequestContext(
            "timelineUpdate", callback.Callable(self.onTimelineResponse))
        context.playQueue = timeline.playQueue
        plexapp.APP.startRequest(request, context)
Ejemplo n.º 9
0
def createPlayQueueForId(id, server=None, contentType=None):
    obj = PlayQueue(server, contentType)
    obj.id = id

    request = plexrequest.PlexRequest(server, "/playQueues/" + str(id))
    request.addParam("own", "1")
    obj.addRequestOptions(request)
    context = request.createRequestContext("own",
                                           callback.Callable(obj.onResponse))
    plexapp.APP.startRequest(request, context)

    return obj
Ejemplo n.º 10
0
    def refreshResources(self, force=False):
        if force:
            plexapp.SERVERMANAGER.resetLastTest()

        request = myplexrequest.MyPlexRequest("/pms/resources")
        context = request.createRequestContext("resources", callback.Callable(self.onResourcesResponse))
        context.timeout = plexapp.ACCOUNT.isOffline and 1000 or 10000

        if plexapp.ACCOUNT.isSecure:
            request.addParam("includeHttps", "1")

        plexapp.APP.startRequest(request, context)
Ejemplo n.º 11
0
    def moveItem(self, item, after):
        if after:
            query = "?after=" + after.get("playQueueItemID", "-1")
        else:
            query = ""

        request = plexrequest.PlexRequest(
            self.server, "/playQueues/" + str(self.id) + "/items/" +
            item.get("playQueueItemID", "-1") + "/move" + query, "PUT")
        self.addRequestOptions(request)
        context = request.createRequestContext(
            "move", callback.Callable(self.onResponse))
        plexapp.APP.startRequest(request, context)
Ejemplo n.º 12
0
    def deferUpdateReachability(self, addTimer=True, logInfo=True):
        if addTimer and not self.deferReachabilityTimer:
            self.deferReachabilityTimer = plexapp.createTimer(
                1000,
                callback.Callable(self.onDeferUpdateReachabilityTimer),
                repeat=True)
            plexapp.APP.addTimer(self.deferReachabilityTimer)
        else:
            if self.deferReachabilityTimer:
                self.deferReachabilityTimer.reset()

        if self.deferReachabilityTimer and logInfo:
            util.LOG(
                'Defer update reachability for all devices a few seconds: GDMactive={0}'
                .format(gdm.DISCOVERY.isActive()))
Ejemplo n.º 13
0
    def setShuffle(self, shuffle=None):
        if shuffle is None:
            shuffle = not self.isShuffled

        if self.isShuffled == shuffle:
            return

        if shuffle:
            command = "/shuffle"
        else:
            command = "/unshuffle"

        # Don't change self.isShuffled, it'll be set in OnResponse if all goes well

        request = plexrequest.PlexRequest(
            self.server, "/playQueues/" + str(self.id) + command, "PUT")
        self.addRequestOptions(request)
        context = request.createRequestContext(
            "shuffle", callback.Callable(self.onResponse))
        plexapp.APP.startRequest(request, context)
Ejemplo n.º 14
0
    def startRequest(self, request, context, body=None, contentType=None):
        context.request = request

        started = request.startAsync(body=body,
                                     contentType=contentType,
                                     context=context)

        if started:
            requestID = context.request.getIdentity()
            self.pendingRequests[requestID] = context

            if context.timeout:
                request.timer = createTimer(
                    context.timeout,
                    callback.Callable(self.onRequestTimeout,
                                      forcedArgs=[context]))
                self.addTimer(request.timer)
        elif context.callback:
            context.callback(None, context)

        return started
Ejemplo n.º 15
0
    def loadState(self):
        # Look for the new JSON serialization. If it's not there, look for the
        # old token and Plex Pass values.

        plexapp.APP.addInitializer("myplex")

        jstring = plexapp.INTERFACE.getRegistry("MyPlexAccount", None,
                                                "myplex")

        if jstring:
            try:
                obj = json.loads(jstring)
            except:
                util.ERROR()
                obj = None

            if obj:
                self.ID = obj.get('ID') or self.ID
                self.title = obj.get('title') or self.title
                self.username = obj.get('username') or self.username
                self.email = obj.get('email') or self.email
                self.authToken = obj.get('authToken') or self.authToken
                self.pin = obj.get('pin') or self.pin
                self.isPlexPass = obj.get('isPlexPass') or self.isPlexPass
                self.isManaged = obj.get('isManaged') or self.isManaged
                self.isAdmin = obj.get('isAdmin') or self.isAdmin
                self.isSecure = obj.get('isSecure') or self.isSecure
                self.isProtected = bool(obj.get('pin'))
                self.adminHasPlexPass = obj.get(
                    'adminHasPlexPass') or self.adminHasPlexPass

        if self.authToken:
            request = myplexrequest.MyPlexRequest("/users/account")
            context = request.createRequestContext(
                "account", callback.Callable(self.onAccountResponse))
            plexapp.APP.startRequest(request, context)
        else:
            plexapp.APP.clearInitializer("myplex")
Ejemplo n.º 16
0
    def refresh(self, force=True, delay=False, wait=False):
        # Ignore refreshing local PQs
        if self.isLocal():
            return

        if wait:
            self.responded = False
            self.initialized = False
        # We refresh our play queue if the caller insists or if we only have a
        # portion of our play queue loaded. In particular, this means that we don't
        # refresh the play queue if we're asked to refresh because a new track is
        # being played but we have the entire album loaded already.

        if force or self.isWindowed():
            if delay:
                # We occasionally want to refresh the PQ in response to moving to a
                # new item and starting playback, but if we refresh immediately:
                # we probably end up refreshing before PMS realizes we've moved on.
                # There's no great solution, but delaying our refresh by just a few
                # seconds makes us much more likely to get an accurate window (and
                # accurate selected IDs) from PMS.

                if not self.refreshTimer:
                    self.refreshTimer = plexapp.createTimer(
                        5000, self.onRefreshTimer)
                    plexapp.APP.addTimer(self.refreshTimer)
            else:
                request = plexrequest.PlexRequest(
                    self.server, "/playQueues/" + str(self.id))
                self.addRequestOptions(request)
                context = request.createRequestContext(
                    "refresh", callback.Callable(self.onResponse))
                plexapp.APP.startRequest(request, context)

        if wait:
            return self.waitForInitialization()
Ejemplo n.º 17
0
def createRemotePlayQueue(item, contentType, options, args):
    util.DEBUG_LOG('Creating remote playQueue request...')
    obj = PlayQueue(item.getServer(), contentType, options)

    # The item's URI is made up of the library section UUID, a descriptor of
    # the item type (item or directory), and the item's path, URL-encoded.

    uri = "library://" + item.getLibrarySectionUuid() + "/"
    itemType = item.isDirectory() and "directory" or "item"
    path = None

    if not options.key:
        # if item.onDeck and len(item.onDeck) > 0:
        #     options.key = item.onDeck[0].getAbsolutePath("key")
        # el
        if not item.isDirectory():
            options.key = item.get("key")

    # If we're asked to play unwatched, ignore the option unless we are unwatched.
    options.unwatched = options.unwatched and item.isUnwatched()

    # TODO(schuyler): Until we build postplay, we're not allowed to queue containers for episodes.
    if item.type == "episode":
        options.context = options.CONTEXT_SELF
    elif item.type == "movie":
        if not options.extrasPrefixCount and not options.resume:
            options.extrasPrefixCount = plexapp.INTERFACE.getPreference(
                "cinema_trailers", 0)

    # How exactly to construct the item URI depends on the metadata type, though
    # whenever possible we simply use /library/metadata/:id.

    if item.isLibraryItem() and not item.isLibraryPQ:
        path = "/library/metadata/" + item.ratingKey
    else:
        path = item.getAbsolutePath("key")

    if options.context == options.CONTEXT_SELF:
        # If the context is specifically for just this item,: just use the
        # item's key and get out.
        pass
    elif item.type == "playlist":
        path = None
        uri = item.get("ratingKey")
        options.isPlaylist = True
    elif item.type == "track":
        # TODO(rob): Is there ever a time the container address is wrong? If we
        # expect to play a single track,: use options.CONTEXT_SELF.
        path = item.container.address or "/library/metadata/" + item.get(
            "parentRatingKey", "")
        itemType = "directory"
    elif item.isPhotoOrDirectoryItem():
        if item.type == "photoalbum" or item.parentKey:
            path = item.getParentPath(item.type == "photoalbum" and "key"
                                      or "parentKey")
            itemType = "item"
        elif item.isDirectory():
            path = item.getAbsolutePath("key")
        else:
            path = item.container.address
            itemType = "directory"
            options.key = item.getAbsolutePath("key")

    elif item.type == "episode":
        path = "/library/metadata/" + item.get("grandparentRatingKey", "")
        itemType = "directory"
        options.key = item.getAbsolutePath("key")
    # elif item.type == "show":
    #     path = "/library/metadata/" + item.get("ratingKey", "")

    if path:
        if args:
            path += util.joinArgs(args)

        util.DEBUG_LOG("playQueue path: " + str(path))

        if "/search" not in path:
            # Convert a few params to the PQ spec
            convert = {'type': "sourceType", 'unwatchedLeaves': "unwatched"}

            for key in convert:
                regex = re.compile("(?i)([?&])" + key + "=")
                path = regex.sub("\1" + convert[key] + "=", path)

        util.DEBUG_LOG("playQueue path: " + str(path))
        uri = uri + itemType + "/" + urllib.quote_plus(path)

    util.DEBUG_LOG("playQueue uri: " + str(uri))

    # Create the PQ request
    request = plexrequest.PlexRequest(obj.server, "/playQueues")

    request.addParam(not options.isPlaylist and "uri" or "playlistID", uri)
    request.addParam("type", contentType)
    # request.addParam('X-Plex-Client-Identifier', plexapp.INTERFACE.getGlobal('clientIdentifier'))

    # Add options we pass once during PQ creation
    if options.shuffle:
        request.addParam("shuffle", "1")
        options.key = None
    else:
        request.addParam("shuffle", "0")

    if options.key:
        request.addParam("key", options.key)

    # Add options we pass every time querying PQs
    obj.addRequestOptions(request)

    util.DEBUG_LOG('Initial playQueue request started...')
    context = request.createRequestContext("create",
                                           callback.Callable(obj.onResponse))
    plexapp.APP.startRequest(request, context, body='')

    return obj