def chooseServer():
    """
    Lets user choose from list of PMS
    """
    log.info("Choosing PMS server requested, starting")

    import initialsetup
    setup = initialsetup.InitialSetup()
    server = setup.pick_pms(showDialog=True)
    if server is None:
        log.error('We did not connect to a new PMS, aborting')
        plex_command('SUSPEND_USER_CLIENT', 'False')
        plex_command('SUSPEND_LIBRARY_THREAD', 'False')
        return

    log.info("User chose server %s" % server['name'])
    setup.write_pms_to_settings(server)

    if not __LogOut():
        return

    from utils import wipe_database
    # Wipe Kodi and Plex database as well as playlists and video nodes
    wipe_database()

    # Log in again
    __LogIn()
    log.info("Choosing new PMS complete")
    # '<PMS> connected'
    dialog('notification',
           lang(29999),
           '%s %s' % (server['name'], lang(39220)),
           icon='{plex}',
           time=3000,
           sound=False)
Exemple #2
0
    def _play(cls, data):

        item_ids = data['ItemIds']
        command = data['PlayCommand']

        playlist_ = playlist.Playlist()

        if command == 'PlayNow':
            startat = data.get('StartPositionTicks', 0)
            playlist_.play_all(item_ids, startat)
            dialog(type_="notification",
                   heading="{emby}",
                   message="%s %s" % (len(item_ids), lang(33004)),
                   icon="{emby}",
                   sound=False)

        elif command == 'PlayNext':
            new_playlist = playlist_.modify_playlist(item_ids)
            dialog(type_="notification",
                   heading="{emby}",
                   message="%s %s" % (len(item_ids), lang(33005)),
                   icon="{emby}",
                   sound=False)
            player = xbmc.Player()
            if not player.isPlaying():
                # Only start the playlist if nothing is playing
                player.play(new_playlist)
Exemple #3
0
    def texture_cache_sync(self):
        # This method will sync all Kodi artwork to textures13.db
        # and cache them locally. This takes diskspace!
        if not dialog(type_="yesno",
                      heading="{emby}",
                      line1=lang(33042)):
            return

        log.info("Doing Image Cache Sync")

        pdialog = xbmcgui.DialogProgress()
        pdialog.create(lang(29999), lang(33043))

        # ask to rest all existing or not
        if dialog(type_="yesno", heading="{emby}", line1=lang(33044)):
            log.info("Resetting all cache data first")
            self.delete_cache()

        # Cache all entries in video DB
        self._cache_all_video_entries(pdialog)
        # Cache all entries in music DB
        self._cache_all_music_entries(pdialog)

        pdialog.update(100, "%s %s" % (lang(33046), len(self.image_cache_threads)))
        log.info("Waiting for all threads to exit")

        while len(self.image_cache_threads):
            for thread in self.image_cache_threads:
                if thread.is_finished:
                    self.image_cache_threads.remove(thread)
            pdialog.update(100, "%s %s" % (lang(33046), len(self.image_cache_threads)))
            log.info("Waiting for all threads to exit: %s", len(self.image_cache_threads))
            xbmc.sleep(500)

        pdialog.close()
    def _startup(self):

        serverId = settings('serverId')
        if (serverId != None):
            serverId = hashlib.md5(serverId).hexdigest()

        ga = GoogleAnalytics()
        ga.sendEventData("Application", "Startup", serverId)
        try:
            ga.sendEventData("Version", "OS", platform.platform())
            ga.sendEventData("Version", "Python", platform.python_version())
        except Exception:
            pass

        # Start up events
        self.warn_auth = True

        username = self.userclient_thread.get_username()
        if settings('connectMsg') == "true" and username:
            # Get additional users
            add_users = settings('additionalUsers')
            if add_users:
                add_users = ", " + ", ".join(add_users.split(','))

            dialog(type_="notification",
                   heading="{emby}",
                   message=("%s %s%s" % (lang(33000), username.decode('utf-8'),
                                         add_users.decode('utf-8'))),
                   icon="{emby}",
                   time=2000,
                   sound=False)
        return True
    def _startup(self):
        
        serverId = settings('serverId')
        if(serverId != None):
            serverId = hashlib.md5(serverId).hexdigest()
        
        ga = GoogleAnalytics()
        ga.sendEventData("Application", "Startup", serverId)
        try:
            ga.sendEventData("Version", "OS", platform.platform())
            ga.sendEventData("Version", "Python", platform.python_version())
        except Exception:
            pass

        # Start up events
        self.warn_auth = True

        username = self.userclient_thread.get_username()
        if settings('connectMsg') == "true" and username:
            # Get additional users
            add_users = settings('additionalUsers')
            if add_users:
                add_users = ", "+", ".join(add_users.split(','))

            dialog(type_="notification",
                   heading="{emby}",
                   message=("%s %s%s"
                            % (lang(33000), username.decode('utf-8'),
                               add_users.decode('utf-8'))),
                   icon="{emby}",
                   time=2000,
                   sound=False)
        return True
Exemple #6
0
    def _server_restarting(cls):

        if settings('supressRestartMsg') == "true":
            dialog(type_="notification",
                   heading="{emby}",
                   message=lang(33006),
                   icon="{emby}")
        window('emby_online', value="false")
Exemple #7
0
    def _auto_pick_pms(self):
        """
        Will try to pick PMS based on machineIdentifier saved in file settings
        but only once

        Returns server or None if unsuccessful
        """
        https_updated = False
        checked_plex_tv = False
        server = None
        while True:
            if https_updated is False:
                serverlist = PF.discover_pms(self.plex_token)
                for item in serverlist:
                    if item.get('machineIdentifier') == self.serverid:
                        server = item
                if server is None:
                    name = settings('plex_servername')
                    LOG.warn(
                        'The PMS you have used before with a unique '
                        'machineIdentifier of %s and name %s is '
                        'offline', self.serverid, name)
                    return
            chk = self._check_pms_connectivity(server)
            if chk == 504 and https_updated is False:
                # switch HTTPS to HTTP or vice-versa
                if server['scheme'] == 'https':
                    server['scheme'] = 'http'
                else:
                    server['scheme'] = 'https'
                https_updated = True
                continue
            if chk == 401:
                LOG.warn('Not yet authorized for Plex server %s',
                         server['name'])
                if self.check_plex_tv_sign_in() is True:
                    if checked_plex_tv is False:
                        # Try again
                        checked_plex_tv = True
                        https_updated = False
                        continue
                    else:
                        LOG.warn('Not authorized even though we are signed '
                                 ' in to plex.tv correctly')
                        dialog(
                            'ok', lang(29999), '%s %s' %
                            (lang(39214), try_encode(server['name'])))
                        return
                else:
                    return
            # Problems connecting
            elif chk >= 400 or chk is False:
                LOG.warn('Problems connecting to server %s. chk is %s',
                         server['name'], chk)
                return
            LOG.info('We found a server to automatically connect to: %s',
                     server['name'])
            return server
