def cleanup():
        log.debug('Cleaning up stale or invalid sessions')

        sessions = WatchSession.all()

        if not len(sessions):
            return

        for key, ws in sessions:
            delete = False

            # Destroy invalid sessions
            if ws is None:
                delete = True
            elif not ws.last_updated or type(ws.last_updated) is not datetime:
                delete = True
            elif total_seconds(datetime.now() - ws.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)
                WatchSession.delete(key)
            elif not ws.update_required:
                log.info('Queueing session %s for update', key)
                ws.update_required = True
                ws.save()

        log.debug('Finished cleaning up')
    def initialize(cls):
        cls.thread = Thread(target=cls.process)

        Activity.on('logging.action.played', cls.on_played)\
                .on('logging.action.unplayed', cls.on_unplayed)

        WatchSession.configure(cls)
    def create_session(self, info):
        if not info.get('ratingKey'):
            log.warn('Invalid ratingKey provided from activity info')
            return None

        # Metadata
        metadata = Metadata.get(info['ratingKey'])

        # Guid
        guid = Guid.parse(metadata.guid) if metadata else None

        ws = WatchSession.from_info(info, metadata, guid, info['ratingKey'])
        ws.skip = not metadata

        # Fetch client by `machineIdentifier`
        ws.client = Plex.clients().get(info['machineIdentifier'])

        if not ws.client:
            # Create dummy client from `info`
            ws.client = Client(Plex.client, 'clients')
            ws.client.name = info.get('client', None)
            ws.client.machine_identifier = info.get('machineIdentifier', None)

            ws.client.address = info.get('address', None)
            ws.client.port = info.get('port', None)

        # Create dummy user from `info`
        ws.user = User(Plex.client, 'accounts')
        ws.user.id = info['user_id']
        ws.user.title = info['user_name']

        ws.save()

        log.debug('created session: %s', ws)
        return ws
    def get_session(self, session_key, state, view_offset):
        session = WatchSession.load(session_key)

        if session:
            if session.last_view_offset and session.last_view_offset > view_offset:
                Log.Debug('View offset has gone backwards (last: %s, cur: %s)' % (
                    session.last_view_offset, view_offset
                ))

                # First try update the session if the media hasn't changed
                # otherwise delete the session
                if self.update_session(session, view_offset):
                    Log.Debug('Updated the current session')
                else:
                    Log.Debug('Deleted the current session')
                    session.delete()
                    session = None

            if not session or session.skip:
                return None

            if state == 'playing' and session.update_required:
                self.update_session(session, view_offset)
        else:
            session = self.create_session(session_key, state)

        return session
    def get_session(self, session_key, state, view_offset):
        session = WatchSession.load(session_key)

        if session:
            if session.last_view_offset and session.last_view_offset > view_offset:
                Log.Debug(
                    'View offset has gone backwards (last: %s, cur: %s)' %
                    (session.last_view_offset, view_offset))

                # First try update the session if the media hasn't changed
                # otherwise delete the session
                if self.update_session(session, view_offset):
                    Log.Debug('Updated the current session')
                else:
                    Log.Debug('Deleted the current session')
                    session.delete()
                    session = None

            if not session or session.skip:
                return None

            if state == 'playing' and session.update_required:
                self.update_session(session, view_offset)
        else:
            session = self.create_session(session_key, state)

        return session
    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, 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,
            PlexMediaServer.metadata(video_section.get('ratingKey')),
            PlexMediaServer.client(player_section.get('machineIdentifier')))
        session.save()

        return session
    def get_session(self, session_key, state, view_offset):
        session = WatchSession.load(session_key)

        if session:
            if session.last_view_offset and session.last_view_offset > view_offset:
                Log.Debug(
                    "View offset has gone backwards (last: %s, cur: %s)" % (session.last_view_offset, view_offset)
                )

                # First try update the session if the media hasn't changed
                # otherwise delete the session
                if not self.update_session(session, view_offset):
                    Log.Debug("Media changed, deleting the session")
                    session.delete()
                    return None

            if session.skip:
                return None

            if state == "playing" and session.update_required:
                Log.Debug("Session update required, updating the session...")

                if not self.update_session(session, view_offset):
                    Log.Debug("Media changed, deleting the session")
                    session.delete()
                    return None
        else:
            session = self.create_session(session_key, state)

        return session
    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')

        item = Plex['status'].sessions().get(session_key)
        if not item:
            log.warn('Unable to find session with key "%s"', session_key)
            return None

        # Metadata
        metadata = Metadata.get(item.rating_key)

        # Guid
        guid = Guid.parse(metadata.guid) if metadata else None

        # Create WatchSession
        ws = WatchSession.from_session(item.session, metadata, guid, item.rating_key, state)
        ws.skip = not metadata

        # Fetch client by `machineIdentifier`
        ws.client = Plex.clients().get(item.session.player.machine_identifier)

        ws.save()

        log.debug('created session: %s', ws)
        return ws
    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,
            PlexMediaServer.metadata(video_section.get('ratingKey')),
            PlexMediaServer.client(player_section.get('machineIdentifier'))
        )
        session.save()

        return session
    def check_sessions(self):
        sessions = WatchSession.all()

        if not len(sessions):
            return

        for key, session in sessions:
            self.check_paused(session)
    def check_sessions(self):
        sessions = WatchSession.all()

        if not len(sessions):
            return

        for key, session in sessions:
            self.check_paused(session)
