Ejemplo n.º 1
0
def _pms_https_enabled(url):
    """
    Returns True if the PMS can talk https, False otherwise.
    None if error occured, e.g. the connection timed out

    Call with e.g. url='192.168.0.1:32400' (NO http/https)

    This is done by GET /identity (returns an error if https is enabled and we
    are trying to use http)

    Prefers HTTPS over HTTP
    """
    res = DU().downloadUrl('https://%s/identity' % url,
                           authenticate=False,
                           verifySSL=False)
    try:
        res.attrib
    except AttributeError:
        # Might have SSL deactivated. Try with http
        res = DU().downloadUrl('http://%s/identity' % url,
                               authenticate=False,
                               verifySSL=False)
        try:
            res.attrib
        except AttributeError:
            LOG.error("Could not contact PMS %s", url)
            return None
        else:
            # Received a valid XML. Server wants to talk HTTP
            return False
    else:
        # Received a valid XML. Server wants to talk HTTPS
        return True
Ejemplo n.º 2
0
def playback_cleanup(ended=False):
    """
    PKC cleanup after playback ends/is stopped. Pass ended=True if Kodi
    completely finished playing an item (because we will get and use wrong
    timing data otherwise)
    """
    LOG.debug('playback_cleanup called')
    # We might have saved a transient token from a user flinging media via
    # Companion (if we could not use the playqueue to store the token)
    state.PLEX_TRANSIENT_TOKEN = None
    for playerid in state.ACTIVE_PLAYERS:
        status = state.PLAYER_STATES[playerid]
        # Remember the last played item later
        state.OLD_PLAYER_STATES[playerid] = copy.deepcopy(status)
        # Stop transcoding
        if status['playmethod'] == 'Transcode':
            LOG.debug('Tell the PMS to stop transcoding')
            DU().downloadUrl('{server}/video/:/transcode/universal/stop',
                             parameters={'session': v.PKC_MACHINE_IDENTIFIER})
        if playerid == 1:
            # Bookmarks might not be pickup up correctly, so let's do them
            # manually. Applies to addon paths, but direct paths might have
            # started playback via PMS
            _record_playstate(status, ended)
        # Reset the player's status
        status = copy.deepcopy(state.PLAYSTATE)
    # As all playback has halted, reset the players that have been active
    state.ACTIVE_PLAYERS = []
    LOG.debug('Finished PKC playback cleanup')
Ejemplo n.º 3
0
def playback_cleanup():
    """
    PKC cleanup after playback ends/is stopped
    """
    # We might have saved a transient token from a user flinging media via
    # Companion (if we could not use the playqueue to store the token)
    LOG.debug('playback_cleanup called')
    state.PLEX_TRANSIENT_TOKEN = None
    for playerid in state.ACTIVE_PLAYERS:
        status = state.PLAYER_STATES[playerid]
        # Remember the last played item later
        state.OLD_PLAYER_STATES[playerid] = dict(status)
        # Stop transcoding
        if status['playmethod'] == 'Transcode':
            LOG.debug('Tell the PMS to stop transcoding')
            DU().downloadUrl(
                '{server}/video/:/transcode/universal/stop',
                parameters={'session': v.PKC_MACHINE_IDENTIFIER})
        # Kodi will not clear the playqueue (because there is not really any)
        # if there is only 1 item in it
        if len(PQ.PLAYQUEUES[playerid].items) == 1:
            PQ.PLAYQUEUES[playerid].clear()
        # Reset the player's status
        status = dict(state.PLAYSTATE)
    # As all playback has halted, reset the players that have been active
    state.ACTIVE_PLAYERS = []
    LOG.debug('Finished PKC playback cleanup')