Exemple #8
0
def playback_init(plex_id, plex_type, playqueue):
    """
    Playback setup if Kodi starts playing an item for the first time.
    """
    LOG.info('Initializing PKC playback')
    xml = GetPlexMetadata(plex_id)
    try:
        xml[0].attrib
    except (IndexError, TypeError, AttributeError):
        LOG.error('Could not get a PMS xml for plex id %s', plex_id)
        # "Play error"
        dialog('notification', lang(29999), lang(30128), icon='{error}')
        return
    trailers = False
    api = API(xml[0])
    if (plex_type == v.PLEX_TYPE_MOVIE and not api.getResume()
            and settings('enableCinema') == "true"):
        if settings('askCinema') == "true":
            # "Play trailers?"
            trailers = dialog('yesno', lang(29999), lang(33016))
            trailers = True if trailers else False
        else:
            trailers = True
    LOG.debug('Playing trailers: %s', trailers)
    playqueue.clear()
    if plex_type != v.PLEX_TYPE_CLIP:
        # Post to the PMS to create a playqueue - in any case due to Companion
        xml = init_plex_playqueue(plex_id,
                                  xml.attrib.get('librarySectionUUID'),
                                  mediatype=plex_type,
                                  trailers=trailers)
        if xml is None:
            LOG.error('Could not get a playqueue xml for plex id %s, UUID %s',
                      plex_id, xml.attrib.get('librarySectionUUID'))
            # "Play error"
            dialog('notification', lang(29999), lang(30128), icon='{error}')
            return
        # Should already be empty, but just in case
        PL.get_playlist_details_from_xml(playqueue, xml)
    stack = _prep_playlist_stack(xml)
    # Sleep a bit to let setResolvedUrl do its thing - bit ugly
    sleep(200)
    _process_stack(playqueue, stack)
    # Reset some playback variables
    state.CONTEXT_MENU_PLAY = False
    state.FORCE_TRANSCODE = False
    # New thread to release this one sooner (e.g. harddisk spinning up)
    thread = Thread(target=Player().play, args=(playqueue.kodi_pl, ))
    thread.setDaemon(True)
    LOG.info('Done initializing PKC playback, starting Kodi player')
    # By design, PKC will start Kodi playback using Player().play(). Kodi
    # caches paths like our plugin://pkc. If we use Player().play() between
    # 2 consecutive startups of exactly the same Kodi library item, Kodi's
    # cache will have been flushed for some reason. Hence the 2nd call for
    # plugin://pkc will be lost; Kodi will try to startup playback for an empty
    # path: log entry is "CGUIWindowVideoBase::OnPlayMedia <missing path>"
    thread.start()
 def content_pop(self, name):
     # It's possible for the time to be 0. It should be considered disabled in this case.
     if not self.pdialog and self.content_msg and self.new_time:
         dialog(type_="notification",
                heading="{emby}",
                message="%s %s" % (lang(33049), name),
                icon="{emby}",
                time=self.new_time,
                sound=False)
Exemple #10
0
    def fullTextureCacheSync(self):
        """
        This method will sync all Kodi artwork to textures13.db
        and cache them locally. This takes diskspace!
        """
        if not dialog('yesno', "Image Texture Cache", lang(39250)):
            return

        log.info("Doing Image Cache Sync")

        # ask to rest all existing or not
        if dialog('yesno', "Image Texture Cache", lang(39251)):
            log.info("Resetting all cache data first")
            # Remove all existing textures first
            path = translatePath("special://thumbnails/")
            if exists(path):
                rmtree(path, ignore_errors=True)

            # remove all existing data from texture DB
            connection = kodiSQL('texture')
            cursor = connection.cursor()
            query = 'SELECT tbl_name FROM sqlite_master WHERE type=?'
            cursor.execute(query, ('table', ))
            rows = cursor.fetchall()
            for row in rows:
                tableName = row[0]
                if tableName != "version":
                    query = "DELETE FROM ?"
                    cursor.execute(query, (tableName, ))
            connection.commit()
            connection.close()

        # Cache all entries in video DB
        connection = kodiSQL('video')
        cursor = connection.cursor()
        # dont include actors
        query = "SELECT url FROM art WHERE media_type != ?"
        cursor.execute(query, ('actor', ))
        result = cursor.fetchall()
        total = len(result)
        log.info("Image cache sync about to process %s video images" % total)
        connection.close()

        for url in result:
            self.cacheTexture(url[0])
        # Cache all entries in music DB
        connection = kodiSQL('music')
        cursor = connection.cursor()
        cursor.execute("SELECT url FROM art")
        result = cursor.fetchall()
        total = len(result)
        log.info("Image cache sync about to process %s music images" % total)
        connection.close()
        for url in result:
            self.cacheTexture(url[0])
 def _delete_item(self):
     """
     Delete item on PMS
     """
     delete = True
     if settings('skipContextMenu') != "true":
         if not dialog("yesno", heading="{plex}", line1=lang(33041)):
             LOG.info("User skipped deletion for: %s", self.plex_id)
             delete = False
     if delete:
         LOG.info("Deleting Plex item with id %s", self.plex_id)
         if delete_item_from_pms(self.plex_id) is False:
             dialog("ok", heading="{plex}", line1=lang(30414))
    def _delete_item(self):

        delete = True
        if settings('skipContextMenu') != "true":

            if not dialog("yesno", heading=lang(29999), line1=lang(33041)):
                log.info("User skipped deletion for: %s", self.item_id)
                delete = False

        if delete:
            log.info("Deleting Plex item with id %s", self.item_id)
            if delete_item_from_pms(self.item_id) is False:
                dialog("ok", heading="{plex}", line1=lang(30414))
    def _delete_item(self):

        delete = True
        if settings('skipContextMenu') != "true":

            if not dialog(type_="yesno", heading=addonName, line1=lang(33041)):
                log.info("User skipped deletion for: %s", self.item_id)
                delete = False

        if delete:
            log.info("Deleting Plex item with id %s", self.item_id)
            if delete_item_from_pms(self.item_id) is False:
                dialog(type_="ok", heading="{plex}", line1=lang(30414))
Exemple #14
0
 def deviceid(self):
     deviceId_old = window('plex_client_Id')
     from clientinfo import getDeviceId
     try:
         deviceId = getDeviceId(reset=True)
     except Exception as e:
         log.error('Failed to generate a new device Id: %s' % e)
         dialog('ok', lang(29999), lang(33032))
     else:
         log.info('Successfully removed old device ID: %s New deviceId:'
                  '%s' % (deviceId_old, deviceId))
         # 'Kodi will now restart to apply the changes'
         dialog('ok', lang(29999), lang(33033))
         executebuiltin('RestartApp')
Exemple #15
0
 def deviceid(self):
     deviceId_old = window('plex_client_Id')
     from clientinfo import getDeviceId
     try:
         deviceId = getDeviceId(reset=True)
     except Exception as e:
         log.error('Failed to generate a new device Id: %s' % e)
         dialog('ok', lang(29999), lang(33032))
     else:
         log.info('Successfully removed old device ID: %s New deviceId:'
                  '%s' % (deviceId_old, deviceId))
         # 'Kodi will now restart to apply the changes'
         dialog('ok', lang(29999), lang(33033))
         executebuiltin('RestartApp')
Exemple #16
0
    def _rate_song(self):

        conn = kodiSQL('music')
        cursor = conn.cursor()
        query = "SELECT rating FROM song WHERE idSong = ?"
        cursor.execute(query, (self.kodi_id, ))
        try:
            value = cursor.fetchone()[0]
            current_value = int(round(float(value), 0))
        except TypeError:
            pass
        else:
            new_value = dialog("numeric", 0, lang(30411), str(current_value))
            if new_value > -1:

                new_value = int(new_value)
                if new_value > 5:
                    new_value = 5

                if settings('enableUpdateSongRating') == "true":
                    musicutils.updateRatingToFile(new_value,
                                                  self.api.get_file_path())

                query = "UPDATE song SET rating = ? WHERE idSong = ?"
                cursor.execute(query, (
                    new_value,
                    self.kodi_id,
                ))
                conn.commit()
        finally:
            cursor.close()
    def _rate_song(self):

        conn = kodiSQL('music')
        cursor = conn.cursor()
        query = "SELECT rating FROM song WHERE idSong = ?"
        cursor.execute(query, (self.kodi_id,))
        try:
            value = cursor.fetchone()[0]
            current_value = int(round(float(value), 0))
        except TypeError:
            pass
        else:
            new_value = dialog("numeric", 0, lang(30411), str(current_value))
            if new_value > -1:

                new_value = int(new_value)
                if new_value > 5:
                    new_value = 5

                if settings('enableUpdateSongRating') == "true":
                    musicutils.updateRatingToFile(new_value, self.api.get_file_path())

                query = "UPDATE song SET rating = ? WHERE idSong = ?"
                cursor.execute(query, (new_value, self.kodi_id,))
                conn.commit()
        finally:
            cursor.close()
Exemple #18
0
def resetAuth():
    # User tried login and failed too many times
    resp = dialog('yesno', heading="{plex}", line1=lang(39206))
    if resp == 1:
        log.info("Reset login attempts.")
        window('plex_serverStatus', value="Auth")
    else:
        executebuiltin('Addon.OpenSettings(plugin.video.plexkodiconnect)')
