def push_movie(all_movies, collected, rated, video):
    pms_metadata = None

    if Prefs['sync_collection'] is True:
        pms_metadata = PMS.metadata(video.get('ratingKey'))
        collected.append(pms_metadata)

    if video.get('viewCount') > 0:
        Log.Debug('You have seen %s', video.get('title'))
        if video.get('type') == 'movie':
            if pms_metadata is None:
                pms_metadata = PMS.metadata(video.get('ratingKey'))

            movie_dict = pms_metadata
            #movie_dict['plays'] = int(video.get('viewCount'))
            #movie_dict.pop('duration')

            all_movies.append(movie_dict)
        else:
            Log.Info('Unknown item %s' % video.get('ratingKey'))

    if video.get('userRating') is not None:
        if pms_metadata is None:
            pms_metadata = PMS.metadata(video.get('ratingKey'))

        rating_movie = pms_metadata
        rating_movie['rating'] = int(video.get('userRating'))

        rated.append(rating_movie)
Exemple #2
0
def pull_movie(watched, rated, video):
    key = video.get('ratingKey')

    # Pull metadata
    metadata = PMS.metadata(key)

    if not metadata:
        Log.Warn('Invalid metadata with key %s, network error' % key)
        return

    if 'imdb_id' not in metadata and 'tmdb_id' not in metadata:
        Log.Warn('Invalid metadata with key %s, no IMDB or TMDB id available' % key)
        return

    # Sync watched
    if Prefs['sync_watched'] is True:
        for movie in finditems(metadata, watched, ['imdb_id', 'tmdb_id']):
            Log.Debug('Found %s with id %s' % (metadata['title'], key))

            if not PMS.scrobble(video):
                Log.Debug('The movie %s is already marked as seen in the library.' % metadata['title'])

    # Sync ratings
    if Prefs['sync_ratings'] is True:
        for movie in finditems(metadata, rated, ['imdb_id', 'tmdb_id']):
            Log.Debug('Found %s with id %s' % (metadata['title'], key))
            PMS.rate(video, movie['rating_advanced'])
    def create_session(self, session_key, state):
        """
        :type session_key: str
        :type state: str

        :rtype: WatchSession or None
        """

        Log.Debug("Creating a WatchSession for the current media")

        video_section = PMS.get_video_session(session_key)
        if not video_section:
            return None

        player_section = video_section.findall("Player")
        if len(player_section):
            player_section = player_section[0]

        session = WatchSession.from_section(
            video_section,
            state,
            PMS.metadata(video_section.get("ratingKey")),
            PMS.client(player_section.get("machineIdentifier")),
        )
        session.save()

        return session
    def create_session(self, info):
        client = None
        if info.get('machineIdentifier'):
            client = PMS.client(info['machineIdentifier'])
        else:
            Log.Info('No machineIdentifier available, client filtering not available')

        return WatchSession.from_info(
            info,
            PMS.metadata(info['ratingKey']),
            client
        )
    def test(cls):
        # Try enable logging
        if not PMS.set_logging_state(True):
            Log.Warn('Unable to enable logging')

        # Test if logging is enabled
        if not PMS.get_logging_state():
            Log.Warn('Debug logging not enabled, unable to use logging activity method.')
            return False

        if cls.try_read_line(True):
            return True

        return False
    def test(cls):
        if PMS.get_sessions() is None:
            Log.Info("Error while retrieving sessions, assuming WebSocket method isn't available")
            return False

        server_info = PMS.get_server_info()
        if server_info is None:
            Log.Info('Error while retrieving server info for testing')
            return False

        multi_user = bool(server_info.get('multiuser', 0))
        if not multi_user:
            Log.Info("Server info indicates multi-user support isn't available, WebSocket method not available")
            return False

        return True
    def update_session(self, session, view_offset):
        Log.Debug('Trying to update the current WatchSession (session key: %s)' % session.key)

        video_section = PMS.get_video_session(session.key)
        if not video_section:
            Log.Warn('Session was not found on media server')
            return False

        Log.Debug('last item key: %s, current item key: %s' % (session.item_key, video_section.get('ratingKey')))

        if session.item_key != video_section.get('ratingKey'):
            Log.Info('Invalid Session: Media changed')
            return False

        if not session.metadata:
            Log.Debug('Invalid Session: Missing metadata')
            return False

        if session.metadata.get('duration', 0) <= 0:
            Log.Debug('Invalid Session: Invalid duration')
            return False

        session.last_view_offset = view_offset
        session.update_required = False

        return True
    def update_session(self, session, view_offset):
        Log.Debug("Trying to update the current WatchSession (session key: %s)" % session.key)

        video_section = PMS.get_video_session(session.key)
        if not video_section:
            Log.Warn("Session was not found on media server")
            return False

        Log.Debug("last item key: %s, current item key: %s" % (session.item_key, video_section.get("ratingKey")))

        if session.item_key != video_section.get("ratingKey"):
            Log.Info("Invalid Session: Media changed")
            return False

        if not session.metadata:
            Log.Debug("Invalid Session: Missing metadata")
            return False

        if session.metadata.get("duration", 0) <= 0:
            Log.Debug("Invalid Session: Invalid duration")
            return False

        session.last_view_offset = view_offset
        session.update_required = False

        return True