Ejemplo n.º 4
0
def init_Plex_playlist(playlist, plex_id=None, kodi_item=None):
    """
    Initializes the Plex side without changing the Kodi playlists
    WILL ALSO UPDATE OUR PLAYLISTS. 

    Returns the first PKC playlist item or raises PlaylistError
    """
    LOG.debug('Initializing the playlist on the Plex side: %s', playlist)
    playlist.clear(kodi=False)
    try:
        if plex_id:
            item = playlist_item_from_plex(plex_id)
        else:
            item = playlist_item_from_kodi(kodi_item)
        params = {
            'next': 0,
            'type': playlist.type,
            'uri': item.uri
        }
        xml = DU().downloadUrl(url="{server}/%ss" % playlist.kind,
                               action_type="POST",
                               parameters=params)
        get_playlist_details_from_xml(playlist, xml)
        # Need to get the details for the playlist item
        item = playlist_item_from_xml(playlist, xml[0])
    except (KeyError, IndexError, TypeError):
        raise PlaylistError('Could not init Plex playlist with plex_id %s and '
                            'kodi_item %s' % (plex_id, kodi_item))
    playlist.items.append(item)
    LOG.debug('Initialized the playlist on the Plex side: %s', playlist)
    return item
Ejemplo n.º 5
0
def move_playlist_item(playlist, before_pos, after_pos):
    """
    Moves playlist item from before_pos [int] to after_pos [int] for Plex only.

    WILL ALSO CHANGE OUR PLAYLISTS. Returns True if successful
    """
    log.debug('Moving item from %s to %s on the Plex side for %s' %
              (before_pos, after_pos, playlist))
    if after_pos == 0:
        url = "{server}/%ss/%s/items/%s/move?after=0" % \
              (playlist.kind,
               playlist.ID,
               playlist.items[before_pos].ID)
    else:
        url = "{server}/%ss/%s/items/%s/move?after=%s" % \
              (playlist.kind,
               playlist.ID,
               playlist.items[before_pos].ID,
               playlist.items[after_pos - 1].ID)
    # We need to increment the playlistVersion
    if _get_playListVersion_from_xml(playlist,
                                     DU().downloadUrl(
                                         url, action_type="PUT")) is False:
        return False
    # Move our item's position in our internal playlist
    playlist.items.insert(after_pos, playlist.items.pop(before_pos))
    log.debug('Done moving for %s' % playlist)
    return True
Ejemplo n.º 6
0
def move_playlist_item(playlist, before_pos, after_pos):
    """
    Moves playlist item from before_pos [int] to after_pos [int] for Plex only.

    WILL ALSO CHANGE OUR PLAYLISTS.
    """
    LOG.debug('Moving item from %s to %s on the Plex side for %s',
              before_pos, after_pos, playlist)
    if after_pos == 0:
        url = "{server}/%ss/%s/items/%s/move?after=0" % \
              (playlist.kind,
               playlist.id,
               playlist.items[before_pos].id)
    else:
        url = "{server}/%ss/%s/items/%s/move?after=%s" % \
              (playlist.kind,
               playlist.id,
               playlist.items[before_pos].id,
               playlist.items[after_pos - 1].id)
    # We need to increment the playlistVersion
    _get_playListVersion_from_xml(
        playlist, DU().downloadUrl(url, action_type="PUT"))
    # Move our item's position in our internal playlist
    playlist.items.insert(after_pos, playlist.items.pop(before_pos))
    LOG.debug('Done moving for %s', playlist)
Ejemplo n.º 7
0
def list_home_users(token):
    """
    Returns a list for myPlex home users for the current plex.tv account.

    Input:
        token for plex.tv
    Output:
        List of users, where one entry is of the form:
            "id": userId,
            "admin": '1'/'0',
            "guest": '1'/'0',
            "restricted": '1'/'0',
            "protected": '1'/'0',
            "email": email,
            "title": title,
            "username": username,
            "thumb": thumb_url
        }
    If any value is missing, None is returned instead (or "" from plex.tv)
    If an error is encountered, False is returned
    """
    xml = DU().downloadUrl('https://plex.tv/api/home/users/',
                           authenticate=False,
                           headerOptions={'X-Plex-Token': token})
    try:
        xml.attrib
    except AttributeError:
        LOG.error('Download of Plex home users failed.')
        return False
    users = []
    for user in xml:
        users.append(user.attrib)
    return users