Exemple #19
0
def resetAuth():
    # User tried login and failed too many times
    resp = dialog('yesno', heading="{plex}", line1=lang(39206))
    if resp == 1:
        log.info("Reset login attempts.")
        plex_command('PMS_STATUS', 'Auth')
    else:
        executebuiltin('Addon.OpenSettings(plugin.video.plexkodiconnect)')
def resetAuth():
    # User tried login and failed too many times
    resp = dialog('yesno', heading="{plex}", line1=lang(39206))
    if resp == 1:
        log.info("Reset login attempts.")
        window('plex_serverStatus', value="Auth")
    else:
        executebuiltin('Addon.OpenSettings(plugin.video.plexkodiconnect)')
Exemple #21
0
def playback_triage(plex_id=None, plex_type=None, path=None, resolve=True):
    """
    Hit this function for addon path playback, Plex trailers, etc.
    Will setup playback first, then on second call complete playback.

    Will set Playback_Successful() with potentially a PKC_ListItem() attached
    (to be consumed by setResolvedURL in default.py)

    If trailers or additional (movie-)parts are added, default.py is released
    and a completely new player instance is called with a new playlist. This
    circumvents most issues with Kodi & playqueues

    Set resolve to False if you do not want setResolvedUrl to be called on
    the first pass - e.g. if you're calling this function from the original
    service.py Python instance
    """
    LOG.info('playback_triage called with plex_id %s, plex_type %s, path %s',
             plex_id, plex_type, path)
    if not state.AUTHENTICATED:
        LOG.error('Not yet authenticated for PMS, abort starting playback')
        if resolve is True:
            # Release default.py
            pickle_me(Playback_Successful())
        # "Unauthorized for PMS"
        dialog('notification', lang(29999), lang(30017))
        return
    playqueue = PQ.get_playqueue_from_type(
        v.KODI_PLAYLIST_TYPE_FROM_PLEX_TYPE[plex_type])
    pos = js.get_position(playqueue.playlistid)
    # Can return -1 (as in "no playlist")
    pos = pos if pos != -1 else 0
    LOG.debug('playQueue position: %s for %s', pos, playqueue)
    # Have we already initiated playback?
    try:
        playqueue.items[pos]
    except IndexError:
        # Release our default.py before starting our own Kodi player instance
        if resolve is True:
            state.PKC_CAUSED_STOP = True
            result = Playback_Successful()
            result.listitem = PKC_ListItem(path='PKC_Dummy_Path_Which_Fails')
            pickle_me(result)
        playback_init(plex_id, plex_type, playqueue)
    else:
        # kick off playback on second pass
        conclude_playback(playqueue, pos)
Exemple #22
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
Exemple #23
0
    def _library_sync(cls, mode):

        if window('emby_online') != "true":
            # Server is not online, do not run the sync
            dialog(type_="ok", heading="{emby}", line1=lang(33034))
            log.warn("Not connected to the emby server")

        elif window('emby_dbScan') != "true":
            import librarysync
            library_sync = librarysync.LibrarySync()

            if mode == 'manualsync':
                librarysync.ManualSync().sync()
            elif mode == 'fastsync':
                library_sync.startSync()
            else:
                library_sync.fullSync(repair=True)
        else:
            log.warn("Database scan is already running")
Exemple #24
0
def emby_connect():

    # Login user to emby connect
    connect = connectmanager.ConnectManager()
    try:
        connectUser = connect.login_connect()
    except RuntimeError:
        return
    else:
        user = connectUser['User']
        token = connectUser['AccessToken']
        username = user['Name']
        dialog(type_="notification",
               heading="{emby}",
               message="%s %s" % (lang(33000), username.decode('utf-8')),
               icon=user.get('ImageUrl') or "{emby}",
               time=2000,
               sound=False)
        
        settings('connectUsername', value=username)
Exemple #25
0
 def play():
     """
     Start up playback_starter in main Python thread
     """
     # Put the request into the 'queue'
     plex_command('PLAY', argv[2])
     # Wait for the result
     while not pickl_window('plex_result'):
         sleep(50)
     result = unpickle_me()
     if result is None:
         log.error('Error encountered, aborting')
         dialog('notification',
                heading='{plex}',
                message=lang(30128),
                icon='{error}',
                time=3000)
         setResolvedUrl(HANDLE, False, ListItem())
     elif result.listitem:
         listitem = convert_PKC_to_listitem(result.listitem)
         setResolvedUrl(HANDLE, True, listitem)
Exemple #26
0
    def _library_sync(cls, mode):

        if window('emby_online') != "true":
            # Server is not online, do not run the sync
            dialog(type_="ok",
                   heading="{emby}",
                   line1=lang(33034))
            log.warn("Not connected to the emby server")

        elif window('emby_dbScan') != "true":
            import librarysync
            library_sync = librarysync.LibrarySync()

            if mode == 'manualsync':
                librarysync.ManualSync().sync()
            elif mode == 'fastsync':
                library_sync.startSync()
            else:
                library_sync.fullSync(repair=True)
        else:
            log.warn("Database scan is already running")
Exemple #27
0
    def _delete_item(self):

        delete = True
        if settings('skipContextMenu') != "true":

            if not dialog(type_="yesno", heading="{emby}", line1=lang(33041)):
                log.info("User skipped deletion for: %s", self.item_id)
                delete = False

        if delete:
            log.info("Deleting request: %s", self.item_id)
            self.emby.deleteItem(self.item_id)
Exemple #28
0
def emby_backup():
    # Create a backup at specified location
    path = settings('backupPath')

    # filename
    default_value = "Kodi%s.%s" % (xbmc.getInfoLabel('System.BuildVersion')[:2],
                                   xbmc.getInfoLabel('System.Date(dd-mm-yy)'))
    folder_name = dialog(type_="input",
                         heading=lang(33089),
                         defaultt=default_value)
    if not folder_name:
        return

    backup = os.path.join(path, folder_name)
    log.info("Backup: %s", backup)

    # Create directory
    if xbmcvfs.exists(backup+"\\"):
        log.info("Existing directory!")
        if not dialog(type_="yesno",
                      heading="{emby}",
                      line1=lang(33090)):
            return emby_backup()
        shutil.rmtree(backup)

    # Addon_data
    addon_data = xbmc.translatePath("special://profile/addon_data/emby.for.kodi").decode('utf-8')
    try:
        shutil.copytree(src=addon_data,
                        dst=os.path.join(backup, "addon_data", "emby.for.kodi"))
    except shutil.Error as error:
        log.error(error)

    # Database files
    database_folder = os.path.join(backup, "Database")
    if not xbmcvfs.mkdir(database_folder):
        try:
            os.makedirs(database_folder)
        except OSError as error:
            log.error(error)
            dialog(type_="ok",
                   heading="{emby}",
                   line1="Failed to create backup")
        return

    # Emby database
    emby_path = database.emby_database()
    xbmcvfs.copy(emby_path, os.path.join(database_folder, ntpath.basename(emby_path)))
    # Videos database
    video_path = database.video_database()
    xbmcvfs.copy(video_path, os.path.join(database_folder, ntpath.basename(video_path)))
    # Music database
    if settings('enableMusic') == "true":
        music_path = database.music_database()
        xbmcvfs.copy(music_path, os.path.join(database_folder, ntpath.basename(music_path)))

    dialog(type_="ok",
           heading="{emby}",
           line1="%s: %s" % (lang(33091), backup))
def togglePlexTV():
    if settings('plexToken'):
        log.info('Reseting plex.tv credentials in settings')
        settings('plexLogin', value="")
        settings('plexToken', value=""),
        settings('plexid', value="")
        settings('plexHomeSize', value="1")
        settings('plexAvatar', value="")
        settings('plex_status', value="Not logged in to plex.tv")

        window('plex_token', clear=True)
        window('plex_username', clear=True)
    else:
        log.info('Login to plex.tv')
        import initialsetup
        initialsetup.InitialSetup().PlexTVSignIn()
    dialog('notification',
           lang(29999),
           lang(39221),
           icon='{plex}',
           time=3000,
           sound=False)
