def __init__(self, sagexHost, useLock=True, log=None):
        '''Creates a SageX object

        @param sagexHost  url such as http://usr:pwd@host:port/
        @param useLock    whether to synchronize sagex API calls
        @param log        plexlog obj from Agent, or None
        '''
        # setup log
        if log:  # called from agent
            self.log = log
            self.isAgent = True
        else:  # called from scanner, use default (console)
            self.log = plexlog.PlexLog()
            self.isAgent = False
        # set property
        if sagexHost:
            if not sagexHost.endswith('/'):
                sagexHost += '/'
            self.SAGEX_HOST = sagexHost
        else:
            self.SAGEX_HOST = ''
            self.log.error('SageX: sagexHost not specified!!')
        # used to synchronize sagex http call, otherwise may get
        # fanart download problem as PLEX calls Agent.search() and
        # Agent.update() from multiple threads and there seems to be
        # some issue with downloading fanart there.
        self.useLock = useLock
        # self.lock = Thread.Lock('sagexLock')
        self.lock = threading.Lock()
    def __init__(self, platform, env_var=DEFAULT_CFG_ENV, log=None):
        '''Create a SagePlexConfig object

        Creates a configuration object by either using default or read
        configuration file pointed by SAGEPLEX_CFG environment
        variable

        @param platform  current platform, either python sys.platform
                         or Platform.OS under PMS
        @param env       environment variable to lookup config file
        @param log       PlexLog obj from agent, or None
        '''
        self.data = {}
        self.SAGEX_HOST = None
        self.PLEX_HOST = None
        if log:  # called from agent
            self.log = log
        else:  # called from scanner, use default (console)
            self.log = plexlog.PlexLog()
        # look up environment variable if specified
        cfg = None
        if env_var:  # if env_var is passed in to constructor
            cfg = os.environ.get(env_var)
            if cfg:  # if env variable exist
                # expand env variables in value such as
                # %LOCALAPPDATA%\Plex Media Server\sageplex_cfg.json
                cfg = os.path.expandvars(cfg)
                self.log.info('Config: %s=%s', env_var, cfg)
                if os.path.isdir(cfg):
                    cfg = os.path.join(cfg, CFG_FILE)
                    self.log.info(
                        'Config: %s points to directory, adding %s to path',
                        env_var, CFG_FILE)
            else:
                self.log.info('Config: no env var %s', env_var)
        # lookup location if no env var used
        if not cfg:
            cfg = os.path.join(self.plexDataDir(platform), CFG_FILE)

        if not os.path.isfile(cfg):
            self.log.error('Config: file not found: %s', cfg)
            return
        # now try to open the JSON file and read it
        self.log.info('Config: %s', cfg)
        try:
            if log:  # if in agent, use readFile()
                data_file = self.readFile(cfg)
                if not data_file:
                    self.log.error("Config: readfile() failed to return data")
                    return
                self.data = JSON.ObjectFromString(data_file)
            else:  # use python open()
                with open(cfg) as data_file:
                    self.data = json.load(data_file)
        except (IOError, ValueError, os.error), e:
            self.log.error("Config: %s: %s", cfg, e)
            return
    def __init__(self, plexHost, log=None, token=None):
        '''Creates a PlexApi object

        @param plexHost  url such as http://host:port/
        @param log       plexlog obj from Agent, or None
        '''
        self.appid = 'com.plexapp.plugins.library'
        # setup log
        if log:  # called from agent
            self.log = log
            self.isAgent = True
        else:  # called from scanner, use default (console)
            self.log = plexlog.PlexLog()
            self.isAgent = False
        # set PLEX_HOST, remove ending / if any
        if plexHost:
            if plexHost[-1] == '/':  # if ends with /
                plexHost = plexHost[:-1]  # remove ending /
            self.PLEX_HOST = plexHost
        else:
            self.PLEX_HOST = ''
            self.log.error('PlexApi: plexHost not specified!!')
        # store token value
        self.PLEX_TOKEN = token
Ejemplo n.º 4
0
def Start():
    '''This function is called when the plug-in first starts. It can be
    used to perform extra initialisation tasks such as configuring the
    environment and setting default attributes.
    '''
    global mylog, myconfig, mysagex, myplex
    mylog = plexlog.PlexLog(isAgent=True)  # use Log instead of logging

    mylog.info('***** Initializing "SageTV BMT Agent (TV Shows)" *****')
    HTTP.CacheTime = CACHE_1HOUR * 24

    # PMS supports a DefaultPrefs.json file for plug-ins, and settings
    # can be accessed via simple Prefs['id'].
    #
    # The problem is, after the 1st run, settings are stored per plugin
    # in an XML file in the "plug-in support folder":
    #  plug-in support\preferences\com.plexapp.agents.bmtagenttvshows.xml
    # This makes updating the setting by the user a little confusing,
    # as there are 2 places to change.
    #
    # using a standalone json file for both scanner/agent is easier
    # for the user to understand and manage.
    myconfig = config.Config(Platform.OS, log=mylog)
    sagexHost = myconfig.getSagexHost()
    mylog.info('SAGE_HOST: %s', sagexHost)
    plexHost = myconfig.getPlexHost()
    mylog.info('PLEX_HOST: %s', plexHost)

    # create the SageX object from sagex module
    mysagex = sagex.SageX(sagexHost,
                          useLock=myconfig.getAgentLocking(),
                          log=mylog)
    # create plex api object
    myplex = plexapi.PlexApi(plexHost,
                             log=mylog,
                             token=myconfig.getPlexToken())