Ejemplo n.º 8
0
def get_PMS_settings(url, token):
    """
    Retrieve the PMS' settings via <url>/:/prefs

    Call with url: scheme://ip:port
    """
    return DU().downloadUrl(
        '%s/:/prefs' % url,
        authenticate=False,
        verifySSL=False,
        headerOptions={'X-Plex-Token': token} if token else None)
Ejemplo n.º 9
0
def delete_playlist_item_from_PMS(playlist, pos):
    """
    Delete the item at position pos [int] on the Plex side and our playlists
    """
    log.debug('Deleting position %s for %s on the Plex side' % (pos, playlist))
    xml = DU().downloadUrl(
        "{server}/%ss/%s/items/%s?repeat=%s" %
        (playlist.kind, playlist.ID, playlist.items[pos].ID, playlist.repeat),
        action_type="DELETE")
    _get_playListVersion_from_xml(playlist, xml)
    del playlist.items[pos]
Ejemplo n.º 10
0
def check_pin(identifier):
    """
    Checks with plex.tv whether user entered the correct PIN on plex.tv/pin

    Returns False if not yet done so, or the XML response file as etree
    """
    # Try to get a temporary token
    xml = DU().downloadUrl('https://plex.tv/pins/%s.xml' % identifier,
                           authenticate=False)
    try:
        temp_token = xml.find('auth_token').text
    except AttributeError:
        LOG.error("Could not find token in plex.tv answer")
        return False
    if not temp_token:
        return False
    # Use temp token to get the final plex credentials
    xml = DU().downloadUrl('https://plex.tv/users/account',
                           authenticate=False,
                           parameters={'X-Plex-Token': temp_token})
    return xml
Ejemplo n.º 11
0
def get_pms_playqueue(playqueue_id):
    """
    Returns the Plex playqueue as an etree XML or None if unsuccessful
    """
    xml = DU().downloadUrl("{server}/playQueues/%s" % playqueue_id,
                           headerOptions={'Accept': 'application/xml'})
    try:
        xml.attrib
    except AttributeError:
        log.error('Could not download Plex playqueue %s' % playqueue_id)
        xml = None
    return xml
Ejemplo n.º 12
0
def check_connection(url, token=None, verifySSL=None):
    """
    Checks connection to a Plex server, available at url. Can also be used
    to check for connection with plex.tv.

    Override SSL to skip the check by setting verifySSL=False
    if 'None', SSL will be checked (standard requests setting)
    if 'True', SSL settings from file settings are used (False/True)

    Input:
        url         URL to Plex server (e.g. https://192.168.1.1:32400)
        token       appropriate token to access server. If None is passed,
                    the current token is used
    Output:
        False       if server could not be reached or timeout occured
        200         if connection was successfull
        int         or other HTML status codes as received from the server
    """
    # Add '/clients' to URL because then an authentication is necessary
    # If a plex.tv URL was passed, this does not work.
    header_options = None
    if token is not None:
        header_options = {'X-Plex-Token': token}
    if verifySSL is True:
        verifySSL = None if settings('sslverify') == 'true' else False
    if 'plex.tv' in url:
        url = 'https://plex.tv/api/home/users'
    else:
        url = url + '/library/onDeck'
    LOG.debug("Checking connection to server %s with verifySSL=%s",
              url, verifySSL)
    answer = DU().downloadUrl(url,
                              authenticate=False,
                              headerOptions=header_options,
                              verifySSL=verifySSL,
                              timeout=10)
    if answer is None:
        LOG.debug("Could not connect to %s", url)
        return False
    try:
        # xml received?
        answer.attrib
    except AttributeError:
        if answer is True:
            # Maybe no xml but connection was successful nevertheless
            answer = 200
    else:
        # Success - we downloaded an xml!
        answer = 200
    # We could connect but maybe were not authenticated. No worries
    LOG.debug("Checking connection successfull. Answer: %s", answer)
    return answer