Exemple #30
0
def togglePlexTV():
    if settings('plexToken'):
        log.info('Reseting plex.tv credentials in settings')
        settings('plexLogin', value="")
        settings('plexToken', value=""),
        settings('plexid', value="")
        settings('plexHomeSize', value="1")
        settings('plexAvatar', value="")
        settings('plex_status', value="Not logged in to plex.tv")

        window('plex_token', clear=True)
        window('plex_username', clear=True)
    else:
        log.info('Login to plex.tv')
        import initialsetup
        initialsetup.InitialSetup().PlexTVSignIn()
    dialog('notification',
           lang(29999),
           lang(39221),
           icon='{plex}',
           time=3000,
           sound=False)
 def _process_alexa(self, data):
     xml = GetPlexMetadata(data['key'])
     try:
         xml[0].attrib
     except (AttributeError, IndexError, TypeError):
         LOG.error('Could not download Plex metadata for: %s', data)
         return
     api = API(xml[0])
     if api.plex_type() == v.PLEX_TYPE_ALBUM:
         LOG.debug('Plex music album detected')
         PQ.init_playqueue_from_plex_children(
             api.plex_id(), transient_token=data.get('token'))
     elif data['containerKey'].startswith('/playQueues/'):
         _, container_key, _ = ParseContainerKey(data['containerKey'])
         xml = DownloadChunks('{server}/playQueues/%s?' % container_key)
         if xml is None:
             # "Play error"
             dialog('notification',
                    lang(29999),
                    lang(30128),
                    icon='{error}')
             return
         playqueue = PQ.get_playqueue_from_type(
             v.KODI_PLAYLIST_TYPE_FROM_PLEX_TYPE[api.plex_type()])
         playqueue.clear()
         get_playlist_details_from_xml(playqueue, xml)
         playqueue.plex_transient_token = data.get('token')
         if data.get('offset') != '0':
             offset = float(data['offset']) / 1000.0
         else:
             offset = None
         play_xml(playqueue, xml, offset)
     else:
         state.PLEX_TRANSIENT_TOKEN = data.get('token')
         if data.get('offset') != '0':
             state.RESUMABLE = True
             state.RESUME_PLAYBACK = True
         playback_triage(api.plex_id(), api.plex_type(), resolve=False)
Exemple #32
0
def togglePlexTV():
    if settings('plexToken'):
        log.info('Reseting plex.tv credentials in settings')
        settings('plexLogin', value="")
        settings('plexToken', value="")
        settings('plexid', value="")
        settings('plexHomeSize', value="1")
        settings('plexAvatar', value="")
        settings('plex_status', value=lang(39226))

        window('plex_token', clear=True)
        plex_command('PLEX_TOKEN', '')
        plex_command('PLEX_USERNAME', '')
    else:
        log.info('Login to plex.tv')
        import initialsetup
        initialsetup.InitialSetup().plex_tv_sign_in()
    dialog('notification',
           lang(29999),
           lang(39221),
           icon='{plex}',
           time=3000,
           sound=False)
Exemple #33
0
def chooseServer():
    """
    Lets user choose from list of PMS
    """
    log.info("Choosing PMS server requested, starting")

    import initialsetup
    setup = initialsetup.InitialSetup()
    server = setup.PickPMS(showDialog=True)
    if server is None:
        log.error('We did not connect to a new PMS, aborting')
        plex_command('SUSPEND_USER_CLIENT', 'False')
        plex_command('SUSPEND_LIBRARY_THREAD', 'False')
        return

    log.info("User chose server %s" % server['name'])
    setup.WritePMStoSettings(server)

    if not __LogOut():
        return

    from utils import deletePlaylists, deleteNodes
    # First remove playlists
    deletePlaylists()
    # Remove video nodes
    deleteNodes()

    # Log in again
    __LogIn()
    log.info("Choosing new PMS complete")
    # '<PMS> connected'
    dialog('notification',
           lang(29999),
           '%s %s' % (server['name'], lang(39220)),
           icon='{plex}',
           time=3000,
           sound=False)
Exemple #34
0
def chooseServer():
    """
    Lets user choose from list of PMS
    """
    log.info("Choosing PMS server requested, starting")

    import initialsetup
    setup = initialsetup.InitialSetup()
    server = setup.PickPMS(showDialog=True)
    if server is None:
        log.error('We did not connect to a new PMS, aborting')
        window('suspend_Userclient', clear=True)
        window('suspend_LibraryThread', clear=True)
        return

    log.info("User chose server %s" % server['name'])
    setup.WritePMStoSettings(server)

    if not __LogOut():
        return

    from utils import deletePlaylists, deleteNodes
    # First remove playlists
    deletePlaylists()
    # Remove video nodes
    deleteNodes()

    # Log in again
    __LogIn()
    log.info("Choosing new PMS complete")
    # '<PMS> connected'
    dialog('notification',
           lang(29999),
           '%s %s' % (server['name'], lang(39220)),
           icon='{plex}',
           time=3000,
           sound=False)
Exemple #35
0
    def path_validation(cls, path):
        # Verify if direct path is accessible or not
        verify_path = path
        if not os.path.supports_unicode_filenames:
            verify_path = path.encode('utf-8')

        if window('emby_pathverified') != "true" and not xbmcvfs.exists(verify_path):
            if dialog(type_="yesno",
                      heading="{emby}",
                      line1="%s %s. %s" % (lang(33047), path, lang(33048))):

                window('emby_shouldStop', value="true")
                return False

        return True
Exemple #36
0
 def play(self):
     """
     Start up playback_starter in main Python thread
     """
     # Put the request into the 'queue'
     while window('plex_play_new_item'):
         sleep(50)
     window('plex_play_new_item',
            value='%s%s' % ('play', argv[2]))
     # Wait for the result
     while not pickl_window('plex_result'):
         sleep(50)
     result = unpickle_me()
     if result is None:
         log.error('Error encountered, aborting')
         dialog('notification',
                heading='{plex}',
                message=lang(30128),
                icon='{error}',
                time=3000)
         setResolvedUrl(HANDLE, False, ListItem())
     elif result.listitem:
         listitem = convert_PKC_to_listitem(result.listitem)
         setResolvedUrl(HANDLE, True, listitem)
Exemple #37
0
    def texture_cache_sync(self):
        # This method will sync all Kodi artwork to textures13.db
        # and cache them locally. This takes diskspace!
        if not dialog(type_="yesno", heading="{emby}", line1=lang(33042)):
            return

        log.info("Doing Image Cache Sync")

        pdialog = xbmcgui.DialogProgress()
        pdialog.create(lang(29999), lang(33043))

        # ask to rest all existing or not
        if dialog(type_="yesno", heading="{emby}", line1=lang(33044)):
            log.info("Resetting all cache data first")
            self.delete_cache()

        # Cache all entries in video DB
        self._cache_all_video_entries(pdialog)
        # Cache all entries in music DB
        self._cache_all_music_entries(pdialog)

        pdialog.update(100,
                       "%s %s" % (lang(33046), len(self.image_cache_threads)))
        log.info("Waiting for all threads to exit")

        while len(self.image_cache_threads):
            for thread in self.image_cache_threads:
                if thread.is_finished:
                    self.image_cache_threads.remove(thread)
            pdialog.update(
                100, "%s %s" % (lang(33046), len(self.image_cache_threads)))
            log.info("Waiting for all threads to exit: %s",
                     len(self.image_cache_threads))
            xbmc.sleep(500)

        pdialog.close()
