def __init__(self): # Check for updates first (required for use in header) self.update_checker = UpdateChecker() Header.show(self) if 'nowPlaying' in Dict and type(Dict['nowPlaying']) is dict: self.cleanup() Dict.Save() else: Dict['nowPlaying'] = dict() Main.update_config() self.session_manager = SessionManager() PlexActivity.on_update_collection.subscribe(self.update_collection)
def __init__(self): self.update_checker = UpdateChecker() self.session_manager = SessionManager() Header.show(self) if 'nowPlaying' in Dict and type(Dict['nowPlaying']) is dict: self.cleanup() Dict.Save() else: Dict['nowPlaying'] = dict() Main.update_config() # Initialize modules for module in self.modules: if hasattr(module, 'initialize'): log.debug("Initializing module %s", module) module.initialize()
class Main(object): modules = [ # core UpdateChecker() ] def __init__(self): Header.show(self) # Initial configuration update self.on_configuration_changed() # Initialize clients self.init_trakt() self.init_plex() self.init() # Initialize modules ModuleManager.initialize() def init(self): names = [] # Initialize modules for module in self.modules: names.append(get_class_name(module)) if hasattr(module, 'initialize'): module.initialize() log.info('Initialized %s modules: %s', len(names), ', '.join(names)) @staticmethod def init_plex(): # Ensure client identifier has been generated if not Dict['plex.client.identifier']: # Generate identifier Dict['plex.client.identifier'] = uuid.uuid4() # Retrieve current client identifier client_id = Dict['plex.client.identifier'] if isinstance(client_id, uuid.UUID): client_id = str(client_id) # plex.py Plex.configuration.defaults.authentication(os.environ.get('PLEXTOKEN')) Plex.configuration.defaults.client(identifier=client_id, product='trakt (for Plex)', version=PLUGIN_VERSION) # plex.activity.py path = os.path.join(LOG_HANDLER.baseFilename, '..', '..', 'Plex Media Server.log') path = os.path.abspath(path) Activity['logging'].add_hint(path) # plex.metadata.py Metadata.configure(client=Plex.client) @classmethod def init_trakt(cls): config = Configuration.advanced['trakt'] # Build timeout value timeout = (config.get_float('connect_timeout', 6.05), config.get_float('read_timeout', 24)) # Client Trakt.configuration.defaults.client( id= 'c9ccd3684988a7862a8542ae0000535e0fbd2d1c0ca35583af7ea4e784650a61', secret= 'bf00575b1ad252b514f14b2c6171fe650d474091daad5eb6fa890ef24d581f65') # Application Trakt.configuration.defaults.app(name='trakt (for Plex)', version=PLUGIN_VERSION) # Http Trakt.base_url = (config.get('protocol', 'https') + '://' + config.get('hostname', 'api.trakt.tv')) Trakt.configuration.defaults.http(timeout=timeout) # Configure keep-alive Trakt.http.keep_alive = config.get_boolean('keep_alive', True) # Configure requests adapter Trakt.http.adapter_kwargs = { 'pool_connections': config.get_int('pool_connections', 10), 'pool_maxsize': config.get_int('pool_size', 10), 'max_retries': Retry(total=config.get_int('connect_retries', 3), read=0) } Trakt.http.rebuild() # Bind to events Trakt.on('oauth.refresh', cls.on_trakt_refresh) Trakt.on('oauth.refresh.rejected', cls.on_trakt_refresh_rejected) log.info( 'Configured trakt.py (timeout=%r, base_url=%r, keep_alive=%r, adapter_kwargs=%r)', timeout, Trakt.base_url, Trakt.http.keep_alive, Trakt.http.adapter_kwargs, ) @classmethod def on_trakt_refresh(cls, username, authorization): log.debug('[Trakt.tv] Token has been refreshed for %r', username) # Retrieve trakt account matching this `authorization` with Trakt.configuration.http(retry=True).oauth( token=authorization.get('access_token')): settings = Trakt['users/settings'].get(validate_token=False) if not settings: log.warn('[Trakt.tv] Unable to retrieve account details for token') return False # Retrieve trakt account username from `settings` s_username = settings.get('user', {}).get('username') if not s_username: log.warn('[Trakt.tv] Unable to retrieve username for token') return False if s_username != username: log.warn('[Trakt.tv] Token mismatch (%r != %r)', s_username, username) return False # Find matching trakt account trakt_account = (TraktAccount.select().where( TraktAccount.username == username)).first() if not trakt_account: log.warn('[Trakt.tv] Unable to find account with the username: %r', username) return False # Update OAuth credential TraktAccountManager.update.from_dict( trakt_account, {'authorization': { 'oauth': authorization }}, settings=settings) log.info('[Trakt.tv] Token updated for %r', trakt_account) return True @classmethod def on_trakt_refresh_rejected(cls, username): log.debug('[Trakt.tv] Token refresh for %r has been rejected', username) # Find matching trakt account account = (TraktAccount.select().where( TraktAccount.username == username)).first() if not account: log.warn('[Trakt.tv] Unable to find account with the username: %r', username) return False # Delete OAuth credential TraktOAuthCredentialManager.delete(account=account.id) log.info('[Trakt.tv] Token cleared for %r', account) return True def start(self): # Construct main thread spawn(self.run, daemon=True, thread_name='main') def run(self): # Check for authentication token log.info('X-Plex-Token: %s', 'available' if os.environ.get('PLEXTOKEN') else 'unavailable') # Process server startup state self.process_server_state() # Start new-style modules module_start() # Start modules names = [] for module in self.modules: if not hasattr(module, 'start'): continue names.append(get_class_name(module)) module.start() log.info('Started %s modules: %s', len(names), ', '.join(names)) ModuleManager.start() # Start plex.activity.py Activity.start(ACTIVITY_MODE.get(Preferences.get('activity.mode'))) @classmethod def process_server_state(cls): # Check startup state server = Plex.detail() if server is None: log.info('Unable to check startup state, detail request failed') return # Check server startup state if server.start_state is None: return if server.start_state == 'startingPlugins': return cls.on_starting_plugins() log.error('Unhandled server start state %r', server.start_state) @staticmethod def on_starting_plugins(): log.debug('on_starting_plugins') SessionPrefix.increment() @classmethod def on_configuration_changed(cls): # Update proxies (for requests) cls.update_proxies() # Refresh loggers LoggerManager.refresh() @staticmethod def update_proxies(): # Retrieve proxy host host = Prefs['proxy_host'] if not host: if not Trakt.http.proxies and not os.environ.get( 'HTTP_PROXY') and not os.environ.get('HTTPS_PROXY'): return # Update trakt client Trakt.http.proxies = {} # Update environment variables if 'HTTP_PROXY' in os.environ: del os.environ['HTTP_PROXY'] if 'HTTPS_PROXY' in os.environ: del os.environ['HTTPS_PROXY'] log.info('HTTP Proxy has been disabled') return # Parse URL host_parsed = urlsplit(host) # Expand components scheme, netloc, path, query, fragment = host_parsed if not scheme: scheme = 'http' # Retrieve proxy credentials username = Prefs['proxy_username'] password = Prefs['proxy_password'] # Build URL if username and password and '@' not in netloc: netloc = '%s:%s@%s' % (quote_plus(username), quote_plus(password), netloc) url = urlunsplit((scheme, netloc, path, query, fragment)) # Update trakt client Trakt.http.proxies = {'http': url, 'https': url} # Update environment variables os.environ.update({'HTTP_PROXY': url, 'HTTPS_PROXY': url}) # Display message in log file if not host_parsed.username and not host_parsed.password: log.info('HTTP Proxy has been enabled (host: %r)', host) else: log.info('HTTP Proxy has been enabled (host: <sensitive>)')
class Main(object): modules = [ # pts Activity, Scrobbler, # sync SyncManager, # plex PlexMetadata ] loggers_allowed = [ 'requests', 'trakt' ] def __init__(self): self.update_checker = UpdateChecker() self.session_manager = SessionManager() Header.show(self) if 'nowPlaying' in Dict and type(Dict['nowPlaying']) is dict: self.cleanup() Dict.Save() else: Dict['nowPlaying'] = dict() Main.update_config() self.init_logging() self.init_trakt() # Initialize modules for module in self.modules: if hasattr(module, 'initialize'): log.debug("Initializing module %s", module) module.initialize() @classmethod def init_logging(cls): logging.basicConfig(level=logging.DEBUG) for name in cls.loggers_allowed: logger = logging.getLogger(name) logger.setLevel(logging.DEBUG) logger.handlers = [PlexHandler()] @staticmethod def init_trakt(): def get_credentials(): password_hash = hashlib.sha1(Prefs['password']) return ( Prefs['username'], password_hash.hexdigest() ) Trakt.configure( # Application api_key='ba5aa61249c02dc5406232da20f6e768f3c82b28', # Version plugin_version=PLUGIN_VERSION, media_center_version=PlexMediaServer.get_version(), # Account credentials=get_credentials ) @classmethod def update_config(cls, valid=None): preferences = Dict['preferences'] or {} # If no validation provided, use last stored result or assume true if valid is None: valid = preferences.get('valid', True) preferences['valid'] = valid Configuration.process(preferences) # Ensure preferences dictionary is stored Dict['preferences'] = preferences Dict.Save() log.info('Preferences updated %s', preferences) EventManager.fire('preferences.updated', preferences) @classmethod def validate_auth(cls, retry_interval=30): if not Prefs['username'] or not Prefs['password']: log.warn('Authentication failed, username or password field empty') cls.update_config(False) return False success = Trakt['account'].test() if not success: # status - False = invalid credentials, None = request failed if success is False: log.warn('Authentication failed, username or password is incorrect') else: # Increase retry interval each time to a maximum of 30 minutes if retry_interval < 60 * 30: retry_interval = int(retry_interval * 1.3) # Ensure we never go over 30 minutes if retry_interval > 60 * 30: retry_interval = 60 * 30 log.warn('Unable to verify account details, will try again in %s seconds', retry_interval) schedule(cls.validate_auth, retry_interval, retry_interval) Main.update_config(False) return False log.info('Authentication successful') Main.update_config(True) return True def start(self): # Validate username/password spawn(self.validate_auth) # Check for updates self.update_checker.run_once(async=True) self.session_manager.start() # Start modules for module in self.modules: if hasattr(module, 'start'): log.debug("Starting module %s", module) module.start() @staticmethod def cleanup(): Log.Debug('Cleaning up stale or invalid sessions') for key, session in Dict['nowPlaying'].items(): delete = False # Destroy invalid sessions if type(session) is not dict: delete = True elif 'update_required' not in session: delete = True elif 'last_updated' not in session: delete = True elif type(session['last_updated']) is not datetime: delete = True elif total_seconds(datetime.now() - session['last_updated']) / 60 / 60 > 24: # Destroy sessions last updated over 24 hours ago Log.Debug('Session %s was last updated over 24 hours ago, queued for deletion', key) delete = True # Delete session or flag for update if delete: Log.Info('Session %s looks stale or invalid, deleting it now', key) del Dict['nowPlaying'][key] elif not session['update_required']: Log.Info('Queueing session %s for update', key) session['update_required'] = True # Update session in storage Dict['nowPlaying'][key] = session Log.Debug('Finished cleaning up')
class Main: def __init__(self): # Check for updates first (required for use in header) self.update_checker = UpdateChecker() Header.show(self) if 'nowPlaying' in Dict and type(Dict['nowPlaying']) is dict: self.cleanup() Dict.Save() else: Dict['nowPlaying'] = dict() Main.update_config() self.session_manager = SessionManager() PlexActivity.on_update_collection.subscribe(self.update_collection) @staticmethod def update_config(): if Prefs['start_scrobble'] and Prefs['username'] is not None: Log('Autostart scrobbling') Dict["scrobble"] = True else: Dict["scrobble"] = False if Prefs['new_sync_collection'] and Prefs['username'] is not None: Log('Automatically sync new Items to Collection') Dict["new_sync_collection"] = True else: Dict["new_sync_collection"] = False def start(self): # Start syncing if Prefs['sync_startup'] and Prefs['username'] is not None: Log('Will autosync in 1 minute') Thread.CreateTimer(60, SyncTrakt) # Get current server version and save it to dict. server_version = PMS.get_server_version() if server_version: Log('Server Version is %s' % server_version) Dict['server_version'] = server_version # Start the plex activity monitor Thread.Create(PlexActivity.run) self.update_checker.run_once(async=True) self.session_manager.start() @staticmethod def update_collection(item_id, action): # delay sync to wait for metadata Thread.CreateTimer(120, CollectionSync, True, item_id, 'add') @staticmethod def cleanup(): Log.Debug('Cleaning up stale or invalid sessions') for key, session in Dict['nowPlaying'].items(): delete = False # Destroy invalid sessions if type(session) is not dict: delete = True elif 'update_required' not in session: delete = True elif 'last_updated' not in session: delete = True elif type(session['last_updated']) is not datetime: delete = True elif total_seconds(datetime.now() - session['last_updated']) / 60 / 60 > 24: # Destroy sessions last updated over 24 hours ago Log.Debug('Session %s was last updated over 24 hours ago, queued for deletion', key) delete = True # Delete session or flag for update if delete: Log.Info('Session %s looks stale or invalid, deleting it now', key) del Dict['nowPlaying'][key] elif not session['update_required']: Log.Info('Queueing session %s for update', key) session['update_required'] = True # Update session in storage Dict['nowPlaying'][key] = session Log.Debug('Finished cleaning up')
class Main(object): modules = [ # pts Activity, Scrobbler, # sync SyncManager, # plex PlexMetadata ] def __init__(self): self.update_checker = UpdateChecker() self.session_manager = SessionManager() Header.show(self) if 'nowPlaying' in Dict and type(Dict['nowPlaying']) is dict: self.cleanup() Dict.Save() else: Dict['nowPlaying'] = dict() Main.update_config() # Initialize modules for module in self.modules: if hasattr(module, 'initialize'): log.debug("Initializing module %s", module) module.initialize() @classmethod def update_config(cls, valid=None): preferences = Dict['preferences'] or {} # If no validation provided, use last stored result or assume true if valid is None: valid = preferences.get('valid', True) preferences['valid'] = valid Configuration.process(preferences) # Ensure preferences dictionary is stored Dict['preferences'] = preferences Dict.Save() log.info('Preferences updated %s', preferences) EventManager.fire('preferences.updated', preferences) @classmethod def validate_auth(cls, retry_interval=30): if not Prefs['username'] or not Prefs['password']: log.warn('Authentication failed, username or password field empty') cls.update_config(False) return False status = Trakt.Account.test() if not status['success']: if status.get('status') == 'failure': log.warn('Authentication failed, username or password is incorrect (trakt returned: %s)', status['message']) else: # Increase retry interval each time to a maximum of 30 minutes if retry_interval < 60 * 30: retry_interval = int(retry_interval * 1.3) # Ensure we never go over 30 minutes if retry_interval > 60 * 30: retry_interval = 60 * 30 log.warn('Unable to verify account details, will try again in %s seconds', retry_interval) schedule(cls.validate_auth, retry_interval, retry_interval) Main.update_config(False) return False log.info('Authentication successful') Main.update_config(True) return True def start(self): # Get current server version and save it to dict. server_version = PlexMediaServer.get_version() if server_version: Log('Server Version is %s' % server_version) Dict['server_version'] = server_version # Validate username/password spawn(self.validate_auth) # Check for updates self.update_checker.run_once(async=True) self.session_manager.start() # Start modules for module in self.modules: if hasattr(module, 'start'): log.debug("Starting module %s", module) module.start() @staticmethod def cleanup(): Log.Debug('Cleaning up stale or invalid sessions') for key, session in Dict['nowPlaying'].items(): delete = False # Destroy invalid sessions if type(session) is not dict: delete = True elif 'update_required' not in session: delete = True elif 'last_updated' not in session: delete = True elif type(session['last_updated']) is not datetime: delete = True elif total_seconds(datetime.now() - session['last_updated']) / 60 / 60 > 24: # Destroy sessions last updated over 24 hours ago Log.Debug('Session %s was last updated over 24 hours ago, queued for deletion', key) delete = True # Delete session or flag for update if delete: Log.Info('Session %s looks stale or invalid, deleting it now', key) del Dict['nowPlaying'][key] elif not session['update_required']: Log.Info('Queueing session %s for update', key) session['update_required'] = True # Update session in storage Dict['nowPlaying'][key] = session Log.Debug('Finished cleaning up')
class Main(object): modules = [ # core UpdateChecker() ] def __init__(self): Header.show(self) LoggerManager.refresh() self.init_trakt() self.init_plex() self.init() ModuleManager.initialize() def init(self): names = [] # Initialize modules for module in self.modules: names.append(get_class_name(module)) if hasattr(module, 'initialize'): module.initialize() log.info('Initialized %s modules: %s', len(names), ', '.join(names)) @staticmethod def init_plex(): # Ensure client identifier has been generated if not Dict['plex.client.identifier']: # Generate identifier Dict['plex.client.identifier'] = uuid.uuid4() # plex.py Plex.configuration.defaults.authentication( os.environ.get('PLEXTOKEN') ) Plex.configuration.defaults.client( identifier=Dict['plex.client.identifier'], product='trakt (for Plex)', version=PLUGIN_VERSION ) # plex.activity.py path = os.path.join(LOG_HANDLER.baseFilename, '..', '..', 'Plex Media Server.log') path = os.path.abspath(path) Activity['logging'].add_hint(path) # plex.metadata.py Metadata.configure( cache=CacheManager.get( 'plex.metadata', serializer='pickle:///?protocol=2' ), client=Plex.client ) @classmethod def init_trakt(cls): # Client Trakt.configuration.defaults.client( id='c9ccd3684988a7862a8542ae0000535e0fbd2d1c0ca35583af7ea4e784650a61', secret='bf00575b1ad252b514f14b2c6171fe650d474091daad5eb6fa890ef24d581f65' ) # Application Trakt.configuration.defaults.app( name='trakt (for Plex)', version=PLUGIN_VERSION ) # Setup request retrying Trakt.http.adapter_kwargs = {'max_retries': Retry(total=3, read=0)} Trakt.http.rebuild() Trakt.on('oauth.token_refreshed', cls.on_token_refreshed) @classmethod def on_token_refreshed(cls, authorization): log.debug('Authentication - PIN authorization refreshed') # Retrieve trakt account matching this `authorization` with Trakt.configuration.http(retry=True).oauth(token=authorization.get('access_token')): settings = Trakt['users/settings'].get() if not settings: log.warn('Authentication - Unable to retrieve account details for authorization') return # Retrieve trakt account username from `settings` username = settings.get('user', {}).get('username') if not username: log.warn('Authentication - Unable to retrieve username for authorization') return None # Find matching trakt account trakt_account = (TraktAccount .select() .where( TraktAccount.username == username ) ).first() if not trakt_account: log.warn('Authentication - Unable to find TraktAccount with the username %r', username) # Update oauth credential TraktAccountManager.update.from_dict(trakt_account, { 'authorization': { 'oauth': authorization } }) log.info('Authentication - Updated OAuth credential for %r', trakt_account) def start(self): # Construct main thread spawn(self.run, thread_name='main') def run(self): # Check for authentication token log.info('X-Plex-Token: %s', 'available' if os.environ.get('PLEXTOKEN') else 'unavailable') # Process server startup state self.process_server_state() # Start new-style modules module_start() # Start modules names = [] for module in self.modules: if not hasattr(module, 'start'): continue names.append(get_class_name(module)) module.start() log.info('Started %s modules: %s', len(names), ', '.join(names)) ModuleManager.start() # Start plex.activity.py Activity.start(ACTIVITY_MODE.get(Preferences.get('activity.mode'))) @classmethod def process_server_state(cls): # Check startup state server = Plex.detail() if server is None: log.info('Unable to check startup state, detail request failed') return # Check server startup state if server.start_state is None: return if server.start_state == 'startingPlugins': return cls.on_starting_plugins() log.error('Unhandled server start state %r', server.start_state) @staticmethod def on_starting_plugins(): log.debug('on_starting_plugins') SessionPrefix.increment() @staticmethod def on_configuration_changed(): LoggerManager.refresh()