Ejemplo n.º 13
0
def delete_item_from_pms(plexid):
    """
    Deletes the item plexid from the Plex Media Server (and the harddrive!).
    Do make sure that the currently logged in user has the credentials

    Returns True if successful, False otherwise
    """
    if DU().downloadUrl('{server}/library/metadata/%s' % plexid,
                        action_type="DELETE") is True:
        LOG.info('Successfully deleted Plex id %s from the PMS', plexid)
        return True
    LOG.error('Could not delete Plex id %s from the PMS', plexid)
    return False
Ejemplo n.º 14
0
def get_PMS_playlist(playlist, playlist_id=None):
    """
    Fetches the PMS playlist/playqueue as an XML. Pass in playlist_id if we
    need to fetch a new playlist

    Returns None if something went wrong
    """
    playlist_id = playlist_id if playlist_id else playlist.ID
    xml = DU().downloadUrl("{server}/%ss/%s" % (playlist.kind, playlist_id),
                           headerOptions={'Accept': 'application/xml'})
    try:
        xml.attrib['%sID' % playlist.kind]
    except (AttributeError, KeyError):
        xml = None
    return xml
Ejemplo n.º 15
0
def DownloadChunks(url):
    """
    Downloads PMS url in chunks of CONTAINERSIZE.

    url MUST end with '?' (if no other url encoded args are present) or '&'

    Returns a stitched-together xml or None.
    """
    xml = None
    pos = 0
    error_counter = 0
    while error_counter < 10:
        args = {
            'X-Plex-Container-Size': CONTAINERSIZE,
            'X-Plex-Container-Start': pos
        }
        xmlpart = DU().downloadUrl(url + urlencode(args))
        # If something went wrong - skip in the hope that it works next time
        try:
            xmlpart.attrib
        except AttributeError:
            LOG.error('Error while downloading chunks: %s',
                      url + urlencode(args))
            pos += CONTAINERSIZE
            error_counter += 1
            continue

        # Very first run: starting xml (to retain data in xml's root!)
        if xml is None:
            xml = deepcopy(xmlpart)
            if len(xmlpart) < CONTAINERSIZE:
                break
            else:
                pos += CONTAINERSIZE
                continue
        # Build answer xml - containing the entire library
        for child in xmlpart:
            xml.append(child)
        # Done as soon as we don't receive a full complement of items
        if len(xmlpart) < CONTAINERSIZE:
            break
        pos += CONTAINERSIZE
    if error_counter == 10:
        LOG.error('Fatal error while downloading chunks for %s', url)
        return None
    return xml
Ejemplo n.º 16
0
def scrobble(ratingKey, state):
    """
    Tells the PMS to set an item's watched state to state="watched" or
    state="unwatched"
    """
    args = {
        'key': ratingKey,
        'identifier': 'com.plexapp.plugins.library'
    }
    if state == "watched":
        url = "{server}/:/scrobble?" + urlencode(args)
    elif state == "unwatched":
        url = "{server}/:/unscrobble?" + urlencode(args)
    else:
        return
    DU().downloadUrl(url)
    LOG.info("Toggled watched state for Plex item %s", ratingKey)
Ejemplo n.º 17
0
def GetMachineIdentifier(url):
    """
    Returns the unique PMS machine identifier of url

    Returns None if something went wrong
    """
    xml = DU().downloadUrl('%s/identity' % url,
                           authenticate=False,
                           verifySSL=False,
                           timeout=10)
    try:
        machineIdentifier = xml.attrib['machineIdentifier']
    except (AttributeError, KeyError):
        LOG.error('Could not get the PMS machineIdentifier for %s', url)
        return None
    LOG.debug('Found machineIdentifier %s for the PMS %s',
              machineIdentifier, url)
    return machineIdentifier