def __LogOut():
    """
    Finishes lib scans, logs out user. The following window attributes are set:
        suspend_LibraryThread: 'true'
        suspend_Userclient: 'true'

    Returns True if successfully signed out, False otherwise
    """
    # Resetting, please wait
    dialog('notification',
           lang(29999),
           lang(39207),
           icon='{plex}',
           time=3000,
           sound=False)
    # Pause library sync thread
    window('suspend_LibraryThread', value='true')
    # Wait max for 10 seconds for all lib scans to shutdown
    counter = 0
    while window('plex_dbScan') == 'true':
        if counter > 200:
            # Failed to reset PMS and plex.tv connects. Try to restart Kodi.
            dialog('ok', lang(29999), lang(39208))
            # Resuming threads, just in case
            window('suspend_LibraryThread', clear=True)
            log.error("Could not stop library sync, aborting")
            return False
        counter += 1
        sleep(50)
    log.debug("Successfully stopped library sync")

    # Log out currently signed in user:
    window('plex_serverStatus', value="401")
    # Above method needs to have run its course! Hence wait
    counter = 0
    while window('plex_serverStatus') == "401":
        if counter > 100:
            # 'Failed to reset PKC. Try to restart Kodi.'
            dialog('ok', lang(29999), lang(39208))
            log.error("Could not sign out user, aborting")
            return False
        counter += 1
        sleep(50)
    # Suspend the user client during procedure
    window('suspend_Userclient', value='true')
    return True
Exemple #39
0
def __LogOut():
    """
    Finishes lib scans, logs out user. The following window attributes are set:
        suspend_LibraryThread: 'true'
        suspend_Userclient: 'true'

    Returns True if successfully signed out, False otherwise
    """
    # Resetting, please wait
    dialog('notification',
           lang(29999),
           lang(39207),
           icon='{plex}',
           time=3000,
           sound=False)
    # Pause library sync thread
    window('suspend_LibraryThread', value='true')
    # Wait max for 10 seconds for all lib scans to shutdown
    counter = 0
    while window('plex_dbScan') == 'true':
        if counter > 200:
            # Failed to reset PMS and plex.tv connects. Try to restart Kodi.
            dialog('ok', lang(29999), lang(39208))
            # Resuming threads, just in case
            window('suspend_LibraryThread', clear=True)
            log.error("Could not stop library sync, aborting")
            return False
        counter += 1
        sleep(50)
    log.debug("Successfully stopped library sync")

    # Log out currently signed in user:
    window('plex_serverStatus', value="401")
    # Above method needs to have run its course! Hence wait
    counter = 0
    while window('plex_serverStatus') == "401":
        if counter > 100:
            # 'Failed to reset PKC. Try to restart Kodi.'
            dialog('ok', lang(29999), lang(39208))
            log.error("Could not sign out user, aborting")
            return False
        counter += 1
        sleep(50)
    # Suspend the user client during procedure
    window('suspend_Userclient', value='true')
    return True
Exemple #40
0
def enterPMS():
    """
    Opens dialogs for the user the plug in the PMS details
    """
    # "Enter your Plex Media Server's IP or URL. Examples are:"
    dialog('ok', lang(29999), lang(39215), '192.168.1.2', 'plex.myServer.org')
    ip = dialog('input', "Enter PMS IP or URL")
    if ip == '':
        return
    port = dialog('input', "Enter PMS port", '32400', type='{numeric}')
    if port == '':
        return
    url = '%s:%s' % (ip, port)
    # "Does your Plex Media Server support SSL connections?
    # (https instead of http)"
    https = dialog('yesno', lang(29999), lang(39217))
    if https:
        url = 'https://%s' % url
    else:
        url = 'http://%s' % url
    https = 'true' if https else 'false'

    machineIdentifier = GetMachineIdentifier(url)
    if machineIdentifier is None:
        # "Error contacting url
        # Abort (Yes) or save address anyway (No)"
        if dialog('yesno',
                  lang(29999),
                  '%s %s. %s' % (lang(39218), url, lang(39219))):
            return
        else:
            settings('plex_machineIdentifier', '')
    else:
        settings('plex_machineIdentifier', machineIdentifier)
    log.info('Set new PMS to https %s, ip %s, port %s, machineIdentifier %s'
             % (https, ip, port, machineIdentifier))
    settings('https', value=https)
    settings('ipaddress', value=ip)
    settings('port', value=port)
    # Chances are this is a local PMS, so disable SSL certificate check
    settings('sslverify', value='false')

    # Sign out to trigger new login
    if __LogOut():
        # Only login again if logout was successful
        __LogIn()
Exemple #41
0
def enterPMS():
    """
    Opens dialogs for the user the plug in the PMS details
    """
    # "Enter your Plex Media Server's IP or URL. Examples are:"
    dialog('ok', lang(29999), lang(39215), '192.168.1.2', 'plex.myServer.org')
    ip = dialog('input', "Enter PMS IP or URL")
    if ip == '':
        return
    port = dialog('input', "Enter PMS port", '32400', type='{numeric}')
    if port == '':
        return
    url = '%s:%s' % (ip, port)
    # "Does your Plex Media Server support SSL connections?
    # (https instead of http)"
    https = dialog('yesno', lang(29999), lang(39217))
    if https:
        url = 'https://%s' % url
    else:
        url = 'http://%s' % url
    https = 'true' if https else 'false'

    machineIdentifier = GetMachineIdentifier(url)
    if machineIdentifier is None:
        # "Error contacting url
        # Abort (Yes) or save address anyway (No)"
        if dialog('yesno',
                  lang(29999),
                  '%s %s. %s' % (lang(39218), url, lang(39219))):
            return
        else:
            settings('plex_machineIdentifier', '')
    else:
        settings('plex_machineIdentifier', machineIdentifier)
    log.info('Set new PMS to https %s, ip %s, port %s, machineIdentifier %s'
             % (https, ip, port, machineIdentifier))
    settings('https', value=https)
    settings('ipaddress', value=ip)
    settings('port', value=port)
    # Chances are this is a local PMS, so disable SSL certificate check
    settings('sslverify', value='false')

    # Sign out to trigger new login
    if __LogOut():
        # Only login again if logout was successful
        __LogIn()
Exemple #42
0
def __LogOut():
    """
    Finishes lib scans, logs out user.

    Returns True if successfully signed out, False otherwise
    """
    # Resetting, please wait
    dialog('notification',
           lang(29999),
           lang(39207),
           icon='{plex}',
           time=3000,
           sound=False)
    # Pause library sync thread
    plex_command('SUSPEND_LIBRARY_THREAD', 'True')
    # Wait max for 10 seconds for all lib scans to shutdown
    counter = 0
    while window('plex_dbScan') == 'true':
        if counter > 200:
            # Failed to reset PMS and plex.tv connects. Try to restart Kodi.
            dialog('ok', lang(29999), lang(39208))
            # Resuming threads, just in case
            plex_command('SUSPEND_LIBRARY_THREAD', 'False')
            log.error("Could not stop library sync, aborting")
            return False
        counter += 1
        sleep(50)
    log.debug("Successfully stopped library sync")

    counter = 0
    # Log out currently signed in user:
    window('plex_serverStatus', value='401')
    plex_command('PMS_STATUS', '401')
    # Above method needs to have run its course! Hence wait
    while window('plex_serverStatus') == "401":
        if counter > 100:
            # 'Failed to reset PKC. Try to restart Kodi.'
            dialog('ok', lang(29999), lang(39208))
            log.error("Could not sign out user, aborting")
            return False
        counter += 1
        sleep(50)
    # Suspend the user client during procedure
    plex_command('SUSPEND_USER_CLIENT', 'True')
    return True