def pull_show(watched, rated, directory, tvdb_id):
    # Sync watched
    if Prefs['sync_watched'] is True:
        for show in [x for x in watched if x['tvdb_id'] == tvdb_id]:
            Log.Debug('We have a match for %s' % show['title'])

            episodes = PMS.get_metadata_leaves(directory.get('ratingKey'))
            if not episodes:
                Log.Warn('Unable to fetch episodes for show with id %s' % directory.get('ratingKey'))
                continue

            for episode in episodes.xpath('//Video'):
                season_num = try_convert(episode.get('parentIndex'), int)
                episode_num = try_convert(episode.get('index'), int)

                # Skip episodes with missing season or episode numbers
                if season_num is None or episode_num is None:
                    continue

                for season in matches(season_num, show['seasons'], lambda x: int(x['season'])):

                    if episode_num in season['episodes']:
                        Log.Debug('Marking %s episode %s with key: %s as seen.' % (
                            episode.get('grandparentTitle'), episode.get('title'), episode.get('ratingKey')
                        ))

                        if not PMS.scrobble(episode):
                            Log.Debug('The episode %s is already marked as seen in the library.' % episode.get('title'))

    # Sync ratings
    if Prefs['sync_ratings'] is True:
        for show in [x for x in rated if x['show']['tvdb_id'] == tvdb_id]:
            show_season = try_convert(show['episode']['season'], int)
            show_episode = try_convert(show['episode']['number'], int)

            # Skip episodes with missing season or episode numbers
            if show_season is None or show_episode is None:
                continue

            episodes = PMS.get_metadata_leaves(directory.get('ratingKey'))
            if not episodes:
                Log.Warn('Unable to fetch episodes for show with id %s' % directory.get('ratingKey'))
                continue

            for episode in episodes.xpath('//Video'):
                if show_season == int(episode.get('parentIndex')) and show_episode == int(episode.get('index')):
                    PMS.rate(episode, show['rating_advanced'])
def CollectionSync(itemID, do):
    metadata = PMS.metadata(itemID)
    if not metadata:
        Log.Warn('Unable to fetch metadata for media with id %s' % itemID)
        return

    #cancel, if metadata is not there yet
    if not 'tvdb_id' in metadata and not 'imdb_id' in metadata and not 'tmdb_id' in metadata:
        return

    if do == 'add':
        do_action = 'library'
    elif do == 'delete':
        do_action = 'unlibrary'
    else:
        return

    action = None
    if metadata['type'] == 'episode':
        action = 'show/episode/%s' % do_action
    elif metadata['type'] == 'movie':
        action = 'movie/%s' % do_action

    # Setup Data to send to Trakt
    values = {}

    if metadata['type'] == 'episode':
        if not metadata.get('tvdb_id'):
            Log.Info('Added episode has no tvdb_id')
            return

        values['tvdb_id'] = metadata['tvdb_id']
        values['title'] = metadata['title']

        if 'year' in metadata:
            values['year'] = metadata['year']

        values['episodes'] = [{'season': metadata['season'], 'episode': metadata['episode']}]

    elif metadata['type'] == 'movie':
        if not metadata.get('imdb_id') and not metadata.get('tmdb_id'):
            Log.Info('Added movie has no imdb_id and no tmdb_id')
            return

        movie = {'title': metadata['title'], 'year': metadata['year']}

        if metadata['imdb_id']:
            movie['imdb_id'] = metadata['imdb_id']
        elif metadata['tmdb_id']:
            movie['tmdb_id'] = metadata['tmdb_id']

        values['movies'] = [movie]

    if action:
        Trakt.request(action, values)