Ejemplo n.º 18
0
    def __init__(self):
        self.__dict__ = self.__shared_state

        self.auth = True
        self.retry = 0

        self.currUser = None
        self.currServer = None
        self.currToken = None
        self.HasAccess = True
        self.AdditionalUser = []

        self.userSettings = None

        self.addon = xbmcaddon.Addon()
        self.doUtils = DU()

        Thread.__init__(self)
Ejemplo n.º 19
0
    def check_plex_tv_sign_in(self):
        """
        Checks existing connection to plex.tv. If not, triggers sign in

        Returns True if signed in, False otherwise
        """
        answer = True
        chk = PF.check_connection('plex.tv', token=self.plex_token)
        if chk in (401, 403):
            # HTTP Error: unauthorized. Token is no longer valid
            LOG.info('plex.tv connection returned HTTP %s', str(chk))
            # Delete token in the settings
            settings('plexToken', value='')
            settings('plexLogin', value='')
            # Could not login, please try again
            dialog('ok', lang(29999), lang(39009))
            answer = self.plex_tv_sign_in()
        elif chk is False or chk >= 400:
            # Problems connecting to plex.tv. Network or internet issue?
            LOG.info(
                'Problems connecting to plex.tv; connection returned '
                'HTTP %s', str(chk))
            dialog('ok', lang(29999), lang(39010))
            answer = False
        else:
            LOG.info('plex.tv connection with token successful')
            settings('plex_status', value=lang(39227))
            # Refresh the info from Plex.tv
            xml = DU().downloadUrl(
                'https://plex.tv/users/account',
                authenticate=False,
                headerOptions={'X-Plex-Token': self.plex_token})
            try:
                self.plex_login = xml.attrib['title']
            except (AttributeError, KeyError):
                LOG.error('Failed to update Plex info from plex.tv')
            else:
                settings('plexLogin', value=self.plex_login)
                home = 'true' if xml.attrib.get('home') == '1' else 'false'
                settings('plexhome', value=home)
                settings('plexAvatar', value=xml.attrib.get('thumb'))
                settings('plexHomeSize', value=xml.attrib.get('homeSize', '1'))
                LOG.info('Updated Plex info from plex.tv')
        return answer
Ejemplo n.º 20
0
def get_pin():
    """
    For plex.tv sign-in: returns 4-digit code and identifier as 2 str
    """
    code = None
    identifier = None
    # Download
    xml = DU().downloadUrl('https://plex.tv/pins.xml',
                           authenticate=False,
                           action_type="POST")
    try:
        xml.attrib
    except AttributeError:
        LOG.error("Error, no PIN from plex.tv provided")
        return None, None
    code = xml.find('code').text
    identifier = xml.find('id').text
    LOG.info('Successfully retrieved code and id from plex.tv')
    return code, identifier
Ejemplo n.º 21
0
def init_Plex_playlist(playlist, plex_id=None, kodi_item=None):
    """
    Initializes the Plex side without changing the Kodi playlists

    WILL ALSO UPDATE OUR PLAYLISTS
    """
    log.debug('Initializing the playlist %s on the Plex side' % playlist)
    if plex_id:
        item = playlist_item_from_plex(plex_id)
    else:
        item = playlist_item_from_kodi(kodi_item)
    params = {'next': 0, 'type': playlist.type, 'uri': item.uri}
    xml = DU().downloadUrl(url="{server}/%ss" % playlist.kind,
                           action_type="POST",
                           parameters=params)
    get_playlist_details_from_xml(playlist, xml)
    item.ID = xml[-1].attrib['%sItemID' % playlist.kind]
    playlist.items.append(item)
    log.debug('Initialized the playlist on the Plex side: %s' % playlist)