Exemple #43
0
    def fullTextureCacheSync(self):
        """
        This method will sync all Kodi artwork to textures13.db
        and cache them locally. This takes diskspace!
        """
        if not dialog('yesno', "Image Texture Cache", lang(39250)):
            return

        log.info("Doing Image Cache Sync")

        # ask to rest all existing or not
        if dialog('yesno', "Image Texture Cache", lang(39251)):
            log.info("Resetting all cache data first")
            # Remove all existing textures first
            path = tryDecode(translatePath("special://thumbnails/"))
            if IfExists(path):
                allDirs, allFiles = listdir(path)
                for dir in allDirs:
                    allDirs, allFiles = listdir(path+dir)
                    for file in allFiles:
                        if os_path.supports_unicode_filenames:
                            delete(os_path.join(
                                path + tryDecode(dir),
                                tryDecode(file)))
                        else:
                            delete(os_path.join(
                                tryEncode(path) + dir,
                                file))

            # remove all existing data from texture DB
            connection = kodiSQL('texture')
            cursor = connection.cursor()
            cursor.execute('SELECT tbl_name FROM sqlite_master WHERE type="table"')
            rows = cursor.fetchall()
            for row in rows:
                tableName = row[0]
                if tableName != "version":
                    cursor.execute("DELETE FROM " + tableName)
            connection.commit()
            connection.close()

        # Cache all entries in video DB
        connection = kodiSQL('video')
        cursor = connection.cursor()
        # dont include actors
        cursor.execute("SELECT url FROM art WHERE media_type != 'actor'")
        result = cursor.fetchall()
        total = len(result)
        log.info("Image cache sync about to process %s video images" % total)
        connection.close()

        for url in result:
            self.cacheTexture(url[0])
        # Cache all entries in music DB
        connection = kodiSQL('music')
        cursor = connection.cursor()
        cursor.execute("SELECT url FROM art")
        result = cursor.fetchall()
        total = len(result)
        log.info("Image cache sync about to process %s music images" % total)
        connection.close()
        for url in result:
            self.cacheTexture(url[0])
Exemple #44
0
    def ServiceEntryPoint(self):
        # Important: Threads depending on abortRequest will not trigger
        # if profile switch happens more than once.
        monitor = self.monitor
        kodiProfile = v.KODI_PROFILE

        # Detect playback start early on
        self.monitor_kodi_play = Monitor_Kodi_Play(self)
        self.monitor_kodi_play.start()

        # Server auto-detect
        initialsetup.InitialSetup().setup()

        # Initialize important threads, handing over self for callback purposes
        self.user = UserClient(self)
        self.ws = PMS_Websocket(self)
        self.alexa = Alexa_Websocket(self)
        self.library = LibrarySync(self)
        self.plexCompanion = PlexCompanion(self)
        self.playqueue = Playqueue(self)
        self.playback_starter = Playback_Starter(self)
        if settings('enableTextureCache') == "true":
            self.image_cache_thread = Image_Cache_Thread()

        plx = PlexAPI.PlexAPI()

        welcome_msg = True
        counter = 0
        while not monitor.abortRequested():

            if window('plex_kodiProfile') != kodiProfile:
                # Profile change happened, terminate this thread and others
                log.warn("Kodi profile was: %s and changed to: %s. "
                         "Terminating old PlexKodiConnect thread."
                         % (kodiProfile, window('plex_kodiProfile')))
                break

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

            if window('plex_online') == "true":
                # Plex server is online
                # Verify if user is set and has access to the server
                if (self.user.currUser is not None) and self.user.HasAccess:
                    if not self.kodimonitor_running:
                        # Start up events
                        self.warn_auth = True
                        if welcome_msg is True:
                            # Reset authentication warnings
                            welcome_msg = False
                            dialog('notification',
                                   lang(29999),
                                   "%s %s" % (lang(33000),
                                              self.user.currUser),
                                   icon='{plex}',
                                   time=2000,
                                   sound=False)
                        # Start monitoring kodi events
                        self.kodimonitor_running = KodiMonitor(self)
                        # Start playqueue client
                        if not self.playqueue_running:
                            self.playqueue_running = True
                            self.playqueue.start()
                        # Start the Websocket Client
                        if not self.ws_running:
                            self.ws_running = True
                            self.ws.start()
                        # Start the Alexa thread
                        if (not self.alexa_running and
                                settings('enable_alexa') == 'true'):
                            self.alexa_running = True
                            self.alexa.start()
                        # Start the syncing thread
                        if not self.library_running:
                            self.library_running = True
                            self.library.start()
                        # Start the Plex Companion thread
                        if not self.plexCompanion_running:
                            self.plexCompanion_running = True
                            self.plexCompanion.start()
                        if not self.playback_starter_running:
                            self.playback_starter_running = True
                            self.playback_starter.start()
                        if (not self.image_cache_thread_running and
                                settings('enableTextureCache') == "true"):
                            self.image_cache_thread_running = True
                            self.image_cache_thread.start()
                else:
                    if (self.user.currUser is None) and self.warn_auth:
                        # Alert user is not authenticated and suppress future
                        # warning
                        self.warn_auth = False
                        log.warn("Not authenticated yet.")

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

                        if window('plex_online') != "true":
                            # Server went offline
                            break

                        if monitor.waitForAbort(5):
                            # Abort was requested while waiting. We should exit
                            break
                        sleep(50)
            else:
                # Wait until Plex server is online
                # or Kodi is shut down.
                while not monitor.abortRequested():
                    server = self.user.getServer()
                    if server is False:
                        # No server info set in add-on settings
                        pass
                    elif plx.CheckConnection(server, verifySSL=True) is False:
                        # Server is offline or cannot be reached
                        # Alert the user and suppress future warning
                        if self.server_online:
                            self.server_online = False
                            window('plex_online', value="false")
                            # Suspend threads
                            window('suspend_LibraryThread', value='true')
                            log.error("Plex Media Server went offline")
                            if settings('show_pms_offline') == 'true':
                                dialog('notification',
                                       lang(33001),
                                       "%s %s" % (lang(29999), lang(33002)),
                                       icon='{plex}',
                                       sound=False)
                        counter += 1
                        # Periodically check if the IP changed, e.g. per minute
                        if counter > 20:
                            counter = 0
                            setup = initialsetup.InitialSetup()
                            tmp = setup.PickPMS()
                            if tmp is not None:
                                setup.WritePMStoSettings(tmp)
                    else:
                        # Server is online
                        counter = 0
                        if not self.server_online:
                            # Server was offline when Kodi started.
                            # Wait for server to be fully established.
                            if monitor.waitForAbort(5):
                                # Abort was requested while waiting.
                                break
                            self.server_online = True
                            # Alert the user that server is online.
                            if (welcome_msg is False and
                                    settings('show_pms_offline') == 'true'):
                                dialog('notification',
                                       lang(29999),
                                       lang(33003),
                                       icon='{plex}',
                                       time=5000,
                                       sound=False)
                        log.info("Server %s is online and ready." % server)
                        window('plex_online', value="true")
                        if window('plex_authenticated') == 'true':
                            # Server got offline when we were authenticated.
                            # Hence resume threads
                            window('suspend_LibraryThread', clear=True)

                        # Start the userclient thread
                        if not self.user_running:
                            self.user_running = True
                            self.user.start()

                        break

                    if monitor.waitForAbort(3):
                        # Abort was requested while waiting.
                        break

            if monitor.waitForAbort(0.05):
                # Abort was requested while waiting. We should exit
                break

        # Terminating PlexKodiConnect

        # Tell all threads to terminate (e.g. several lib sync threads)
        window('plex_terminateNow', value='true')
        try:
            self.plexCompanion.stopThread()
        except:
            log.warn('plexCompanion already shut down')
        try:
            self.library.stopThread()
        except:
            log.warn('Library sync already shut down')
        try:
            self.ws.stopThread()
        except:
            log.warn('Websocket client already shut down')
        try:
            self.alexa.stopThread()
        except:
            log.warn('Websocket client already shut down')
        try:
            self.user.stopThread()
        except:
            log.warn('User client already shut down')
        try:
            downloadutils.DownloadUtils().stopSession()
        except:
            pass
        window('plex_service_started', clear=True)
        log.warn("======== STOP %s ========" % v.ADDON_NAME)