def pull_movie(watched, rated, video):
    # Pull metadata
    metadata = PMS.metadata(video.get('ratingKey'))
    if not metadata or 'imdb_id' not in metadata:
        Log.Warn('Invalid metadata for movie with key %s (network error or missing IMDB ID)' % video.get('ratingKey'))
        return

    # Sync watched
    if Prefs['sync_watched'] is True:
        for movie in finditems(metadata, watched, 'imdb_id'):
            Log.Debug('Found %s with id %s' % (metadata['title'], video.get('ratingKey')))

            if not PMS.scrobble(video):
                Log.Debug('The movie %s is already marked as seen in the library.' % metadata['title'])

    # Sync ratings
    if Prefs['sync_ratings'] is True:
        for movie in finditems(metadata, rated, 'imdb_id'):
            Log.Debug('Found %s with id %s' % (metadata['title'], video.get('ratingKey')))
            PMS.rate(video, movie['rating_advanced'])
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 match_tvdb_id(rating_key):
    if not rating_key:
        Log.Warn("Guid matching failed, key isn't a valid string")
        return None

    guid = PMS.get_metadata_guid(rating_key)

    match = TVSHOW1_REGEXP.search(guid)
    if not match:
        Log.Warn('Guid matching failed on "%s"' % guid)
        return None

    return match.group(2)
    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()
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 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!')
def push_show(all_episodes, collected, rated, directory):
    tvdb_id = match_tvdb_id(directory.get('ratingKey'))
    if not tvdb_id:
        return

    tv_show = {
        'title': directory.get('title')
    }

    year = directory.get('year', None)
    if year is not None:
        tv_show['year'] = int(year)

    if tvdb_id is not None:
        tv_show['tvdb_id'] = tvdb_id

    seen_episodes = []
    collected_episodes = []

    episodes = PMS.get_metadata_leaves(directory.get('ratingKey'))
    if not episodes:
        Log.Warn('Unable to fetch episodes for show with id %s' % directory.get('ratingKey'))
        return

    for episode, parentIndex, index in iterget(episodes.xpath('//Video'), ['parentIndex', 'index']):
        # Ensure we have valid data
        if parentIndex is None or index is None:
            Log.Warn('Episode missing required data, skipping (key: %s)' % episode.get('ratingKey'))
            continue

        season_num = int(parentIndex)
        episode_num = int(index)

        base_episode = {
            'season': season_num,
            'episode': episode_num
        }

        collected_episodes.append(base_episode)

        if episode.get('viewCount') > 0:
            seen_episodes.append(extend(base_episode))

        if episode.get('userRating') is not None:
            rating_episode = extend(base_episode, {
                'title': directory.get('title'),
                'rating': int(episode.get('userRating'))
            })

            if year is not None:
                rating_episode['year'] = year

            if tvdb_id is not None:
                rating_episode['tvdb_id'] = tvdb_id

            rated.append(rating_episode)

    if len(seen_episodes) > 0:
        seen_tv_show = {
            'title': directory.get('title')
        }

        if year is not None:
            seen_tv_show['year'] = year

        if tvdb_id is not None:
            seen_tv_show['tvdb_id'] = tvdb_id

        seen_tv_show['episodes'] = seen_episodes
        all_episodes.append(seen_tv_show)

    tv_show['episodes'] = collected_episodes
    collected.append(tv_show)