Ejemplo n.º 22
0
def add_item_to_PMS_playlist(playlist, pos, plex_id=None, kodi_item=None):
    """
    Adds a new item to the playlist at position pos [int] only on the Plex
    side of things (e.g. because the user changed the Kodi side)

    WILL ALSO UPDATE OUR PLAYLISTS
    """
    log.debug('Adding new item plex_id: %s, kodi_item: %s on the Plex side at '
              'position %s for %s' % (plex_id, kodi_item, pos, playlist))
    if plex_id:
        try:
            item = playlist_item_from_plex(plex_id)
        except KeyError:
            log.error('Could not add new item to the PMS playlist')
            return
    else:
        item = playlist_item_from_kodi(kodi_item)
    url = "{server}/%ss/%s?uri=%s" % (playlist.kind, playlist.ID, item.uri)
    # Will always put the new item at the end of the Plex playlist
    xml = DU().downloadUrl(url, action_type="PUT")
    try:
        item.ID = xml[-1].attrib['%sItemID' % playlist.kind]
    except IndexError:
        log.info('Could not get playlist children. Adding a dummy')
    except (TypeError, AttributeError, KeyError):
        log.error('Could not add item %s to playlist %s' %
                  (kodi_item, playlist))
        return
    # Get the guid for this item
    for plex_item in xml:
        if plex_item.attrib['%sItemID' % playlist.kind] == item.ID:
            item.guid = plex_item.attrib['guid']
    playlist.items.append(item)
    if pos == len(playlist.items) - 1:
        # Item was added at the end
        _get_playListVersion_from_xml(playlist, xml)
    else:
        # Move the new item to the correct position
        move_playlist_item(playlist, len(playlist.items) - 1, pos)
    log.debug('Successfully added item on the Plex side: %s' % playlist)
Ejemplo n.º 23
0
def _poke_pms(pms, queue):
    data = pms['connections'][0].attrib
    if data['local'] == '1':
        protocol = data['protocol']
        address = data['address']
        port = data['port']
        url = '%s://%s:%s' % (protocol, address, port)
    else:
        url = data['uri']
        if url.count(':') == 1:
            url = '%s:%s' % (url, data['port'])
        protocol, address, port = url.split(':', 2)
        address = address.replace('/', '')
    xml = DU().downloadUrl('%s/identity' % url,
                           authenticate=False,
                           headerOptions={'X-Plex-Token': pms['token']},
                           verifySSL=False,
                           timeout=10)
    try:
        xml.attrib['machineIdentifier']
    except (AttributeError, KeyError):
        # No connection, delete the one we just tested
        del pms['connections'][0]
        if pms['connections']:
            # Still got connections left, try them
            return _poke_pms(pms, queue)
        return
    else:
        # Connection successful - correct pms?
        if xml.get('machineIdentifier') == pms['machineIdentifier']:
            # process later
            pms['baseURL'] = url
            pms['protocol'] = protocol
            pms['ip'] = address
            pms['port'] = port
            queue.put(pms)
            return
    LOG.info('Found a pms at %s, but the expected machineIdentifier of '
             '%s did not match the one we found: %s',
             url, pms['uuid'], xml.get('machineIdentifier'))
Ejemplo n.º 24
0
def init_Plex_playlist(playlist, plex_id=None, kodi_item=None):
    """
    Initializes the Plex side without changing the Kodi playlists

    WILL ALSO UPDATE OUR PLAYLISTS
    """
    log.debug('Initializing the playlist %s on the Plex side' % playlist)
    try:
        if plex_id:
            item = playlist_item_from_plex(plex_id)
        else:
            item = playlist_item_from_kodi(kodi_item)
        params = {'next': 0, 'type': playlist.type, 'uri': item.uri}
        xml = DU().downloadUrl(url="{server}/%ss" % playlist.kind,
                               action_type="POST",
                               parameters=params)
        get_playlist_details_from_xml(playlist, xml)
    except KeyError:
        log.error('Could not init Plex playlist')
        return
    playlist.items.append(item)
    log.debug('Initialized the playlist on the Plex side: %s' % playlist)