Exemple #45
0
    def __init__(self):
        log.debug('Full sys.argv received: %s' % argv)
        # Parse parameters
        params = dict(parse_qsl(argv[2][1:]))
        mode = params.get('mode', '')
        itemid = params.get('id', '')

        if mode == 'play':
            self.play()

        elif mode == 'plex_node':
            self.play()

        elif mode == 'ondeck':
            entrypoint.getOnDeck(itemid,
                                 params.get('type'),
                                 params.get('tagname'),
                                 int(params.get('limit')))

        elif mode == 'recentepisodes':
            entrypoint.getRecentEpisodes(itemid,
                                         params.get('type'),
                                         params.get('tagname'),
                                         int(params.get('limit')))

        elif mode == 'nextup':
            entrypoint.getNextUpEpisodes(params['tagname'],
                                         int(params['limit']))

        elif mode == 'inprogressepisodes':
            entrypoint.getInProgressEpisodes(params['tagname'],
                                             int(params['limit']))

        elif mode == 'browseplex':
            entrypoint.browse_plex(key=params.get('key'),
                                   plex_section_id=params.get('id'))

        elif mode == 'getsubfolders':
            entrypoint.GetSubFolders(itemid)

        elif mode == 'watchlater':
            entrypoint.watchlater()

        elif mode == 'channels':
            entrypoint.channels()

        elif mode == 'settings':
            executebuiltin('Addon.OpenSettings(%s)' % v.ADDON_ID)

        elif mode == 'enterPMS':
            entrypoint.enterPMS()

        elif mode == 'reset':
            reset()

        elif mode == 'togglePlexTV':
            entrypoint.togglePlexTV()

        elif mode == 'resetauth':
            entrypoint.resetAuth()

        elif mode == 'passwords':
            passwordsXML()

        elif mode == 'switchuser':
            entrypoint.switchPlexUser()

        elif mode in ('manualsync', 'repair'):
            if window('plex_online') != 'true':
                # Server is not online, do not run the sync
                dialog('ok',
                       heading=lang(29999),
                       message=lang(39205))
                log.error('Not connected to a PMS.')
            else:
                if mode == 'repair':
                    window('plex_runLibScan', value='repair')
                    log.info('Requesting repair lib sync')
                elif mode == 'manualsync':
                    log.info('Requesting full library scan')
                    window('plex_runLibScan', value='full')

        elif mode == 'texturecache':
            window('plex_runLibScan', value='del_textures')

        elif mode == 'chooseServer':
            entrypoint.chooseServer()

        elif mode == 'refreshplaylist':
            log.info('Requesting playlist/nodes refresh')
            window('plex_runLibScan', value='views')

        elif mode == 'deviceid':
            self.deviceid()

        elif mode == 'fanart':
            log.info('User requested fanarttv refresh')
            window('plex_runLibScan', value='fanart')

        elif '/extrafanart' in argv[0]:
            plexpath = argv[2][1:]
            plexid = itemid
            entrypoint.getExtraFanArt(plexid, plexpath)
            entrypoint.getVideoFiles(plexid, plexpath)

        # Called by e.g. 3rd party plugin video extras
        elif ('/Extras' in argv[0] or '/VideoFiles' in argv[0] or
                '/Extras' in argv[2]):
            plexId = itemid or None
            entrypoint.getVideoFiles(plexId, params)

        else:
            entrypoint.doMainListing(content_type=params.get('content_type'))
    def downloadUrl(self, url, action_type="GET", postBody=None,
                    parameters=None, authenticate=True, headerOptions=None,
                    verifySSL=True, timeout=None):
        """
        Override SSL check with verifySSL=False

        If authenticate=True, existing request session will be used/started
        Otherwise, 'empty' request will be made

        Returns:
            None              If an error occured
            True               If connection worked but no body was received
            401, ...           integer if PMS answered with HTTP error 401
                               (unauthorized) or other http error codes
            xml                xml etree root object, if applicable
            JSON               json() object, if applicable
        """
        kwargs = {'timeout': self.timeout}
        if authenticate is True:
            # Get requests session
            try:
                s = self.s
            except AttributeError:
                log.info("Request session does not exist: start one")
                self.startSession()
                s = self.s
            # Replace for the real values
            url = url.replace("{server}", self.server)
        else:
            # User is not (yet) authenticated. Used to communicate with
            # plex.tv and to check for PMS servers
            s = requests
            headerOptions = self.getHeader(options=headerOptions)
            if settings('sslcert') != 'None':
                kwargs['cert'] = settings('sslcert')

        # Set the variables we were passed (fallback to request session
        # otherwise - faster)
        kwargs['url'] = url
        if verifySSL is False:
            kwargs['verify'] = False
        if headerOptions is not None:
            kwargs['headers'] = headerOptions
        if postBody is not None:
            kwargs['data'] = postBody
        if parameters is not None:
            kwargs['params'] = parameters
        if timeout is not None:
            kwargs['timeout'] = timeout

        # ACTUAL DOWNLOAD HAPPENING HERE
        try:
            r = self._doDownload(s, action_type, **kwargs)

        # THE EXCEPTIONS
        except requests.exceptions.ConnectionError as e:
            # Connection error
            log.debug("Server unreachable at: %s" % url)
            log.debug(e)

        except requests.exceptions.Timeout as e:
            log.debug("Server timeout at: %s" % url)
            log.debug(e)

        except requests.exceptions.HTTPError as e:
            log.warn('HTTP Error at %s' % url)
            log.warn(e)

        except requests.exceptions.SSLError as e:
            log.warn("Invalid SSL certificate for: %s" % url)
            log.warn(e)

        except requests.exceptions.TooManyRedirects as e:
            log.warn("Too many redirects connecting to: %s" % url)
            log.warn(e)

        except requests.exceptions.RequestException as e:
            log.warn("Unknown error connecting to: %s" % url)
            log.warn(e)

        except SystemExit:
            log.info('SystemExit detected, aborting download')
            self.stopSession()

        except:
            log.warn('Unknown error while downloading. Traceback:')
            import traceback
            log.warn(traceback.format_exc())

        # THE RESPONSE #####
        else:
            # We COULD contact the PMS, hence it ain't dead
            if authenticate is True:
                window('countError', value='0')
                if r.status_code != 401:
                    window('countUnauthorized', value='0')

            if r.status_code == 204:
                # No body in the response
                # But read (empty) content to release connection back to pool
                # (see requests: keep-alive documentation)
                r.content
                return True

            elif r.status_code == 401:
                if authenticate is False:
                    # Called when checking a connect - no need for rash action
                    return 401
                r.encoding = 'utf-8'
                log.warn('HTTP error 401 from PMS %s' % url)
                log.info(r.text)
                if '401 Unauthorized' in r.text:
                    # Truly unauthorized
                    window('countUnauthorized',
                           value=str(int(window('countUnauthorized')) + 1))
                    if (int(window('countUnauthorized')) >=
                            self.unauthorizedAttempts):
                        log.warn('We seem to be truly unauthorized for PMS'
                                 ' %s ' % url)
                        if window('plex_serverStatus') not in ('401', 'Auth'):
                            # Tell userclient token has been revoked.
                            log.debug('Setting PMS server status to '
                                      'unauthorized')
                            window('plex_serverStatus', value="401")
                            dialog('notification',
                                   lang(29999),
                                   lang(30017),
                                   icon='{error}')
                else:
                    # there might be other 401 where e.g. PMS under strain
                    log.info('PMS might only be under strain')
                return 401

            elif r.status_code in (200, 201):
                # 200: OK
                # 201: Created
                try:
                    # xml response
                    r = etree.fromstring(r.content)
                    return r
                except:
                    r.encoding = 'utf-8'
                    if r.text == '':
                        # Answer does not contain a body
                        return True
                    try:
                        # UNICODE - JSON object
                        r = r.json()
                        return r
                    except:
                        if '200 OK' in r.text:
                            # Received f****d up OK from PMS on playstate
                            # update
                            pass
                        else:
                            log.error("Unable to convert the response for: "
                                      "%s" % url)
                            log.info("Received headers were: %s" % r.headers)
                            log.info('Received text:')
                            log.info(r.text)
                        return True
            elif r.status_code == 403:
                # E.g. deleting a PMS item
                log.error('PMS sent 403: Forbidden error for url %s' % url)
                return None
            else:
                log.error('Unknown answer from PMS %s with status code %s. '
                          'Message:' % (url, r.status_code))
                r.encoding = 'utf-8'
                log.info(r.text)
                return True

        # And now deal with the consequences of the exceptions
        if authenticate is True:
            # Make the addon aware of status
            try:
                window('countError',
                       value=str(int(window('countError')) + 1))
                if int(window('countError')) >= self.connectionAttempts:
                    log.warn('Failed to connect to %s too many times. '
                             'Declare PMS dead' % url)
                    window('plex_online', value="false")
            except:
                # 'countError' not yet set
                pass
        return None
    def _general_commands(cls, data):

        command = data['Name']
        arguments = data['Arguments']

        if command in ('Mute', 'Unmute', 'SetVolume',
                       'SetSubtitleStreamIndex', 'SetAudioStreamIndex'):

            player = xbmc.Player()
            # These commands need to be reported back
            if command == 'Mute':
                xbmc.executebuiltin('Mute')

            elif command == 'Unmute':
                xbmc.executebuiltin('Mute')

            elif command == 'SetVolume':
                volume = arguments['Volume']
                xbmc.executebuiltin('SetVolume(%s[,showvolumebar])' % volume)

            elif command == 'SetAudioStreamIndex':
                index = int(arguments['Index'])
                player.setAudioStream(index - 1)

            elif command == 'SetSubtitleStreamIndex':
                emby_index = int(arguments['Index'])
                current_file = player.getPlayingFile()
                mapping = window('emby_%s.indexMapping' % current_file)

                if emby_index == -1:
                    player.showSubtitles(False)

                elif mapping:
                    external_index = json.loads(mapping)
                    # If there's external subtitles added via playbackutils
                    for index in external_index:
                        if external_index[index] == emby_index:
                            player.setSubtitleStream(int(index))
                            break
                    else:
                        # User selected internal subtitles
                        external = len(external_index)
                        audio_tracks = len(player.getAvailableAudioStreams())
                        player.setSubtitleStream(external + emby_index - audio_tracks - 1)
                else:
                    # Emby merges audio and subtitle index together
                    audio_tracks = len(player.getAvailableAudioStreams())
                    player.setSubtitleStream(emby_index - audio_tracks - 1)

            # Let service know
            window('emby_command', value="true")

        elif command == 'DisplayMessage':

            header = arguments['Header']
            text = arguments['Text']
            dialog(type_="notification",
                   heading=header,
                   message=text,
                   icon="{emby}",
                   time=int(settings('displayMessage'))*1000)

        elif command == 'SendString':

            params = {

                'text': arguments['String'],
                'done': False
            }
            JSONRPC('Input.SendText').execute(params)

        elif command in ('MoveUp', 'MoveDown', 'MoveRight', 'MoveLeft'):
            # Commands that should wake up display
            actions = {

                'MoveUp': "Input.Up",
                'MoveDown': "Input.Down",
                'MoveRight': "Input.Right",
                'MoveLeft': "Input.Left"
            }
            JSONRPC(actions[command]).execute()

        elif command == 'GoHome':
            JSONRPC('GUI.ActivateWindow').execute({'window': "home"})

        else:
            builtin = {

                'ToggleFullscreen': 'Action(FullScreen)',
                'ToggleOsdMenu': 'Action(OSD)',
                'ToggleContextMenu': 'Action(ContextMenu)',
                'Select': 'Action(Select)',
                'Back': 'Action(back)',
                'PageUp': 'Action(PageUp)',
                'NextLetter': 'Action(NextLetter)',
                'GoToSearch': 'VideoLibrary.Search',
                'GoToSettings': 'ActivateWindow(Settings)',
                'PageDown': 'Action(PageDown)',
                'PreviousLetter': 'Action(PrevLetter)',
                'TakeScreenshot': 'TakeScreenshot',
                'ToggleMute': 'Mute',
                'VolumeUp': 'Action(VolumeUp)',
                'VolumeDown': 'Action(VolumeDown)',
            }
            if command in builtin:
                xbmc.executebuiltin(builtin[command])
    def _server_online_check(self):
        # Set emby_online true/false property
        user_client = self.userclient_thread
        while not self.monitor.abortRequested():

            if user_client.get_server() is None:
                # No server info set in add-on settings
                pass

            elif not user_client.verify_server():
                # Server is offline.
                # Alert the user and suppress future warning
                if self.server_online:
                    log.info("Server is offline")
                    window('emby_online', value="false")

                    if settings('offlineMsg') == "true":
                        dialog(type_="notification",
                               heading=lang(33001),
                               message="%s %s" % (self.addon_name, lang(33002)),
                               icon="{emby}",
                               sound=False)

                self.server_online = False

            elif window('emby_online') in ("sleep", "reset"):
                # device going to sleep
                if self.websocket_running:
                    self.websocket_thread.stop_client()
                    self.websocket_thread = wsc.WebSocketClient()
                    self.websocket_running = False

                if self.library_running:
                    self.library_thread.stopThread()
                    self.library_thread = librarysync.LibrarySync()
                    self.library_running = 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.monitor.waitForAbort(5):
                        # Abort was requested while waiting.
                        break
                    # Alert the user that server is online.
                    dialog(type_="notification",
                           heading="{emby}",
                           message=lang(33003),
                           icon="{emby}",
                           time=2000,
                           sound=False)

                self.server_online = True
                window('emby_online', value="true")
                log.info("Server is online and ready")

                # Start the userclient thread
                if not self.userclient_running:
                    self.userclient_running = True
                    user_client.start()

                break

            if self.monitor.waitForAbort(1):
                # Abort was requested while waiting.
                break
