def run(self, *args, **kwargs): self.reset(kwargs.get('artifacts')) # Trigger handlers and return if there was an error exceptions, results = self.trigger(None, *args, **kwargs) if not all(results): self.update_status(False) return False # Create "http" cache for this task cache_key = 'http.%s.%s' % (self.get_sid(), self.key) cache = CacheManager.open(cache_key) with Plex.configuration.cache(http=cache): # Trigger children and return if there was an error exceptions, results = self.trigger_children(*args, **kwargs) # Discard HTTP cache CacheManager.delete(cache_key) if not all(results): self.update_status(False, exceptions=exceptions) return False self.update_status(True) return True
def run(self, *args, **kwargs): self.reset(kwargs.get('artifacts')) # Trigger handlers and return if there was an error if not all(self.trigger(None, *args, **kwargs)): self.update_status(False) return False # Trigger children and return if there was an error if not all(self.trigger_children(*args, **kwargs)): self.update_status(False) return False self.update_status(True) return True
def get_sections(cls, types=None, keys=None, titles=None, cache_id=None): """Get the current sections available on the server, optionally filtering by type and/or key :param types: Section type filter :type types: str or list of str :param keys: Section key filter :type keys: str or list of str :return: List of sections found :rtype: (type, key, title) """ if types and isinstance(types, basestring): types = [types] if keys and isinstance(keys, basestring): keys = [keys] if titles: if isinstance(titles, basestring): titles = [titles] titles = [x.lower() for x in titles] container = cls.request('library/sections', cache_id=cache_id) sections = [] for section in container: # Try retrieve section details - (type, key, title) section = ( section.get('type', None), section.get('key', None), section.get('title', None) ) # Validate section, skip over bad sections if not all(x for x in section): continue # Apply type filter if types is not None and section[0] not in types: continue # Apply key filter if keys is not None and section[1] not in keys: continue # Apply title filter if titles is not None and section[2].lower() not in titles: continue sections.append(section) return sections
def get_sections(cls, types=None, keys=None, titles=None, cache_id=None): """Get the current sections available on the server, optionally filtering by type and/or key :param types: Section type filter :type types: str or list of str :param keys: Section key filter :type keys: str or list of str :return: List of sections found :rtype: (type, key, title) """ if types and isinstance(types, basestring): types = [types] if keys and isinstance(keys, basestring): keys = [keys] if titles: if isinstance(titles, basestring): titles = [titles] titles = [x.lower() for x in titles] container = cls.request('library/sections', cache_id=cache_id) sections = [] for section in container: # Try retrieve section details - (type, key, title) section = (section.get('type', None), section.get('key', None), section.get('title', None)) # Validate section, skip over bad sections if not all(x for x in section): continue # Apply type filter if types is not None and section[0] not in types: continue # Apply key filter if keys is not None and section[1] not in keys: continue # Apply title filter if titles is not None and section[2].lower() not in titles: continue sections.append(section) return sections
def itersections(types=('show', 'movie')): """Iterate over valid PMS sections of type 'show' or 'movie'""" result = [] for section in [parse_section(s) for s in PMS.get_sections()]: # Ensure fields exist if all(v is not None for v in section): section_type, key, title = section # Ensure section is of type 'show' or 'movie' if section_type in types: result.append((section_type, key, title)) return result
def watch(self, key, p_items, t_item, include_identifier=True): if type(p_items) is not list: p_items = [p_items] # Ignore if trakt movie is already watched if t_item and t_item.is_watched: return True # Ignore if none of the plex items are watched if all([not x.seen for x in p_items]): return True # TODO should we instead pick the best result, instead of just the first? self.store('watched', self.plex.to_trakt(key, p_items[0], include_identifier))
def process(self, line): match = CLIENT_REGEX.match(line) if not match: return info = match.groupdict() if info.get('trailing'): info.update(dict(CLIENT_PARAM_REGEX.findall(info.pop('trailing')))) valid = all([key in info for key in self.required_info]) if valid: self.scrobbler.update(info)
def process_playing(item): session_key = item.get('sessionKey') state = item.get('state') view_offset = try_convert(item.get('viewOffset'), int) valid = all([x is not None for x in [session_key, state, view_offset]]) if valid: EventManager.fire('notifications.playing', str(session_key), str(state), view_offset) return True log.warn("'playing' notification doesn't look valid, ignoring: %s" % item) return False
def process_playing(item): session_key = item.get('sessionKey') state = item.get('state') view_offset = try_convert(item.get('viewOffset'), int) valid = all([ x is not None for x in [session_key, state, view_offset] ]) if valid: EventManager.fire('notifications.playing', str(session_key), str(state), view_offset) return True log.warn("'playing' notification doesn't look valid, ignoring: %s" % item) return False
def watch(self, key, p_items, t_item): if type(p_items) is not list: p_items = [p_items] # Ignore if trakt movie is already watched if t_item and t_item.is_watched: return True # Ignore if none of the plex items are watched if all([not x.seen for x in p_items]): return True # Ignore if we are currently watching this item if WatchSession.is_active(p_items[0].rating_key): log.trace("[P #%s] ignored - item is currently being watched", p_items[0].rating_key) return True # Build item which can be sent to trakt item = ActionHelper.plex.to_trakt(key, p_items[0]) if not item: log.warn('watch() - Ignored for unmatched media "%s" [%s]', p_items[0].title, key) return True # Check action against history history = ActionManager.history.get(p_items[0].rating_key, {}) if not ActionManager.valid_action("add", history): log.debug( 'watch() - Invalid action for "%s" [%s] (already scrobbled or duplicate action)', p_items[0].title, key ) return True # Mark item as added in `pts.action_manager` ActionManager.update_history(p_items[0].rating_key, "add", "add") # Set "watched_at" parameter (if available) watched_at = self.get_datetime(p_items[0], "last_viewed_at") if watched_at: item["watched_at"] = watched_at # Store item in "watched" collection self.store("watched", item) return True
def discover_missing(self, t_shows): # Ensure collection cleaning is enabled if not Prefs['sync_clean_collection']: return log.info('Searching for shows/episodes that are missing from plex') # Find collected shows that are missing from Plex t_collection_missing = self.get_missing(t_shows, is_collected=False) # Discover entire shows missing num_shows = 0 for key, t_show in t_collection_missing.items(): # Ignore show if there are no collected episodes on trakt if all([not e.is_collected for (_, e) in t_show.episodes.items()]): continue self.store('missing.shows', t_show.to_info()) num_shows = num_shows + 1 # Discover episodes missing num_episodes = 0 for key, t_show in t_shows.items(): if t_show.pk in t_collection_missing: continue t_episodes_missing = self.get_missing(t_show.episodes) if not t_episodes_missing: continue self.store_episodes('missing.episodes', t_show.to_info(), episodes=[ x.to_info() for x in t_episodes_missing.itervalues() ]) num_episodes = num_episodes + len(t_episodes_missing) log.info('Found %s show%s and %s episode%s missing from plex', num_shows, plural(num_shows), num_episodes, plural(num_episodes))
def discover_missing(self, t_shows): # Ensure collection cleaning is enabled if not Prefs['sync_clean_collection']: return log.info('Searching for shows/episodes that are missing from plex') # Find collected shows that are missing from Plex t_collection_missing = self.get_missing(t_shows, is_collected=False) # Discover entire shows missing num_shows = 0 for key, t_show in t_collection_missing.items(): # Ignore show if there are no collected episodes on trakt if all([not e.is_collected for (_, e) in t_show.episodes.items()]): continue self.store('missing.shows', t_show.to_info()) num_shows = num_shows + 1 # Discover episodes missing num_episodes = 0 for key, t_show in t_shows.items(): if t_show.pk in t_collection_missing: continue t_episodes_missing = self.get_missing(t_show.episodes) if not t_episodes_missing: continue self.store_episodes( 'missing.episodes', t_show.to_info(), episodes=[x.to_info() for x in t_episodes_missing.itervalues()] ) num_episodes = num_episodes + len(t_episodes_missing) log.info( 'Found %s show%s and %s episode%s missing from plex', num_shows, plural(num_shows), num_episodes, plural(num_episodes) )
def action(media_type, action, retry=False, timeout=None, max_retries=3, **kwargs): if not all([x in kwargs for x in ['duration', 'progress', 'title']]): raise ValueError() # Retry scrobble requests as they are important (compared to watching requests) if action == 'scrobble': # Only change these values if they aren't already set retry = retry or True timeout = timeout or 3 max_retries = 5 return Trakt.request( media_type + '/' + action, kwargs, retry=retry, max_retries=max_retries, timeout=timeout )
def watch(self, key, p_items, t_item, include_identifier=True): if type(p_items) is not list: p_items = [p_items] # Ignore if trakt movie is already watched if t_item and t_item.is_watched: return True # Ignore if none of the plex items are watched if all([not x.seen for x in p_items]): return True # Ignore if we are currently watching this item if self.is_watching(p_items[0]): log.trace('[P #%s] ignored - item is currently being watched', p_items[0].rating_key) return True # TODO should we instead pick the best result, instead of just the first? self.store('watched', self.plex.to_trakt(key, p_items[0], include_identifier))
def action(media_type, action, retry=False, timeout=None, max_retries=3, **kwargs): if not all( [x in kwargs for x in ['duration', 'progress', 'title']]): raise ValueError() # Retry scrobble requests as they are important (compared to watching requests) if action == 'scrobble': # Only change these values if they aren't already set retry = retry or True timeout = timeout or 3 max_retries = 5 return Trakt.request(media_type + '/' + action, kwargs, authenticate=True, retry=retry, max_retries=max_retries, timeout=timeout)
def ManuallyTrakt(): if Prefs['username'] is None: Log.Info('You need to enter you login information first.') return MessageContainer('Login information missing', 'You need to enter you login information first.') if Prefs['sync_watched'] is not True and Prefs['sync_ratings'] is not True: Log.Info('You need to enable at least one type of actions to sync first.') return MessageContainer('No type selected', 'You need to enable at least one type of actions to sync first.') values = {'extended': 'min'} movie_list = None show_list = None movies_rated_list = None episodes_rated_list = None # Get watched and rated lists from trakt if Prefs['sync_watched'] is True: movie_list = Trakt.request( 'user/library/movies/watched.json', values, param=Prefs['username'] ).get('data') show_list = Trakt.request( 'user/library/shows/watched.json', values, param=Prefs['username'] ).get('data') if not all([x is not None for x in [movie_list, show_list]]): return MessageContainer('Network error', 'Network error while requesting watched items from trakt.') if Prefs['sync_ratings'] is True: movies_rated_list = Trakt.request( 'user/ratings/movies.json', values, param=Prefs['username'] ).get('data') episodes_rated_list = Trakt.request( 'user/ratings/episodes.json', values, param=Prefs['username'] ).get('data') if not all([x is not None for x in [movies_rated_list, episodes_rated_list]]): return MessageContainer('Network error', 'Network error while requesting rated items from trakt.') # Go through the Plex library and update flags for section_type, key, title in itersections(): # Sync movies if section_type == 'movie': for video in PMS.get_section_videos(key): pull_movie(movie_list, movies_rated_list, video) # Sync TV Shows if section_type == 'show': for directory in PMS.get_section_directories(key): tvdb_id = match_tvdb_id(directory.get('ratingKey')) if not tvdb_id: continue if tvdb_id is not None: pull_show(show_list, episodes_rated_list, directory, tvdb_id) Log.Info('Syncing is done!') Dict['Last_sync_down'] = Datetime.Now() return MessageContainer('Done', 'Syncing is done!')
def delete_directory(path, conditions=None): if not all([c(path) for c in conditions]): return False shutil.rmtree(path) return True
def delete_file(path, conditions=None): if not all([c(path) for c in conditions]): return False os.remove(path) return True
def discover_missing(self, t_shows): # Ensure collection cleaning is enabled if not Prefs['sync_clean_collection']: return log.info('Searching for shows/episodes that are missing from plex') for key, t_show in t_shows.iteritems(): # Ignore show if there are no collected episodes on trakt if all([not e.is_collected for (_, e) in t_show.episodes()]): continue show = t_show.to_identifier() if self.is_missing(t_show): # Entire show is missing log.debug('Unable to find "%s" [%s] in plex', t_show.title, key) self.store('missing.shows', show) continue # Create 'seasons' list if 'seasons' not in show: show['seasons'] = [] for sk, t_season in t_show.seasons.iteritems(): # Ignore season if there are no collected episodes on trakt if all([not e.is_collected for e in t_season.episodes.values()]): continue i_season = {'number': sk} if self.is_missing(t_season): # Entire season is missing log.debug('Unable to find S%02d of "%s" [%s] in plex', sk, t_show.title, key) show['seasons'].append(i_season) continue # Create 'episodes' list if 'episodes' not in i_season: i_season['episodes'] = [] for ek, t_episode in t_season.episodes.iteritems(): if not self.is_missing(t_episode): continue log.debug('Unable to find S%02dE%02d of "%s" [%s] in plex', sk, ek, t_show.title, key) # Append episode to season dict i_season['episodes'].append({'number': ek}) if not i_season['episodes']: # Couldn't find any missing episodes in this season continue # Append season to show dict show['seasons'].append(i_season) if not show['seasons']: # Couldn't find any missing seasons/episodes continue self.store('missing.shows', show) log.info('Discovered %s show(s) with missing items', len(self.retrieve('missing.shows')))
def SyncSection(key): if Prefs['username'] is None: Log.Info('You need to enter you login information first.') return MessageContainer( 'Login information missing', 'You need to enter you login information first.' ) prefs = (Prefs['sync_watched'], Prefs['sync_ratings'], Prefs['sync_collection']) if all(x is not True for x in prefs): Log.Info('You need to enable at least one type of actions to sync first.') return MessageContainer( 'No type selected', 'You need to enable at least one type of actions to sync first.' ) # Sync the library with trakt.tv all_movies = [] all_episodes = [] ratings_movies = [] ratings_episodes = [] collection_movies = [] collection_episodes = [] for value in key.split(','): section = PMS.get_section(value) if not section: Log.Warn('Unable to get section with key "%s"' % value) continue item_kind = section.xpath('//MediaContainer')[0].get('viewGroup') # Sync movies if item_kind == 'movie': for video in PMS.get_section_videos(value): push_movie(all_movies, collection_movies, ratings_movies, video) # Sync TV Shows if item_kind == 'show': for directory in PMS.get_section_directories(value): push_show(all_episodes, collection_episodes, ratings_episodes, directory) Log.Info('Found %s movies' % len(all_movies)) Log.Info('Found %s series' % len(all_episodes)) if Prefs['sync_ratings'] is True: if len(ratings_episodes) > 0: Trakt.request('rate/episodes', { 'episodes': ratings_episodes }) if len(ratings_movies) > 0: Trakt.request('rate/movies', { 'movies': ratings_movies }) if Prefs['sync_watched'] is True: if len(all_movies) > 0: Trakt.request('movie/seen', { 'movies': all_movies }) for episode in all_episodes: Trakt.request('show/episode/seen', episode) if Prefs['sync_collection'] is True: if len(collection_movies) > 0: Trakt.request('movie/library', { 'movies': collection_movies }) for episode in collection_episodes: Trakt.request('show/episode/library', episode) Log.Info('Syncing is done!') Dict['Last_sync_up'] = Datetime.Now() return MessageContainer('Done', 'Syncing is done!')