class LoggingScrobbler(ScrobblerMethod):
    name = 'LoggingScrobbler'

    def __init__(self):
        super(LoggingScrobbler, self).__init__()

        EventManager.subscribe('scrobbler.logging.update', self.update)

    @classmethod
    def test(cls):
        # Try enable logging
        if not PlexPreferences.log_debug(True):
            log.warn('Unable to enable logging')

        # Test if logging is enabled
        if not PlexPreferences.log_debug():
            log.warn(
                'Debug logging not enabled, unable to use logging activity method.'
            )
            return False

        return True

    def create_session(self, info):
        if not info.get('ratingKey'):
            log.warn('Invalid ratingKey provided from activity info')
            return None

        skip = False

        # Client
        client = None
        if info.get('machineIdentifier'):
            client = PlexMediaServer.get_client(info['machineIdentifier'])
        else:
            log.info(
                'No machineIdentifier available, client filtering not available'
            )

        # Metadata
        metadata = None

        try:
            metadata = PlexMetadata.get(info['ratingKey'])

            if metadata:
                metadata = metadata.to_dict()
        except NotImplementedError, e:
            # metadata not supported (music, etc..)
            log.debug('%s, ignoring session' % e.message)
            skip = True

        session = WatchSession.from_info(info, metadata, client)
        session.skip = skip
        session.save()

        return session
示例#14
0
    def is_watching(self, p_item):
        sessions = WatchSession.all(lambda s:
            s.get('metadata') and
            s['metadata'].get('rating_key') == p_item.rating_key
        )

        for key, session in sessions:
            if session.watching:
                return True

        return False
    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 check_sessions(self):
        sessions = WatchSession.all()

        if not len(sessions):
            return

        for key, ws in sessions:
            if getattr(ws, 'skip', True):
                continue

            try:
                self.check_paused(ws)
            except AttributeError, ex:
                log.warn("Unable to determine if session is paused, skipping invalid session - %s", ex, exc_info=True)
                ws.skip = True
示例#17
0
    def get_session(self, info):
        session = WatchSession.load('logging-%s' % info.get('client_id'))

        if session:
            if not self.session_valid(session, info):
                session.delete()
                session = None
                Log.Info('Session deleted')

            if not session or session.skip:
                return None

        else:
            session = self.create_session(info)

        return session
示例#18
0
    def get_session(self, info):
        session = WatchSession.load('logging-%s' % info.get('client_id'))

        if session:
            if not self.session_valid(session, info):
                session.delete()
                session = None
                Log.Info('Session deleted')

            if not session or session.skip:
                return None

        else:
            session = self.create_session(info)

        return session
    def get_session(self, session_key, state, view_offset):
        session = WatchSession.load(session_key)

        if not session:
            session = self.create_session(session_key, state)

            if not session:
                return None

        update_session = False

        # Update session when view offset goes backwards
        if session.last_view_offset and session.last_view_offset > view_offset:
            log.debug('View offset has gone backwards (last: %s, cur: %s)' % (
                session.last_view_offset, view_offset
            ))

            update_session = True

        # Update session on missing metadata + session skip
        if not session.metadata and session.skip:
            update_session = True

        # First try update the session if the media hasn't changed
        # otherwise delete the session
        if update_session and not self.update_session(session, view_offset):
            log.debug('Media changed, deleting the session')
            session.delete_instance()
            return None

        # Delete session if invalid
        if not self.session_valid(session):
            session.delete_instance()
            return None

        if session.skip:
            return None

        if state == 'playing' and session.update_required:
            log.debug('Session update required, updating the session...')

            if not self.update_session(session, view_offset):
                log.debug('Media changed, deleting the session')
                session.delete_instance()
                return None

        return session
    def from_event(cls, info):
        account_key = try_convert(info.get('account_key'), int)
        rating_key = info.get('rating_key')

        if account_key is None or rating_key is None:
            log.warn('Invalid action format: %s', info)
            return None

        if account_key != 1:
            log.debug('Ignoring action from shared account')
            return None

        if WatchSession.is_active(rating_key, lambda ws: not ws.update_required):
            log.debug('Ignoring action, item is currently being watched')
            return False

        metadata = Metadata.get(rating_key)

        if not metadata:
            log.debug('Ignoring action, unable to retrieve metadata')
            return False

        section = metadata.section.title.lower()

        f_allow, _ = get_filter('filter_sections')

        if f_allow is not None and section not in f_allow:
            log.debug('Ignoring action, section has been filtered')
            return False

        guid = Guid.parse(metadata.guid)

        request = {}

        if type(metadata) is Movie:
            request = cls.from_movie(metadata, guid)
        elif type(metadata) is Season:
            request = cls.from_season(metadata, guid)
        elif type(metadata) is Episode:
            request = cls.from_episode(metadata, guid)
        else:
            log.warn('Unsupported metadata type: %r', metadata)
            return None

        log.debug('request: %r', request)

        return request