Ejemplo n.º 5
0
    def update(self, metadata, media, lang):
        '''Adding metadata to media

        Once an item has been successfully matched, it is added to the
        update queue. As the framework processes queued items, it
        calls the update method of the relevant agents.

        This is called once for each Show. The function should craw
        through all the seasons/episodes and set the appropriate
        attribute on each one.

        @param metadata  A pre-initialized metadata object if this is
                         the first time the item is being updated, or
                         the existing metadata object if the item is
                         being refreshed.
        @param media     An object containing information about the
                         media hierarchy in the database.
        @param lang      A string identifying the user's currently
                         selected language.
        '''
        # use a local mylog object as this function is called from
        # different threads and we want the log header (that is stored
        # inside the mylog object) to be unique for each call.
        mylog = plexlog.PlexLog(isAgent=True)

        mylog.info("***** entering BMTAgent.update(%s) ***** ", media.title)

        if media and metadata.title is None: metadata.title = media.title

        # Show/Series info is set when we encounter 1st episode below
        seriesInfo = False

        # now set information for each episode in each season
        for s in media.seasons:

            season = metadata.seasons[s]
            season.index = int(s)

            for e in media.seasons[s].episodes:

                episode = metadata.seasons[s].episodes[e]
                episodeMedia = media.seasons[s].episodes[e].items[0]
                # the file for episode is available from the media
                # object, no need to use mysagex.getMediaFilesForShow
                epFile = os.path.basename(episodeMedia.parts[0].file)
                # set a log prefix such as: "showname/s5/e11: "
                mylog.setPrefix('%s/s%s/e%s: ' % (metadata.title, s, e))
                mylog.info('%s', epFile)

                # get the MediaFile object from sage
                mf = mysagex.getMediaFileForName(epFile)
                if not mf:
                    # this should not happen
                    mylog.error("no media info from SageTV")
                    continue

                mediaFileID = mf.get('MediaFileID')
                mylog.info('mfid: %s', mediaFileID)

                # retrieving the airing/show field that should always exist
                airing = mf.get('Airing')
                if not airing:
                    mylog.error('no Airing field, skipping file')
                    continue
                show = airing.get('Show')
                if not show:
                    mylog.error('no [Airing][Show] field, skipping file')
                    continue

                # set series info if we haven't done so already
                if not seriesInfo:
                    if self.setShowSeriesInfo(metadata, media, mf, mylog):
                        seriesInfo = True

                # TODO: move the following episode setter to own function?
                mylog.info('setting episode level metadata')
                if (airing.get('AiringStartTime')):
                    startTime = airing.get('AiringStartTime') // 1000
                    airDate = Datetime.FromTimestamp(startTime)

                mylog.debug('airdate: %s', airDate)

                episode.title = show.get('ShowEpisode')
                if not episode.title:
                    episode.title = show.get('ShowTitle')
                episode.summary = show.get('ShowDescription')
                episode.originally_available_at = airDate
                episode.duration = airing.get('AiringDuration')
                episode.season = int(s)

                stars = show.get('PeopleListInShow')
                episode.guest_stars.clear()
                if stars:  # See issue #13
                    for star in stars:
                        episode.guest_stars.add(star)
                else:
                    mylog.debug('no PeopleListInShow data.')

                # set rating
                rSource = airing.get('ParentalRating')
                rTarget = rSource[:2] + '-' + rSource[2:]
                mylog.debug('rating: %s -> %s', rSource, rTarget)
                episode.content_rating = rTarget

                # set watch flag and resume position
                self.setWatchStatus(mf, airing, media, s, e, mylog)

                # misc stuff
                mfprops = mf.get('MediaFileMetadataProperties')
                episode.guest_stars.add(show.get('PeopleInShow'))
                episode.writers.add(mfprops.get('Writer'))
                episode.directors.add(mfprops.get('Director'))
                episode.producers.add(mfprops.get('ExecutiveProducer'))

                # set the fanart for show and episode
                self.setFanArt(metadata, season, episode, mediaFileID, mylog)

                mylog.debug(
                    "COMPLETED SETTING EPISODE-LEVEL METADATA: "
                    "episode.title=%s;episode.summary=%s;"
                    "episode.originally_available_at=%s;episode.duration=%s;"
                    "episode.season=%s;metadata.content_rating=%s;" %
                    (episode.title, episode.summary,
                     episode.originally_available_at, episode.duration,
                     episode.season, metadata.content_rating))