Ejemplo n.º 25
0
def GetPlexMetadata(key):
    """
    Returns raw API metadata for key as an etree XML.

    Can be called with either Plex key '/library/metadata/xxxx'metadata
    OR with the digits 'xxxx' only.

    Returns None or 401 if something went wrong
    """
    key = str(key)
    if '/library/metadata/' in key:
        url = "{server}" + key
    else:
        url = "{server}/library/metadata/" + key
    arguments = {
        'checkFiles': 0,
        'includeExtras': 1,         # Trailers and Extras => Extras
        'includeReviews': 1,
        'includeRelated': 0,        # Similar movies => Video -> Related
        # 'includeRelatedCount': 0,
        # 'includeOnDeck': 1,
        # 'includeChapters': 1,
        # 'includePopularLeaves': 1,
        # 'includeConcerts': 1
    }
    url = url + '?' + urlencode(arguments)
    xml = DU().downloadUrl(url)
    if xml == 401:
        # Either unauthorized (taken care of by doUtils) or PMS under strain
        return 401
    # Did we receive a valid XML?
    try:
        xml.attrib
    # Nope we did not receive a valid XML
    except AttributeError:
        LOG.error("Error retrieving metadata for %s", url)
        xml = None
    return xml
Ejemplo n.º 26
0
def GetPMSStatus(token):
    """
    token:                  Needs to be authorized with a master Plex token
                            (not a managed user token)!
    Calls /status/sessions on currently active PMS. Returns a dict with:

    'sessionKey':
    {
        'userId':           Plex ID of the user (if applicable, otherwise '')
        'username':         Plex name (if applicable, otherwise '')
        'ratingKey':        Unique Plex id of item being played
    }

    or an empty dict.
    """
    answer = {}
    xml = DU().downloadUrl('{server}/status/sessions',
                           headerOptions={'X-Plex-Token': token})
    try:
        xml.attrib
    except AttributeError:
        return answer
    for item in xml:
        ratingKey = item.attrib.get('ratingKey')
        sessionKey = item.attrib.get('sessionKey')
        userId = item.find('User')
        username = ''
        if userId is not None:
            username = userId.attrib.get('title', '')
            userId = userId.attrib.get('id', '')
        else:
            userId = ''
        answer[sessionKey] = {
            'userId': userId,
            'username': username,
            'ratingKey': ratingKey
        }
    return answer
Ejemplo n.º 27
0
def init_plex_playqueue(itemid, librarySectionUUID, mediatype='movie',
                        trailers=False):
    """
    Returns raw API metadata XML dump for a playlist with e.g. trailers.
   """
    url = "{server}/playQueues"
    args = {
        'type': mediatype,
        'uri': ('library://' + librarySectionUUID +
                '/item/%2Flibrary%2Fmetadata%2F' + itemid),
        'includeChapters': '1',
        'shuffle': '0',
        'repeat': '0'
    }
    if trailers is True:
        args['extrasPrefixCount'] = settings('trailerNumber')
    xml = DU().downloadUrl(url + '?' + urlencode(args), action_type="POST")
    try:
        xml[0].tag
    except (IndexError, TypeError, AttributeError):
        LOG.error("Error retrieving metadata for %s", url)
        return None
    return xml