Exemple #49
0
    def client_update(self):
        self.update_sock = socket.socket(socket.AF_INET,
                                         socket.SOCK_DGRAM,
                                         socket.IPPROTO_UDP)
        update_sock = self.update_sock

        # Set socket reuse, may not work on all OSs.
        try:
            update_sock.setsockopt(socket.SOL_SOCKET,
                                   socket.SO_REUSEADDR,
                                   1)
        except:
            pass

        # Attempt to bind to the socket to recieve and send data.  If we cant
        # do this, then we cannot send registration
        try:
            update_sock.bind(('0.0.0.0', self.client_update_port))
        except:
            log.error("Unable to bind to port [%s] - Plex Companion will not "
                      "be registered. Change the Plex Companion update port!"
                      % self.client_update_port)
            if settings('companion_show_gdm_port_warning') == 'true':
                if dialog('yesno',
                          language(29999),
                          'Port %s' % self.client_update_port,
                          language(39079),
                          yeslabel=language(30013),  # Never show again
                          nolabel=language(30012)):  # OK
                    settings('companion_show_gdm_port_warning', value='false')
                from xbmc import executebuiltin
                executebuiltin(
                    'Addon.OpenSettings(plugin.video.plexkodiconnect)')
            return

        update_sock.setsockopt(socket.IPPROTO_IP,
                               socket.IP_MULTICAST_TTL,
                               255)
        update_sock.setsockopt(socket.IPPROTO_IP,
                               socket.IP_ADD_MEMBERSHIP,
                               socket.inet_aton(
                                   self._multicast_address) +
                               socket.inet_aton('0.0.0.0'))
        update_sock.setblocking(0)

        # Send initial client registration
        self.register_as_client()

        # Now, listen format client discovery reguests and respond.
        while self._registration_is_running:
            try:
                data, addr = update_sock.recvfrom(1024)
                log.debug("Recieved UDP packet from [%s] containing [%s]"
                          % (addr, data.strip()))
            except socket.error:
                pass
            else:
                if "M-SEARCH * HTTP/1." in data:
                    log.debug("Detected client discovery request from %s. "
                              " Replying" % str(addr))
                    try:
                        update_sock.sendto("HTTP/1.0 200 OK\n%s"
                                           % self.client_data,
                                           addr)
                    except:
                        log.error("Unable to send client update message")

                    log.debug("Sending registration data HTTP/1.0 200 OK")
                    self.client_registered = True
            sleep(500)
        log.info("Client Update loop stopped")
        # When we are finished, then send a final goodbye message to
        # deregister cleanly.
        log.debug("Sending registration data: BYE %s\n%s"
                  % (self.client_header, self.client_data))
        try:
            update_sock.sendto("BYE %s\n%s"
                               % (self.client_header, self.client_data),
                               self.client_register_group)
        except:
            log.error("Unable to send client update message")
        self.client_registered = False
Exemple #50
0
def RunLibScan(mode):
    if window('plex_online') != "true":
        # Server is not online, do not run the sync
        dialog('ok', lang(29999), lang(39205))
    else:
        window('plex_runLibScan', value='full')