示例#21
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
示例#22
0
    def get_session(self, session_key, state, view_offset):
        session = WatchSession.load(session_key)

        if not session:
            session = self.create_session(session_key, state)

            if not session:
                return None

        update_session = False

        # Update session when view offset goes backwards
        if session.last_view_offset and session.last_view_offset > view_offset:
            log.debug('View offset has gone backwards (last: %s, cur: %s)' %
                      (session.last_view_offset, view_offset))

            update_session = True

        # Update session on missing metadata + session skip
        if not session.metadata and session.skip:
            update_session = True

        # First try update the session if the media hasn't changed
        # otherwise delete the session
        if update_session and not self.update_session(session, view_offset):
            log.debug('Media changed, deleting the session')
            session.delete()
            return None

        # Delete session if invalid
        if not self.session_valid(session):
            session.delete()
            return None

        if session.skip:
            return None

        if state == 'playing' and session.update_required:
            log.debug('Session update required, updating the session...')

            if not self.update_session(session, view_offset):
                log.debug('Media changed, deleting the session')
                session.delete()
                return None

        return session
    def get_session(self, info):
        session = WatchSession.load('logging-%s' % info.get('machineIdentifier'))

        if session and not self.session_valid(session, info):
            session.delete_instance()
            session = None
            log.debug('Session deleted')

        if not session:
            session = self.create_session(info)

            if not session:
                return None

        if not session or session.skip:
            return None

        return session
    def get_session(self, info):
        session = WatchSession.load('logging-%s' %
                                    info.get('machineIdentifier'))

        if not session:
            session = self.create_session(info)

            if not session:
                return None

        if not self.session_valid(session, info):
            session.delete()
            session = None
            log.debug('Session deleted')

        if not session or session.skip:
            return None

        return session
示例#25
0
 def create_session(self, info):
     return WatchSession.from_info(
         info,
         PlexMediaServer.metadata(info['ratingKey']),
         PlexMediaServer.client(info.get('client_id'))
     )
示例#26
0
 def create_session(self, info):
     return WatchSession.from_info(
         info, PlexMediaServer.metadata(info['ratingKey']),
         PlexMediaServer.client(info.get('client_id')))
示例#27
0
class WebSocketScrobbler(ScrobblerMethod):
    name = 'WebSocketScrobbler'

    def __init__(self):
        super(WebSocketScrobbler, self).__init__()

        EventManager.subscribe('notifications.playing', self.update)

    @classmethod
    def test(cls):
        if PlexMediaServer.get_sessions() is None:
            log.info(
                "Error while retrieving sessions, assuming WebSocket method isn't available"
            )
            return False

        server_info = PlexMediaServer.get_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 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')

        skip = False

        info = PlexMediaServer.get_session(session_key)
        if not info:
            return None

        # Client
        player_section = info.findall('Player')
        if len(player_section):
            player_section = player_section[0]

        client = PlexMediaServer.get_client(
            player_section.get('machineIdentifier'))

        # Metadata
        metadata = None

        try:
            metadata = PlexMetadata.get(info.get('ratingKey'))

            if metadata:
                metadata = metadata.to_dict()
        except NotImplementedError, e:
            # metadata not supported (music, etc..)
            log.debug('%s, ignoring session' % e.message)
            skip = True

        session = WatchSession.from_section(info, state, metadata, client)
        session.skip = skip
        session.save()

        return session