Ejemplo n.º 28
0
def add_item_to_PMS_playlist(playlist, pos, plex_id=None, kodi_item=None):
    """
    Adds a new item to the playlist at position pos [int] only on the Plex
    side of things (e.g. because the user changed the Kodi side)
    WILL ALSO UPDATE OUR PLAYLISTS

    Returns the PKC PlayList item or raises PlaylistError
    """
    verify_kodi_item(plex_id, kodi_item)
    if plex_id:
        item = playlist_item_from_plex(plex_id)
    else:
        item = playlist_item_from_kodi(kodi_item)
    url = "{server}/%ss/%s?uri=%s" % (playlist.kind, playlist.id, item.uri)
    # Will always put the new item at the end of the Plex playlist
    xml = DU().downloadUrl(url, action_type="PUT")
    try:
        xml[-1].attrib
    except (TypeError, AttributeError, KeyError, IndexError):
        raise PlaylistError('Could not add item %s to playlist %s' %
                            (kodi_item, playlist))
    api = API(xml[-1])
    item.xml = xml[-1]
    item.id = api.item_id()
    item.guid = api.guid_html_escaped()
    item.offset = api.resume_point()
    item.playcount = api.viewcount()
    playlist.items.append(item)
    if pos == len(playlist.items) - 1:
        # Item was added at the end
        _get_playListVersion_from_xml(playlist, xml)
    else:
        # Move the new item to the correct position
        move_playlist_item(playlist, len(playlist.items) - 1, pos)
    LOG.debug('Successfully added item on the Plex side: %s', playlist)
    return item
Ejemplo n.º 29
0
def process_indirect(key, offset, resolve=True):
    """
    Called e.g. for Plex "Play later" - Plex items where we need to fetch an
    additional xml for the actual playurl. In the PMS metadata, indirect="1" is
    set.

    Will release default.py with setResolvedUrl

    Set resolve to False if playback should be kicked off directly, not via
    setResolvedUrl
    """
    LOG.info('process_indirect called with key: %s, offset: %s', key, offset)
    result = Playback_Successful()
    if key.startswith('http') or key.startswith('{server}'):
        xml = DU().downloadUrl(key)
    elif key.startswith('/system/services'):
        xml = DU().downloadUrl('http://node.plexapp.com:32400%s' % key)
    else:
        xml = DU().downloadUrl('{server}%s' % key)
    try:
        xml[0].attrib
    except (TypeError, IndexError, AttributeError):
        LOG.error('Could not download PMS metadata')
        if resolve is True:
            # Release default.py
            pickle_me(result)
        return
    if offset != '0':
        offset = int(v.PLEX_TO_KODI_TIMEFACTOR * float(offset))
        # Todo: implement offset
    api = API(xml[0])
    listitem = PKC_ListItem()
    api.CreateListItemFromPlexItem(listitem)
    playqueue = PQ.get_playqueue_from_type(
        v.KODI_PLAYLIST_TYPE_FROM_PLEX_TYPE[api.getType()])
    playqueue.clear()
    item = PL.Playlist_Item()
    item.xml = xml[0]
    item.offset = int(offset)
    item.plex_type = v.PLEX_TYPE_CLIP
    item.playmethod = 'DirectStream'
    # Need to get yet another xml to get the final playback url
    xml = DU().downloadUrl('http://node.plexapp.com:32400%s' %
                           xml[0][0][0].attrib['key'])
    try:
        xml[0].attrib
    except (TypeError, IndexError, AttributeError):
        LOG.error('Could not download last xml for playurl')
        if resolve is True:
            # Release default.py
            pickle_me(result)
        return
    playurl = xml[0].attrib['key']
    item.file = playurl
    listitem.setPath(tryEncode(playurl))
    playqueue.items.append(item)
    if resolve is True:
        result.listitem = listitem
        pickle_me(result)
    else:
        thread = Thread(target=Player().play,
                        args={
                            'item': tryEncode(playurl),
                            'listitem': listitem
                        })
        thread.setDaemon(True)
        LOG.info('Done initializing PKC playback, starting Kodi player')
        thread.start()
Ejemplo n.º 30
0
def get_plex_sections():
    """
    Returns all Plex sections (libraries) of the PMS as an etree xml
    """
    return DU().downloadUrl('{server}/library/sections')