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
Example #2
0
    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 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
Example #6
0
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
Example #7
0
    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))
Example #8
0
    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
Example #11
0
    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
Example #12
0
    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))
Example #13
0
    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)
        )
Example #14
0
        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
            )
Example #15
0
    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))
Example #16
0
        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)
Example #17
0
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!')
Example #18
0
    def delete_directory(path, conditions=None):
        if not all([c(path) for c in conditions]):
            return False

        shutil.rmtree(path)
        return True
Example #19
0
    def delete_file(path, conditions=None):
        if not all([c(path) for c in conditions]):
            return False

        os.remove(path)
        return True
Example #20
0
    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')))
Example #21
0
    def delete_file(path, conditions=None):
        if not all([c(path) for c in conditions]):
            return False

        os.remove(path)
        return True
Example #22
0
    def delete_directory(path, conditions=None):
        if not all([c(path) for c in conditions]):
            return False

        shutil.rmtree(path)
        return True
Example #23
0
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!')