Beispiel #1
0
    def process(self):
        if self.is_valid_session():
            from plexpy import helpers

            ap = activity_processor.ActivityProcessor()
            db_session = ap.get_session_by_key(
                session_key=self.get_session_key())

            this_state = self.timeline['state']
            this_key = str(self.timeline['ratingKey'])

            # If we already have this session in the temp table, check for state changes
            if db_session:
                last_state = db_session['state']
                last_key = str(db_session['rating_key'])

                # Make sure the same item is being played
                if this_key == last_key:
                    # Update the session state and viewOffset
                    if this_state == 'playing':
                        ap.set_session_state(
                            session_key=self.get_session_key(),
                            state=this_state,
                            view_offset=self.timeline['viewOffset'])
                    # Start our state checks
                    if this_state != last_state:
                        if this_state == 'paused':
                            self.on_pause()
                        elif last_state == 'paused' and this_state == 'playing':
                            self.on_resume()
                        elif this_state == 'stopped':
                            self.on_stop()
                    elif this_state == 'buffering':
                        self.on_buffer()
                # If a client doesn't register stop events (I'm looking at you PHT!) check if the ratingKey has changed
                else:
                    # Manually stop and start
                    # Set force_stop so that we don't overwrite our last viewOffset
                    self.on_stop(force_stop=True)
                    self.on_start()

                # Monitor if the stream has reached the watch percentage for notifications
                # The only purpose of this is for notifications
                progress_percent = helpers.get_percent(
                    self.timeline['viewOffset'], db_session['duration'])
                if progress_percent >= plexpy.CONFIG.NOTIFY_WATCHED_PERCENT and this_state != 'buffering':
                    threading.Thread(target=notification_handler.notify,
                                     kwargs=dict(
                                         stream_data=db_session,
                                         notify_action='watched')).start()

            else:
                # We don't have this session in our table yet, start a new one.
                if this_state != 'buffering':
                    self.on_start()
Beispiel #2
0
    def process(self):
        if self.is_valid_session():
            ap = activity_processor.ActivityProcessor()
            db_session = ap.get_session_by_key(session_key=self.get_session_key())

            this_state = self.timeline['state']
            this_key = str(self.timeline['ratingKey'])

            # If we already have this session in the temp table, check for state changes
            if db_session:
                last_state = db_session['state']
                last_key = str(db_session['rating_key'])

                # Make sure the same item is being played
                if this_key == last_key:
                    # Update the session state and viewOffset
                    if this_state == 'playing':
                        ap.set_session_state(session_key=self.get_session_key(),
                                             state=this_state,
                                             view_offset=self.timeline['viewOffset'])
                    # Start our state checks
                    if this_state != last_state:
                        if this_state == 'paused':
                            self.on_pause()
                        elif last_state == 'paused' and this_state == 'playing':
                            self.on_resume()
                        elif this_state == 'stopped':
                            self.on_stop()
                    elif this_state == 'buffering':
                        self.on_buffer()
                # If a client doesn't register stop events (I'm looking at you PHT!) check if the ratingKey has changed
                else:
                    # Manually stop and start
                    # Set force_stop so that we don't overwrite our last viewOffset
                    self.on_stop(force_stop=True)
                    self.on_start()

                # Monitor if the stream has reached the watch percentage for notifications
                # The only purpose of this is for notifications
                # Check if any notification agents have notifications enabled
                notify_agents = [d['id'] for d in notifiers.available_notification_agents() if d['on_watched']]
                # Get the current states for notifications from our db
                notified_agents = [d['agent_id'] for d in notification_handler.get_notify_state(session=db_session)
                                   if d['notify_action'] == 'watched'] if notify_agents else []

                if any(a not in notified_agents for a in notify_agents):
                    progress_percent = helpers.get_percent(self.timeline['viewOffset'], db_session['duration'])
                    if progress_percent >= plexpy.CONFIG.NOTIFY_WATCHED_PERCENT and this_state != 'buffering':
                        # Rather not put this on it's own thread so we know it completes before our next event.
                        notification_handler.notify(stream_data=db_session, notify_action='watched')

            else:
                # We don't have this session in our table yet, start a new one.
                if this_state != 'buffering':
                    self.on_start()
Beispiel #3
0
    def process(self):
        if self.is_valid_session():
            from plexpy import helpers

            ap = activity_processor.ActivityProcessor()
            db_session = ap.get_session_by_key(session_key=self.get_session_key())

            this_state = self.timeline["state"]
            this_key = str(self.timeline["ratingKey"])

            # If we already have this session in the temp table, check for state changes
            if db_session:
                last_state = db_session["state"]
                last_key = str(db_session["rating_key"])

                # Make sure the same item is being played
                if this_key == last_key:
                    # Update the session state and viewOffset
                    if this_state == "playing":
                        ap.set_session_state(
                            session_key=self.get_session_key(),
                            state=this_state,
                            view_offset=self.timeline["viewOffset"],
                        )
                    # Start our state checks
                    if this_state != last_state:
                        if this_state == "paused":
                            self.on_pause()
                        elif last_state == "paused" and this_state == "playing":
                            self.on_resume()
                        elif this_state == "stopped":
                            self.on_stop()
                    elif this_state == "buffering":
                        self.on_buffer()
                # If a client doesn't register stop events (I'm looking at you PHT!) check if the ratingKey has changed
                else:
                    # Manually stop and start
                    # Set force_stop so that we don't overwrite our last viewOffset
                    self.on_stop(force_stop=True)
                    self.on_start()

                # Monitor if the stream has reached the watch percentage for notifications
                # The only purpose of this is for notifications
                progress_percent = helpers.get_percent(self.timeline["viewOffset"], db_session["duration"])
                if progress_percent >= plexpy.CONFIG.NOTIFY_WATCHED_PERCENT and this_state != "buffering":
                    threading.Thread(
                        target=notification_handler.notify, kwargs=dict(stream_data=db_session, notify_action="watched")
                    ).start()

            else:
                # We don't have this session in our table yet, start a new one.
                if this_state != "buffering":
                    self.on_start()
Beispiel #4
0
def build_notify_text(session, state):
    from plexpy import pmsconnect, helpers
    import re

    # Get the server name
    pms_connect = pmsconnect.PmsConnect()
    server_name = pms_connect.get_server_pref(pref='FriendlyName')

    # Get metadata feed for item
    metadata = pms_connect.get_metadata_details(
        rating_key=session['rating_key'])

    if metadata:
        item_metadata = metadata['metadata']
    else:
        logger.error(
            u"PlexPy Notifier :: Unable to retrieve metadata for rating_key %s"
            % str(session['rating_key']))
        return []

    # Check for exclusion tags
    if session['media_type'] == 'episode':
        # Regex pattern to remove the text in the tags we don't want
        pattern = re.compile('<movie>[^>]+.</movie>|<music>[^>]+.</music>',
                             re.IGNORECASE)
    elif session['media_type'] == 'movie':
        # Regex pattern to remove the text in the tags we don't want
        pattern = re.compile('<tv>[^>]+.</tv>|<music>[^>]+.</music>',
                             re.IGNORECASE)
    elif session['media_type'] == 'track':
        # Regex pattern to remove the text in the tags we don't want
        pattern = re.compile('<tv>[^>]+.</tv>|<movie>[^>]+.</movie>',
                             re.IGNORECASE)
    else:
        pattern = None

    if session['media_type'] == 'episode' or session['media_type'] == 'movie' or session['media_type'] == 'track' \
            and pattern:
        # Remove the unwanted tags and strip any unmatch tags too.
        on_start_subject = strip_tag(
            re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_START_SUBJECT_TEXT))
        on_start_body = strip_tag(
            re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_START_BODY_TEXT))
        on_stop_subject = strip_tag(
            re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_STOP_SUBJECT_TEXT))
        on_stop_body = strip_tag(
            re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_STOP_BODY_TEXT))
        on_pause_subject = strip_tag(
            re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_PAUSE_SUBJECT_TEXT))
        on_pause_body = strip_tag(
            re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_PAUSE_BODY_TEXT))
        on_resume_subject = strip_tag(
            re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_RESUME_SUBJECT_TEXT))
        on_resume_body = strip_tag(
            re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_RESUME_BODY_TEXT))
        on_buffer_subject = strip_tag(
            re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_BUFFER_SUBJECT_TEXT))
        on_buffer_body = strip_tag(
            re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_BUFFER_BODY_TEXT))
        on_watched_subject = strip_tag(
            re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_WATCHED_SUBJECT_TEXT))
        on_watched_body = strip_tag(
            re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_WATCHED_BODY_TEXT))
    else:
        on_start_subject = plexpy.CONFIG.NOTIFY_ON_START_SUBJECT_TEXT
        on_start_body = plexpy.CONFIG.NOTIFY_ON_START_BODY_TEXT
        on_stop_subject = plexpy.CONFIG.NOTIFY_ON_STOP_SUBJECT_TEXT
        on_stop_body = plexpy.CONFIG.NOTIFY_ON_STOP_BODY_TEXT
        on_pause_subject = plexpy.CONFIG.NOTIFY_ON_PAUSE_SUBJECT_TEXT
        on_pause_body = plexpy.CONFIG.NOTIFY_ON_PAUSE_BODY_TEXT
        on_resume_subject = plexpy.CONFIG.NOTIFY_ON_RESUME_SUBJECT_TEXT
        on_resume_body = plexpy.CONFIG.NOTIFY_ON_RESUME_BODY_TEXT
        on_buffer_subject = plexpy.CONFIG.NOTIFY_ON_BUFFER_SUBJECT_TEXT
        on_buffer_body = plexpy.CONFIG.NOTIFY_ON_BUFFER_BODY_TEXT
        on_watched_subject = plexpy.CONFIG.NOTIFY_ON_WATCHED_SUBJECT_TEXT
        on_watched_body = plexpy.CONFIG.NOTIFY_ON_WATCHED_BODY_TEXT

    # Create a title
    if session['media_type'] == 'episode':
        full_title = '%s - %s' % (session['grandparent_title'],
                                  session['title'])
    elif session['media_type'] == 'track':
        full_title = '%s - %s' % (session['grandparent_title'],
                                  session['title'])
    else:
        full_title = session['title']

    # Generate a combined transcode decision value
    if session['video_decision']:
        if session['video_decision'] == 'transcode':
            transcode_decision = 'Transcode'
        elif session['video_decision'] == 'copy' or session[
                'audio_decision'] == 'copy':
            transcode_decision = 'Direct Stream'
        else:
            transcode_decision = 'Direct Play'
    else:
        if session['audio_decision'] == 'transcode':
            transcode_decision = 'Transcode'
        else:
            transcode_decision = 'Direct Play'

    duration = helpers.convert_milliseconds_to_minutes(
        item_metadata['duration'])
    view_offset = helpers.convert_milliseconds_to_minutes(
        session['view_offset'])
    stream_duration = 0
    if state != 'play':
        if session['paused_counter']:
            stream_duration = int(
                (time.time() - helpers.cast_to_float(session['started']) -
                 helpers.cast_to_float(session['paused_counter'])) / 60)
        else:
            stream_duration = int(
                (time.time() - helpers.cast_to_float(session['started'])) / 60)

    progress_percent = helpers.get_percent(view_offset, duration)

    available_params = {
        'server_name': server_name,
        'user': session['friendly_name'],
        'platform': session['platform'],
        'player': session['player'],
        'media_type': session['media_type'],
        'title': full_title,
        'show_name': item_metadata['grandparent_title'],
        'episode_name': item_metadata['title'],
        'artist_name': item_metadata['grandparent_title'],
        'album_name': item_metadata['parent_title'],
        'season_num': item_metadata['parent_index'],
        'season_num00': item_metadata['parent_index'].zfill(2),
        'episode_num': item_metadata['index'],
        'episode_num00': item_metadata['index'].zfill(2),
        'transcode_decision': transcode_decision,
        'year': item_metadata['year'],
        'studio': item_metadata['studio'],
        'content_rating': item_metadata['content_rating'],
        'summary': item_metadata['summary'],
        'rating': item_metadata['rating'],
        'duration': duration,
        'stream_duration': stream_duration,
        'remaining_duration': duration - view_offset,
        'progress': view_offset,
        'progress_percent': progress_percent
    }

    # Default subject text
    subject_text = 'PlexPy (%s)' % server_name

    if state == 'play':
        # Default body text
        body_text = '%s (%s) is watching %s' % (session['friendly_name'],
                                                session['player'], full_title)

        if on_start_subject and on_start_body:
            try:
                subject_text = unicode(on_start_subject).format(
                    **available_params)
            except LookupError, e:
                logger.error(
                    u"PlexPy Notifier :: Unable to parse field %s in notification subject. Using fallback."
                    % e)
            except:
Beispiel #5
0
def notify(stream_data=None, notify_action=None):
    from plexpy import users
    
    if stream_data and notify_action:
        # Check if notifications enabled for user
        user_data = users.Users()
        user_details = user_data.get_user_friendly_name(user=stream_data['user'])

        if not user_details['do_notify']:
            return

        if (stream_data['media_type'] == 'movie' and plexpy.CONFIG.MOVIE_NOTIFY_ENABLE) \
            or (stream_data['media_type'] == 'episode' and plexpy.CONFIG.TV_NOTIFY_ENABLE):

            progress_percent = helpers.get_percent(stream_data['view_offset'], stream_data['duration'])

            for agent in notifiers.available_notification_agents():
                if agent['on_play'] and notify_action == 'play':
                    # Build and send notification
                    notify_strings = build_notify_text(session=stream_data, state=notify_action)
                    notifiers.send_notification(config_id=agent['id'],
                                                subject=notify_strings[0],
                                                body=notify_strings[1])
                    # Set the notification state in the db
                    set_notify_state(session=stream_data, state=notify_action, agent_info=agent)

                elif agent['on_stop'] and notify_action == 'stop' \
                    and (plexpy.CONFIG.NOTIFY_CONSECUTIVE or progress_percent < plexpy.CONFIG.NOTIFY_WATCHED_PERCENT):
                    # Build and send notification
                    notify_strings = build_notify_text(session=stream_data, state=notify_action)
                    notifiers.send_notification(config_id=agent['id'],
                                                subject=notify_strings[0],
                                                body=notify_strings[1])

                    set_notify_state(session=stream_data, state=notify_action, agent_info=agent)

                elif agent['on_pause'] and notify_action == 'pause' \
                    and (plexpy.CONFIG.NOTIFY_CONSECUTIVE or progress_percent < 99):
                    # Build and send notification
                    notify_strings = build_notify_text(session=stream_data, state=notify_action)
                    notifiers.send_notification(config_id=agent['id'],
                                                subject=notify_strings[0],
                                                body=notify_strings[1])

                    set_notify_state(session=stream_data, state=notify_action, agent_info=agent)

                elif agent['on_resume'] and notify_action == 'resume' \
                    and (plexpy.CONFIG.NOTIFY_CONSECUTIVE or progress_percent < 99):
                    # Build and send notification
                    notify_strings = build_notify_text(session=stream_data, state=notify_action)
                    notifiers.send_notification(config_id=agent['id'],
                                                subject=notify_strings[0],
                                                body=notify_strings[1])

                    set_notify_state(session=stream_data, state=notify_action, agent_info=agent)

                elif agent['on_buffer'] and notify_action == 'buffer':
                    # Build and send notification
                    notify_strings = build_notify_text(session=stream_data, state=notify_action)
                    notifiers.send_notification(config_id=agent['id'],
                                                subject=notify_strings[0],
                                                body=notify_strings[1])

                    set_notify_state(session=stream_data, state=notify_action, agent_info=agent)

                elif agent['on_watched'] and notify_action == 'watched':
                    # Get the current states for notifications from our db
                    notify_states = get_notify_state(session=stream_data)

                    # If there is nothing in the notify_log for our agent id but it is enabled we should notify
                    if not any(d['agent_id'] == agent['id'] for d in notify_states):
                        # Build and send notification
                        notify_strings = build_notify_text(session=stream_data, state=notify_action)
                        notifiers.send_notification(config_id=agent['id'],
                                                    subject=notify_strings[0],
                                                    body=notify_strings[1])
                        # Set the notification state in the db
                        set_notify_state(session=stream_data, state=notify_action, agent_info=agent)

                    else:
                        # Check in our notify log if the notification has already been sent
                        for notify_state in notify_states:
                            if not notify_state['on_watched'] and (notify_state['agent_id'] == agent['id']):
                                # Build and send notification
                                notify_strings = build_notify_text(session=stream_data, state=notify_action)
                                notifiers.send_notification(config_id=agent['id'],
                                                            subject=notify_strings[0],
                                                            body=notify_strings[1])
                                # Set the notification state in the db
                                set_notify_state(session=stream_data, state=notify_action, agent_info=agent)

        elif (stream_data['media_type'] == 'track' and plexpy.CONFIG.MUSIC_NOTIFY_ENABLE):

            for agent in notifiers.available_notification_agents():
                if agent['on_play'] and notify_action == 'play':
                    # Build and send notification
                    notify_strings = build_notify_text(session=stream_data, state=notify_action)
                    notifiers.send_notification(config_id=agent['id'],
                                                subject=notify_strings[0],
                                                body=notify_strings[1])
                    # Set the notification state in the db
                    set_notify_state(session=stream_data, state=notify_action, agent_info=agent)

                elif agent['on_stop'] and notify_action == 'stop':
                    # Build and send notification
                    notify_strings = build_notify_text(session=stream_data, state=notify_action)
                    notifiers.send_notification(config_id=agent['id'],
                                                subject=notify_strings[0],
                                                body=notify_strings[1])
                    # Set the notification state in the db
                    set_notify_state(session=stream_data, state=notify_action, agent_info=agent)

                elif agent['on_pause'] and notify_action == 'pause':
                    # Build and send notification
                    notify_strings = build_notify_text(session=stream_data, state=notify_action)
                    notifiers.send_notification(config_id=agent['id'],
                                                subject=notify_strings[0],
                                                body=notify_strings[1])
                    # Set the notification state in the db
                    set_notify_state(session=stream_data, state=notify_action, agent_info=agent)

                elif agent['on_resume'] and notify_action == 'resume':
                    # Build and send notification
                    notify_strings = build_notify_text(session=stream_data, state=notify_action)
                    notifiers.send_notification(config_id=agent['id'],
                                                subject=notify_strings[0],
                                                body=notify_strings[1])
                    # Set the notification state in the db
                    set_notify_state(session=stream_data, state=notify_action, agent_info=agent)

                elif agent['on_buffer'] and notify_action == 'buffer':
                    # Build and send notification
                    notify_strings = build_notify_text(session=stream_data, state=notify_action)
                    notifiers.send_notification(config_id=agent['id'],
                                                subject=notify_strings[0],
                                                body=notify_strings[1])
                    # Set the notification state in the db
                    set_notify_state(session=stream_data, state=notify_action, agent_info=agent)

        elif stream_data['media_type'] == 'clip':
            pass
        else:
            #logger.debug(u"PlexPy Notifier :: Notify called with unsupported media type.")
            pass
    else:
        logger.debug(u"PlexPy Notifier :: Notify called but incomplete data received.")
Beispiel #6
0
    def get_session_each(self, stream_type="", session=None):
        session_output = None
        data_factory = datafactory.DataFactory()
        if stream_type == "track":

            media_info = session.getElementsByTagName("Media")[0]
            audio_decision = "direct play"
            audio_channels = helpers.get_xml_attr(media_info, "audioChannels")
            audio_codec = helpers.get_xml_attr(media_info, "audioCodec")
            container = helpers.get_xml_attr(media_info, "container")
            bitrate = helpers.get_xml_attr(media_info, "bitrate")
            duration = helpers.get_xml_attr(media_info, "duration")
            progress = helpers.get_xml_attr(session, "viewOffset")

            if session.getElementsByTagName("TranscodeSession"):
                transcode_session = session.getElementsByTagName("TranscodeSession")[0]
                audio_decision = helpers.get_xml_attr(transcode_session, "audioDecision")
                transcode_audio_channels = helpers.get_xml_attr(transcode_session, "audioChannels")
                transcode_audio_codec = helpers.get_xml_attr(transcode_session, "audioCodec")
                transcode_container = helpers.get_xml_attr(transcode_session, "container")
                transcode_protocol = helpers.get_xml_attr(transcode_session, "protocol")
                duration = helpers.get_xml_attr(transcode_session, "duration")
            else:
                transcode_audio_channels = ""
                transcode_audio_codec = ""
                transcode_container = ""
                transcode_protocol = ""

            user_details = data_factory.get_user_details(
                user=helpers.get_xml_attr(session.getElementsByTagName("User")[0], "title")
            )

            if helpers.get_xml_attr(session.getElementsByTagName("Player")[0], "machineIdentifier").endswith("_Track"):
                machine_id = helpers.get_xml_attr(session.getElementsByTagName("Player")[0], "machineIdentifier")[:-6]
            else:
                machine_id = helpers.get_xml_attr(session.getElementsByTagName("Player")[0], "machineIdentifier")

            session_output = {
                "session_key": helpers.get_xml_attr(session, "sessionKey"),
                "media_index": helpers.get_xml_attr(session, "index"),
                "parent_media_index": helpers.get_xml_attr(session, "parentIndex"),
                "art": helpers.get_xml_attr(session, "art"),
                "parent_thumb": helpers.get_xml_attr(session, "parentThumb"),
                "grandparent_thumb": helpers.get_xml_attr(session, "grandparentThumb"),
                "thumb": helpers.get_xml_attr(session, "thumb"),
                "bif_thumb": "",
                "user": helpers.get_xml_attr(session.getElementsByTagName("User")[0], "title"),
                "user_id": user_details["user_id"],
                "friendly_name": user_details["friendly_name"],
                "player": helpers.get_xml_attr(session.getElementsByTagName("Player")[0], "title"),
                "platform": helpers.get_xml_attr(session.getElementsByTagName("Player")[0], "platform"),
                "machine_id": machine_id,
                "state": helpers.get_xml_attr(session.getElementsByTagName("Player")[0], "state"),
                "grandparent_title": helpers.get_xml_attr(session, "grandparentTitle"),
                "parent_title": helpers.get_xml_attr(session, "parentTitle"),
                "title": helpers.get_xml_attr(session, "title"),
                "rating_key": helpers.get_xml_attr(session, "ratingKey"),
                "parent_rating_key": helpers.get_xml_attr(session, "parentRatingKey"),
                "grandparent_rating_key": helpers.get_xml_attr(session, "grandparentRatingKey"),
                "audio_decision": audio_decision,
                "audio_channels": audio_channels,
                "audio_codec": audio_codec,
                "video_decision": "",
                "video_codec": "",
                "height": "",
                "width": "",
                "container": container,
                "bitrate": bitrate,
                "video_resolution": "",
                "video_framerate": "",
                "aspect_ratio": "",
                "transcode_audio_channels": transcode_audio_channels,
                "transcode_audio_codec": transcode_audio_codec,
                "transcode_video_codec": "",
                "transcode_width": "",
                "transcode_height": "",
                "transcode_container": transcode_container,
                "transcode_protocol": transcode_protocol,
                "duration": duration,
                "progress": progress,
                "progress_percent": str(helpers.get_percent(progress, duration)),
                "type": "track",
                "indexes": 0,
            }
        elif stream_type == "video":
            media_info = session.getElementsByTagName("Media")[0]
            audio_decision = "direct play"
            audio_channels = helpers.get_xml_attr(media_info, "audioChannels")
            audio_codec = helpers.get_xml_attr(media_info, "audioCodec")
            video_decision = "direct play"
            video_codec = helpers.get_xml_attr(media_info, "videoCodec")
            container = helpers.get_xml_attr(media_info, "container")
            bitrate = helpers.get_xml_attr(media_info, "bitrate")
            video_resolution = helpers.get_xml_attr(media_info, "videoResolution")
            video_framerate = helpers.get_xml_attr(media_info, "videoFrameRate")
            aspect_ratio = helpers.get_xml_attr(media_info, "aspectRatio")
            width = helpers.get_xml_attr(media_info, "width")
            height = helpers.get_xml_attr(media_info, "height")
            duration = helpers.get_xml_attr(media_info, "duration")
            progress = helpers.get_xml_attr(session, "viewOffset")

            if session.getElementsByTagName("TranscodeSession"):
                transcode_session = session.getElementsByTagName("TranscodeSession")[0]
                audio_decision = helpers.get_xml_attr(transcode_session, "audioDecision")
                transcode_audio_channels = helpers.get_xml_attr(transcode_session, "audioChannels")
                transcode_audio_codec = helpers.get_xml_attr(transcode_session, "audioCodec")
                video_decision = helpers.get_xml_attr(transcode_session, "videoDecision")
                transcode_video_codec = helpers.get_xml_attr(transcode_session, "videoCodec")
                transcode_width = helpers.get_xml_attr(transcode_session, "width")
                transcode_height = helpers.get_xml_attr(transcode_session, "height")
                transcode_container = helpers.get_xml_attr(transcode_session, "container")
                transcode_protocol = helpers.get_xml_attr(transcode_session, "protocol")
            else:
                transcode_audio_channels = ""
                transcode_audio_codec = ""
                transcode_video_codec = ""
                transcode_width = ""
                transcode_height = ""
                transcode_container = ""
                transcode_protocol = ""

            media_info = session.getElementsByTagName("Media")[0]
            if media_info.getElementsByTagName("Part"):
                indexes = helpers.get_xml_attr(media_info.getElementsByTagName("Part")[0], "indexes")
                part_id = helpers.get_xml_attr(media_info.getElementsByTagName("Part")[0], "id")
                if indexes == "sd":
                    bif_thumb = "/library/parts/" + part_id + "/indexes/sd/" + progress
                else:
                    bif_thumb = ""
            else:
                indexes = ""
                bif_thumb = ""

            if plexpy.CONFIG.PMS_USE_BIF and indexes == "sd":
                use_indexes = 1
            else:
                use_indexes = 0

            user_details = data_factory.get_user_details(
                user=helpers.get_xml_attr(session.getElementsByTagName("User")[0], "title")
            )

            if helpers.get_xml_attr(session.getElementsByTagName("Player")[0], "machineIdentifier").endswith("_Video"):
                machine_id = helpers.get_xml_attr(session.getElementsByTagName("Player")[0], "machineIdentifier")[:-6]
            else:
                machine_id = helpers.get_xml_attr(session.getElementsByTagName("Player")[0], "machineIdentifier")

            if helpers.get_xml_attr(session, "type") == "episode":
                session_output = {
                    "session_key": helpers.get_xml_attr(session, "sessionKey"),
                    "media_index": helpers.get_xml_attr(session, "index"),
                    "parent_media_index": helpers.get_xml_attr(session, "parentIndex"),
                    "art": helpers.get_xml_attr(session, "art"),
                    "parent_thumb": helpers.get_xml_attr(session, "parentThumb"),
                    "grandparent_thumb": helpers.get_xml_attr(session, "grandparentThumb"),
                    "thumb": helpers.get_xml_attr(session, "thumb"),
                    "bif_thumb": bif_thumb,
                    "user": helpers.get_xml_attr(session.getElementsByTagName("User")[0], "title"),
                    "user_id": user_details["user_id"],
                    "friendly_name": user_details["friendly_name"],
                    "player": helpers.get_xml_attr(session.getElementsByTagName("Player")[0], "title"),
                    "platform": helpers.get_xml_attr(session.getElementsByTagName("Player")[0], "platform"),
                    "machine_id": machine_id,
                    "state": helpers.get_xml_attr(session.getElementsByTagName("Player")[0], "state"),
                    "grandparent_title": helpers.get_xml_attr(session, "grandparentTitle"),
                    "parent_title": helpers.get_xml_attr(session, "parentTitle"),
                    "title": helpers.get_xml_attr(session, "title"),
                    "rating_key": helpers.get_xml_attr(session, "ratingKey"),
                    "parent_rating_key": helpers.get_xml_attr(session, "parentRatingKey"),
                    "grandparent_rating_key": helpers.get_xml_attr(session, "grandparentRatingKey"),
                    "audio_decision": audio_decision,
                    "audio_channels": audio_channels,
                    "audio_codec": audio_codec,
                    "video_decision": video_decision,
                    "video_codec": video_codec,
                    "height": height,
                    "width": width,
                    "container": container,
                    "bitrate": bitrate,
                    "video_resolution": video_resolution,
                    "video_framerate": video_framerate,
                    "aspect_ratio": aspect_ratio,
                    "transcode_audio_channels": transcode_audio_channels,
                    "transcode_audio_codec": transcode_audio_codec,
                    "transcode_video_codec": transcode_video_codec,
                    "transcode_width": transcode_width,
                    "transcode_height": transcode_height,
                    "transcode_container": transcode_container,
                    "transcode_protocol": transcode_protocol,
                    "duration": duration,
                    "progress": progress,
                    "progress_percent": str(helpers.get_percent(progress, duration)),
                    "type": helpers.get_xml_attr(session, "type"),
                    "indexes": use_indexes,
                }
            elif helpers.get_xml_attr(session, "type") == "movie":
                session_output = {
                    "session_key": helpers.get_xml_attr(session, "sessionKey"),
                    "media_index": helpers.get_xml_attr(session, "index"),
                    "parent_media_index": helpers.get_xml_attr(session, "parentIndex"),
                    "art": helpers.get_xml_attr(session, "art"),
                    "thumb": helpers.get_xml_attr(session, "thumb"),
                    "bif_thumb": bif_thumb,
                    "parent_thumb": helpers.get_xml_attr(session, "parentThumb"),
                    "grandparent_thumb": helpers.get_xml_attr(session, "grandparentThumb"),
                    "user": helpers.get_xml_attr(session.getElementsByTagName("User")[0], "title"),
                    "user_id": user_details["user_id"],
                    "friendly_name": user_details["friendly_name"],
                    "player": helpers.get_xml_attr(session.getElementsByTagName("Player")[0], "title"),
                    "platform": helpers.get_xml_attr(session.getElementsByTagName("Player")[0], "platform"),
                    "machine_id": machine_id,
                    "state": helpers.get_xml_attr(session.getElementsByTagName("Player")[0], "state"),
                    "grandparent_title": helpers.get_xml_attr(session, "grandparentTitle"),
                    "parent_title": helpers.get_xml_attr(session, "parentTitle"),
                    "title": helpers.get_xml_attr(session, "title"),
                    "rating_key": helpers.get_xml_attr(session, "ratingKey"),
                    "parent_rating_key": helpers.get_xml_attr(session, "parentRatingKey"),
                    "grandparent_rating_key": helpers.get_xml_attr(session, "grandparentRatingKey"),
                    "audio_decision": audio_decision,
                    "audio_channels": audio_channels,
                    "audio_codec": audio_codec,
                    "video_decision": video_decision,
                    "video_codec": video_codec,
                    "height": height,
                    "width": width,
                    "container": container,
                    "bitrate": bitrate,
                    "video_resolution": video_resolution,
                    "video_framerate": video_framerate,
                    "aspect_ratio": aspect_ratio,
                    "transcode_audio_channels": transcode_audio_channels,
                    "transcode_audio_codec": transcode_audio_codec,
                    "transcode_video_codec": transcode_video_codec,
                    "transcode_width": transcode_width,
                    "transcode_height": transcode_height,
                    "transcode_container": transcode_container,
                    "transcode_protocol": transcode_protocol,
                    "duration": duration,
                    "progress": progress,
                    "progress_percent": str(helpers.get_percent(progress, duration)),
                    "type": helpers.get_xml_attr(session, "type"),
                    "indexes": use_indexes,
                }
            elif helpers.get_xml_attr(session, "type") == "clip":
                session_output = {
                    "session_key": helpers.get_xml_attr(session, "sessionKey"),
                    "media_index": helpers.get_xml_attr(session, "index"),
                    "parent_media_index": helpers.get_xml_attr(session, "parentIndex"),
                    "art": helpers.get_xml_attr(session, "art"),
                    "thumb": helpers.get_xml_attr(session, "thumb"),
                    "bif_thumb": bif_thumb,
                    "parent_thumb": helpers.get_xml_attr(session, "parentThumb"),
                    "grandparent_thumb": helpers.get_xml_attr(session, "grandparentThumb"),
                    "user": helpers.get_xml_attr(session.getElementsByTagName("User")[0], "title"),
                    "user_id": user_details["user_id"],
                    "friendly_name": user_details["friendly_name"],
                    "player": helpers.get_xml_attr(session.getElementsByTagName("Player")[0], "title"),
                    "platform": helpers.get_xml_attr(session.getElementsByTagName("Player")[0], "platform"),
                    "machine_id": machine_id,
                    "state": helpers.get_xml_attr(session.getElementsByTagName("Player")[0], "state"),
                    "grandparent_title": helpers.get_xml_attr(session, "grandparentTitle"),
                    "parent_title": helpers.get_xml_attr(session, "parentTitle"),
                    "title": helpers.get_xml_attr(session, "title"),
                    "rating_key": helpers.get_xml_attr(session, "ratingKey"),
                    "parent_rating_key": helpers.get_xml_attr(session, "parentRatingKey"),
                    "grandparent_rating_key": helpers.get_xml_attr(session, "grandparentRatingKey"),
                    "audio_decision": audio_decision,
                    "audio_channels": audio_channels,
                    "audio_codec": audio_codec,
                    "video_decision": video_decision,
                    "video_codec": video_codec,
                    "height": height,
                    "width": width,
                    "container": container,
                    "bitrate": bitrate,
                    "video_resolution": video_resolution,
                    "video_framerate": video_framerate,
                    "aspect_ratio": aspect_ratio,
                    "transcode_audio_channels": transcode_audio_channels,
                    "transcode_audio_codec": transcode_audio_codec,
                    "transcode_video_codec": transcode_video_codec,
                    "transcode_width": transcode_width,
                    "transcode_height": transcode_height,
                    "transcode_container": transcode_container,
                    "transcode_protocol": transcode_protocol,
                    "duration": duration,
                    "progress": progress,
                    "progress_percent": str(helpers.get_percent(progress, duration)),
                    "type": helpers.get_xml_attr(session, "type"),
                    "indexes": 0,
                }
        else:
            logger.warn(u"No known stream types found in session list.")

        return session_output
Beispiel #7
0
                            status_state = helpers.get_xml_attr(
                                status, 'state')
                            status_item_count = helpers.get_xml_attr(
                                status, 'itemsCount')
                            status_item_complete_count = helpers.get_xml_attr(
                                status, 'itemsCompleteCount')
                            status_item_downloaded_count = helpers.get_xml_attr(
                                status, 'itemsDownloadedCount')
                            status_item_ready_count = helpers.get_xml_attr(
                                status, 'itemsReadyCount')
                            status_item_successful_count = helpers.get_xml_attr(
                                status, 'itemsSuccessfulCount')
                            status_total_size = helpers.get_xml_attr(
                                status, 'totalSize')
                            status_item_download_percent_complete = helpers.get_percent(
                                status_item_downloaded_count,
                                status_item_count)

                        for settings in item.getElementsByTagName(
                                'MediaSettings'):
                            settings_audio_boost = helpers.get_xml_attr(
                                settings, 'audioBoost')
                            settings_music_bitrate = helpers.get_xml_attr(
                                settings, 'musicBitrate')
                            settings_photo_quality = helpers.get_xml_attr(
                                settings, 'photoQuality')
                            settings_photo_resolution = helpers.get_xml_attr(
                                settings, 'photoResolution')
                            settings_video_quality = helpers.get_xml_attr(
                                settings, 'videoQuality')
                            settings_video_resolution = helpers.get_xml_attr(
Beispiel #8
0
def check_active_sessions(ws_request=False):

    with monitor_lock:
        pms_connect = pmsconnect.PmsConnect()
        session_list = pms_connect.get_current_activity()
        monitor_db = database.MonitorDatabase()
        monitor_process = activity_processor.ActivityProcessor()
        # logger.debug(u"PlexPy Monitor :: Checking for active streams.")

        global int_ping_count

        if session_list:
            if int_ping_count >= 3:
                logger.info(u"PlexPy Monitor :: The Plex Media Server is back up.")
                # Fire off notifications
                threading.Thread(target=notification_handler.notify_timeline,
                                    kwargs=dict(notify_action='intup')).start()
            int_ping_count = 0

            media_container = session_list['sessions']

            # Check our temp table for what we must do with the new streams
            db_streams = monitor_db.select('SELECT * FROM sessions')
            for stream in db_streams:
                if any(d['session_key'] == str(stream['session_key']) and d['rating_key'] == str(stream['rating_key'])
                       for d in media_container):
                    # The user's session is still active
                    for session in media_container:
                        if session['session_key'] == str(stream['session_key']) and \
                                session['rating_key'] == str(stream['rating_key']):
                            # The user is still playing the same media item
                            # Here we can check the play states
                            if session['state'] != stream['state']:
                                if session['state'] == 'paused':
                                    # Push any notifications -
                                    # Push it on it's own thread so we don't hold up our db actions
                                    threading.Thread(target=notification_handler.notify,
                                                     kwargs=dict(stream_data=stream, notify_action='pause')).start()

                                if session['state'] == 'playing' and stream['state'] == 'paused':
                                    # Push any notifications -
                                    # Push it on it's own thread so we don't hold up our db actions
                                    threading.Thread(target=notification_handler.notify,
                                                     kwargs=dict(stream_data=stream, notify_action='resume')).start()

                            if stream['state'] == 'paused' and not ws_request:
                                # The stream is still paused so we need to increment the paused_counter
                                # Using the set config parameter as the interval, probably not the most accurate but
                                # it will have to do for now. If it's a websocket request don't use this method.
                                paused_counter = int(stream['paused_counter']) + plexpy.CONFIG.MONITORING_INTERVAL
                                monitor_db.action('UPDATE sessions SET paused_counter = ? '
                                                  'WHERE session_key = ? AND rating_key = ?',
                                                  [paused_counter, stream['session_key'], stream['rating_key']])

                            if session['state'] == 'buffering' and plexpy.CONFIG.BUFFER_THRESHOLD > 0:
                                # The stream is buffering so we need to increment the buffer_count
                                # We're going just increment on every monitor ping,
                                # would be difficult to keep track otherwise
                                monitor_db.action('UPDATE sessions SET buffer_count = buffer_count + 1 '
                                                  'WHERE session_key = ? AND rating_key = ?',
                                                  [stream['session_key'], stream['rating_key']])

                                # Check the current buffer count and last buffer to determine if we should notify
                                buffer_values = monitor_db.select('SELECT buffer_count, buffer_last_triggered '
                                                                  'FROM sessions '
                                                                  'WHERE session_key = ? AND rating_key = ?',
                                                                  [stream['session_key'], stream['rating_key']])

                                if buffer_values[0]['buffer_count'] >= plexpy.CONFIG.BUFFER_THRESHOLD:
                                    # Push any notifications -
                                    # Push it on it's own thread so we don't hold up our db actions
                                    # Our first buffer notification
                                    if buffer_values[0]['buffer_count'] == plexpy.CONFIG.BUFFER_THRESHOLD:
                                        logger.info(u"PlexPy Monitor :: User '%s' has triggered a buffer warning."
                                                    % stream['user'])
                                        # Set the buffer trigger time
                                        monitor_db.action('UPDATE sessions '
                                                          'SET buffer_last_triggered = strftime("%s","now") '
                                                          'WHERE session_key = ? AND rating_key = ?',
                                                          [stream['session_key'], stream['rating_key']])

                                        threading.Thread(target=notification_handler.notify,
                                                         kwargs=dict(stream_data=stream, notify_action='buffer')).start()
                                    else:
                                        # Subsequent buffer notifications after wait time
                                        if int(time.time()) > buffer_values[0]['buffer_last_triggered'] + \
                                                plexpy.CONFIG.BUFFER_WAIT:
                                            logger.info(u"PlexPy Monitor :: User '%s' has triggered multiple buffer warnings."
                                                    % stream['user'])
                                            # Set the buffer trigger time
                                            monitor_db.action('UPDATE sessions '
                                                              'SET buffer_last_triggered = strftime("%s","now") '
                                                              'WHERE session_key = ? AND rating_key = ?',
                                                              [stream['session_key'], stream['rating_key']])

                                            threading.Thread(target=notification_handler.notify,
                                                             kwargs=dict(stream_data=stream, notify_action='buffer')).start()

                                logger.debug(u"PlexPy Monitor :: Stream buffering. Count is now %s. Last triggered %s."
                                             % (buffer_values[0]['buffer_count'],
                                                buffer_values[0]['buffer_last_triggered']))

                            # Check if the user has reached the offset in the media we defined as the "watched" percent
                            # Don't trigger if state is buffer as some clients push the progress to the end when
                            # buffering on start.
                            if session['view_offset'] and session['duration'] and session['state'] != 'buffering':
                                if helpers.get_percent(session['view_offset'],
                                                       session['duration']) > plexpy.CONFIG.NOTIFY_WATCHED_PERCENT:
                                    # Push any notifications -
                                    # Push it on it's own thread so we don't hold up our db actions
                                    threading.Thread(target=notification_handler.notify,
                                                     kwargs=dict(stream_data=stream, notify_action='watched')).start()

                else:
                    # The user has stopped playing a stream
                    logger.debug(u"PlexPy Monitor :: Removing sessionKey %s ratingKey %s from session queue"
                                 % (stream['session_key'], stream['rating_key']))
                    monitor_db.action('DELETE FROM sessions WHERE session_key = ? AND rating_key = ?',
                                      [stream['session_key'], stream['rating_key']])

                    # Check if the user has reached the offset in the media we defined as the "watched" percent
                    if stream['view_offset'] and stream['duration']:
                        if helpers.get_percent(stream['view_offset'],
                                               stream['duration']) > plexpy.CONFIG.NOTIFY_WATCHED_PERCENT:
                            # Push any notifications -
                            # Push it on it's own thread so we don't hold up our db actions
                            threading.Thread(target=notification_handler.notify,
                                             kwargs=dict(stream_data=stream, notify_action='watched')).start()

                    # Push any notifications - Push it on it's own thread so we don't hold up our db actions
                    threading.Thread(target=notification_handler.notify,
                                     kwargs=dict(stream_data=stream, notify_action='stop')).start()

                    # Write the item history on playback stop
                    monitor_process.write_session_history(session=stream)

            # Process the newly received session data
            for session in media_container:
                monitor_process.write_session(session)
        else:
            logger.debug(u"PlexPy Monitor :: Unable to read session list.")

            int_ping_count += 1
            logger.warn(u"PlexPy Monitor :: Unable to get an internal response from the server, ping attempt %s." \
                        % str(int_ping_count))

        if int_ping_count == 3:
            # Fire off notifications
            threading.Thread(target=notification_handler.notify_timeline,
                             kwargs=dict(notify_action='intdown')).start()
Beispiel #9
0
    def write_session_history(self,
                              session=None,
                              import_metadata=None,
                              is_import=False,
                              import_ignore_interval=0):
        server_name = plexpy.PMS_SERVERS.get_server_by_id(
            session['server_id']).CONFIG.PMS_NAME

        library_id = plexpy.libraries.get_section_index(
            session['server_id'], session['section_id'])

        if not is_import:
            user_data = users.Users()
            user_details = user_data.get_details(user_id=session['user_id'])

            library_data = libraries.Libraries()
            library_details = library_data.get_details(id=library_id)

            # Return false if failed to retrieve user or library details
            if not user_details or not library_details:
                return False

        if session:
            logging_enabled = False

            # Reload json from raw stream info
            if session.get('raw_stream_info'):
                raw_stream_info = json.loads(session['raw_stream_info'])
                # Don't overwrite id, session_key, stopped, view_offset
                raw_stream_info.pop('id', None)
                raw_stream_info.pop('session_key', None)
                raw_stream_info.pop('stopped', None)
                raw_stream_info.pop('view_offset', None)
                session.update(raw_stream_info)

            session = defaultdict(str, session)

            if is_import:
                if str(session['stopped']).isdigit():
                    stopped = int(session['stopped'])
                else:
                    stopped = int(time.time())
            elif session['stopped']:
                stopped = int(session['stopped'])
            else:
                stopped = int(time.time())
                self.set_session_state(session_key=session['session_key'],
                                       state='stopped',
                                       stopped=stopped)

            if str(session['rating_key']).isdigit(
            ) and session['media_type'] in ('movie', 'episode', 'track'):
                logging_enabled = True
            else:
                logger.debug(
                    u"Tautulli ActivityProcessor :: %s: Session %s ratingKey %s not logged. "
                    u"Does not meet logging criteria. Media type is '%s'" %
                    (server_name, session['session_key'],
                     session['rating_key'], session['media_type']))
                return session['id']

            if str(session['paused_counter']).isdigit():
                real_play_time = stopped - int(session['started']) - int(
                    session['paused_counter'])
            else:
                real_play_time = stopped - int(session['started'])

            if not is_import and plexpy.CONFIG.LOGGING_IGNORE_INTERVAL:
                if (session['media_type'] == 'movie' or session['media_type'] == 'episode') and \
                        (real_play_time < int(plexpy.CONFIG.LOGGING_IGNORE_INTERVAL)):
                    logging_enabled = False
                    logger.debug(
                        u"Tautulli ActivityProcessor :: %s: Play duration for session %s ratingKey %s is %s secs "
                        u"which is less than %s seconds, so we're not logging it."
                        % (server_name, session['session_key'],
                           session['rating_key'], str(real_play_time),
                           plexpy.CONFIG.LOGGING_IGNORE_INTERVAL))
            if not is_import and session['media_type'] == 'track':
                if real_play_time < 15 and int(session['duration']) >= 30:
                    logging_enabled = False
                    logger.debug(
                        u"Tautulli ActivityProcessor :: %s: Play duration for session %s ratingKey %s is %s secs, "
                        u"looks like it was skipped so we're not logging it" %
                        (server_name, session['session_key'],
                         session['rating_key'], str(real_play_time)))
            elif is_import and import_ignore_interval:
                if (session['media_type'] == 'movie' or session['media_type'] == 'episode') and \
                        (real_play_time < int(import_ignore_interval)):
                    logging_enabled = False
                    logger.debug(
                        u"Tautulli ActivityProcessor :: %s: Play duration for ratingKey %s is %s secs which is less than %s "
                        u"seconds, so we're not logging it." %
                        (server_name, session['rating_key'],
                         str(real_play_time), import_ignore_interval))

            if not is_import and not user_details['keep_history']:
                logging_enabled = False
                logger.debug(
                    u"Tautulli ActivityProcessor :: %s: History logging for user '%s' is disabled."
                    % (server_name, user_details['username']))
            elif not is_import and not library_details['keep_history']:
                logging_enabled = False
                logger.debug(
                    u"Tautulli ActivityProcessor :: %s: History logging for library '%s' is disabled."
                    % (server_name, library_details['section_name']))

            if logging_enabled:

                # Fetch metadata first so we can return false if it fails
                if not is_import:
                    logger.debug(
                        u"Tautulli ActivityProcessor :: %s: Fetching metadata for item ratingKey %s"
                        % (server_name, session['rating_key']))
                    metadata = self.server.get_metadata_details(
                        rating_key=str(session['rating_key']))
                    if not metadata:
                        return False
                    else:
                        media_info = {}
                        if 'media_info' in metadata and len(
                                metadata['media_info']) > 0:
                            media_info = metadata['media_info'][0]
                else:
                    metadata = import_metadata
                    ## TODO: Fix media info from imports. Temporary media info from import session.
                    media_info = session

                # logger.debug(u"Tautulli ActivityProcessor :: %s: Attempting to write sessionKey %s to session_history table..."
                #              % (server_name, session['session_key']))
                keys = {'id': None}
                values = {
                    'started': session['started'],
                    'stopped': stopped,
                    'rating_key': session['rating_key'],
                    'server_id': session['server_id'],
                    'parent_rating_key': session['parent_rating_key'],
                    'grandparent_rating_key':
                    session['grandparent_rating_key'],
                    'media_type': session['media_type'],
                    'user_id': session['user_id'],
                    'user': session['user'],
                    'ip_address': session['ip_address'],
                    'paused_counter': session['paused_counter'],
                    'player': session['player'],
                    'product': session['product'],
                    'product_version': session['product_version'],
                    'platform': session['platform'],
                    'platform_version': session['platform_version'],
                    'profile': session['profile'],
                    'machine_id': session['machine_id'],
                    'bandwidth': session['bandwidth'],
                    'location': session['location'],
                    'quality_profile': session['quality_profile'],
                    'view_offset': session['view_offset']
                }

                # logger.debug(u"Tautulli ActivityProcessor :: %s: Writing sessionKey %s session_history transaction..."
                #              % (server_name, session['session_key']))
                self.db.upsert(table_name='session_history',
                               key_dict=keys,
                               value_dict=values)

                # Check if we should group the session, select the last two rows from the user
                query = 'SELECT id, server_id, rating_key, view_offset, user_id, reference_id FROM session_history ' \
                        'WHERE user_id = ? AND server_id = ? AND rating_key = ? ORDER BY id DESC LIMIT 2 '

                args = [
                    session['user_id'], session['server_id'],
                    session['rating_key']
                ]

                result = self.db.select(query=query, args=args)

                new_session = prev_session = None
                prev_progress_percent = media_watched_percent = 0
                # Get the last insert row id
                last_id = self.db.last_insert_id()

                if len(result) > 1:
                    new_session = {
                        'id': result[0]['id'],
                        'server_id': result[0]['server_id'],
                        'rating_key': result[0]['rating_key'],
                        'view_offset': result[0]['view_offset'],
                        'user_id': result[0]['user_id'],
                        'reference_id': result[0]['reference_id']
                    }

                    prev_session = {
                        'id': result[1]['id'],
                        'server_id': result[1]['server_id'],
                        'rating_key': result[1]['rating_key'],
                        'view_offset': result[1]['view_offset'],
                        'user_id': result[1]['user_id'],
                        'reference_id': result[1]['reference_id']
                    }

                    watched_percent = {
                        'movie': plexpy.CONFIG.MOVIE_WATCHED_PERCENT,
                        'episode': plexpy.CONFIG.TV_WATCHED_PERCENT,
                        'track': plexpy.CONFIG.MUSIC_WATCHED_PERCENT
                    }
                    prev_progress_percent = helpers.get_percent(
                        prev_session['view_offset'], session['duration'])
                    media_watched_percent = watched_percent.get(
                        session['media_type'], 0)

                query = 'UPDATE session_history SET reference_id = ? WHERE id = ? '

                # If previous session view offset less than watched percent,
                # and new session view offset is greater,
                # then set the reference_id to the previous row,
                # else set the reference_id to the new id
                if prev_session is None and new_session is None:
                    args = [last_id, last_id]
                elif prev_progress_percent < media_watched_percent and \
                        prev_session['view_offset'] <= new_session['view_offset']:
                    args = [prev_session['reference_id'], new_session['id']]
                else:
                    args = [new_session['id'], new_session['id']]

                self.db.action(query=query, args=args)

                # logger.debug(u"Tautulli ActivityProcessor :: %s: Successfully written history item, last id for session_history is %s"
                #              % (server_name, last_id))

                # Write the session_history_media_info table

                # logger.debug(u"Tautulli ActivityProcessor :: %s: Attempting to write to sessionKey %s session_history_media_info table..."
                #              % (server_name, session['session_key']))
                keys = {'id': last_id}
                values = {
                    'rating_key':
                    session['rating_key'],
                    'server_id':
                    session['server_id'],
                    'video_decision':
                    session['video_decision'],
                    'audio_decision':
                    session['audio_decision'],
                    'transcode_decision':
                    session['transcode_decision'],
                    'duration':
                    session['duration'],
                    'container':
                    session['container'],
                    'bitrate':
                    session['bitrate'],
                    'width':
                    session['width'],
                    'height':
                    session['height'],
                    'video_bit_depth':
                    session['video_bit_depth'],
                    'video_bitrate':
                    session['video_bitrate'],
                    'video_codec':
                    session['video_codec'],
                    'video_codec_level':
                    session['video_codec_level'],
                    'video_width':
                    session['video_width'],
                    'video_height':
                    session['video_height'],
                    'video_resolution':
                    session['video_resolution'],
                    'video_framerate':
                    session['video_framerate'],
                    'aspect_ratio':
                    session['aspect_ratio'],
                    'audio_codec':
                    session['audio_codec'],
                    'audio_bitrate':
                    session['audio_bitrate'],
                    'audio_channels':
                    session['audio_channels'],
                    'subtitle_codec':
                    session['subtitle_codec'],
                    'transcode_protocol':
                    session['transcode_protocol'],
                    'transcode_container':
                    session['transcode_container'],
                    'transcode_video_codec':
                    session['transcode_video_codec'],
                    'transcode_audio_codec':
                    session['transcode_audio_codec'],
                    'transcode_audio_channels':
                    session['transcode_audio_channels'],
                    'transcode_width':
                    session['transcode_width'],
                    'transcode_height':
                    session['transcode_height'],
                    'transcode_hw_requested':
                    session['transcode_hw_requested'],
                    'transcode_hw_full_pipeline':
                    session['transcode_hw_full_pipeline'],
                    'transcode_hw_decoding':
                    session['transcode_hw_decoding'],
                    'transcode_hw_decode':
                    session['transcode_hw_decode'],
                    'transcode_hw_decode_title':
                    session['transcode_hw_decode_title'],
                    'transcode_hw_encoding':
                    session['transcode_hw_encoding'],
                    'transcode_hw_encode':
                    session['transcode_hw_encode'],
                    'transcode_hw_encode_title':
                    session['transcode_hw_encode_title'],
                    'stream_container':
                    session['stream_container'],
                    'stream_container_decision':
                    session['stream_container_decision'],
                    'stream_bitrate':
                    session['stream_bitrate'],
                    'stream_video_decision':
                    session['stream_video_decision'],
                    'stream_video_bitrate':
                    session['stream_video_bitrate'],
                    'stream_video_codec':
                    session['stream_video_codec'],
                    'stream_video_codec_level':
                    session['stream_video_codec_level'],
                    'stream_video_bit_depth':
                    session['stream_video_bit_depth'],
                    'stream_video_height':
                    session['stream_video_height'],
                    'stream_video_width':
                    session['stream_video_width'],
                    'stream_video_resolution':
                    session['stream_video_resolution'],
                    'stream_video_framerate':
                    session['stream_video_framerate'],
                    'stream_audio_decision':
                    session['stream_audio_decision'],
                    'stream_audio_codec':
                    session['stream_audio_codec'],
                    'stream_audio_bitrate':
                    session['stream_audio_bitrate'],
                    'stream_audio_channels':
                    session['stream_audio_channels'],
                    'stream_subtitle_decision':
                    session['stream_subtitle_decision'],
                    'stream_subtitle_codec':
                    session['stream_subtitle_codec'],
                    'stream_subtitle_container':
                    session['stream_subtitle_container'],
                    'stream_subtitle_forced':
                    session['stream_subtitle_forced'],
                    'subtitles':
                    session['subtitles'],
                    'synced_version':
                    session['synced_version'],
                    'synced_version_profile':
                    session['synced_version_profile'],
                    'optimized_version':
                    session['optimized_version'],
                    'optimized_version_profile':
                    session['optimized_version_profile'],
                    'optimized_version_title':
                    session['optimized_version_title']
                }

                # logger.debug(u"Tautulli ActivityProcessor :: %s: Writing sessionKey %s session_history_media_info transaction..."
                #              % (server_name, session['session_key']))
                self.db.upsert(table_name='session_history_media_info',
                               key_dict=keys,
                               value_dict=values)

                # Write the session_history_metadata table
                directors = ";".join(metadata['directors'])
                writers = ";".join(metadata['writers'])
                actors = ";".join(metadata['actors'])
                genres = ";".join(metadata['genres'])
                labels = ";".join(metadata['labels'])

                # logger.debug(u"Tautulli ActivityProcessor :: %s: Attempting to write to sessionKey %s session_history_metadata table..."
                #              % (server_name, session['session_key']))
                keys = {'id': last_id}
                values = {
                    'rating_key': session['rating_key'],
                    'server_id': session['server_id'],
                    'parent_rating_key': session['parent_rating_key'],
                    'grandparent_rating_key':
                    session['grandparent_rating_key'],
                    'title': session['title'],
                    'parent_title': session['parent_title'],
                    'grandparent_title': session['grandparent_title'],
                    'original_title': session['original_title'],
                    'full_title': session['full_title'],
                    'media_index': metadata['media_index'],
                    'parent_media_index': metadata['parent_media_index'],
                    'section_id': metadata['section_id'],
                    'library_id': library_id,
                    'thumb': metadata['thumb'],
                    'parent_thumb': metadata['parent_thumb'],
                    'grandparent_thumb': metadata['grandparent_thumb'],
                    'art': metadata['art'],
                    'media_type': session['media_type'],
                    'year': metadata['year'],
                    'originally_available_at':
                    metadata['originally_available_at'],
                    'added_at': metadata['added_at'],
                    'updated_at': metadata['updated_at'],
                    'last_viewed_at': metadata['last_viewed_at'],
                    'content_rating': metadata['content_rating'],
                    'summary': metadata['summary'],
                    'tagline': metadata['tagline'],
                    'rating': metadata['rating'],
                    'duration': metadata['duration'],
                    'guid': metadata['guid'],
                    'directors': directors,
                    'writers': writers,
                    'actors': actors,
                    'genres': genres,
                    'studio': metadata['studio'],
                    'labels': labels
                }

                # logger.debug(u"Tautulli ActivityProcessor :: %s: Writing sessionKey %s session_history_metadata transaction..."
                #              % (server_name, session['session_key']))
                self.db.upsert(table_name='session_history_metadata',
                               key_dict=keys,
                               value_dict=values)

            # Return the session row id when the session is successfully written to the database
            return session['id']
Beispiel #10
0
    def get_synced_items(self, machine_id=None, user_id=None):
        sync_list = self.get_plextv_sync_lists(machine_id)
        user_data = users.Users()

        synced_items = []

        try:
            xml_parse = minidom.parseString(sync_list)
        except Exception as e:
            logger.warn(u"PlexPy PlexTV :: Unable to parse XML for get_synced_items: %s" % e)
            return []
        except:
            logger.warn(u"PlexPy PlexTV :: Unable to parse XML for get_synced_items.")
            return []

        xml_head = xml_parse.getElementsByTagName('SyncList')

        if not xml_head:
            logger.warn(u"PlexPy PlexTV :: Unable to parse XML for get_synced_items.")
        else:
            for a in xml_head:
                client_id = helpers.get_xml_attr(a, 'id')
                sync_device = a.getElementsByTagName('Device')
                for device in sync_device:
                    device_user_id = helpers.get_xml_attr(device, 'userID')
                    try:
                        device_username = user_data.get_details(user_id=device_user_id)['username']
                        device_friendly_name = user_data.get_details(user_id=device_user_id)['friendly_name']
                    except:
                        device_username = ''
                        device_friendly_name = ''
                    device_name = helpers.get_xml_attr(device, 'name')
                    device_product = helpers.get_xml_attr(device, 'product')
                    device_product_version = helpers.get_xml_attr(device, 'productVersion')
                    device_platform = helpers.get_xml_attr(device, 'platform')
                    device_platform_version = helpers.get_xml_attr(device, 'platformVersion')
                    device_type = helpers.get_xml_attr(device, 'device')
                    device_model = helpers.get_xml_attr(device, 'model')
                    device_last_seen = helpers.get_xml_attr(device, 'lastSeenAt')

                # Filter by user_id
                if user_id and user_id != device_user_id:
                    continue

                for synced in a.getElementsByTagName('SyncItems'):
                    sync_item = synced.getElementsByTagName('SyncItem')
                    for item in sync_item:
                        sync_id = helpers.get_xml_attr(item, 'id')
                        sync_version = helpers.get_xml_attr(item, 'version')
                        sync_root_title = helpers.get_xml_attr(item, 'rootTitle')
                        sync_title = helpers.get_xml_attr(item, 'title')
                        sync_metadata_type = helpers.get_xml_attr(item, 'metadataType')
                        sync_content_type = helpers.get_xml_attr(item, 'contentType')

                        for status in item.getElementsByTagName('Status'):
                            status_failure_code = helpers.get_xml_attr(status, 'failureCode')
                            status_failure = helpers.get_xml_attr(status, 'failure')
                            status_state = helpers.get_xml_attr(status, 'state')
                            status_item_count = helpers.get_xml_attr(status, 'itemsCount')
                            status_item_complete_count = helpers.get_xml_attr(status, 'itemsCompleteCount')
                            status_item_downloaded_count = helpers.get_xml_attr(status, 'itemsDownloadedCount')
                            status_item_ready_count = helpers.get_xml_attr(status, 'itemsReadyCount')
                            status_item_successful_count = helpers.get_xml_attr(status, 'itemsSuccessfulCount')
                            status_total_size = helpers.get_xml_attr(status, 'totalSize')
                            status_item_download_percent_complete = helpers.get_percent(
                                status_item_downloaded_count, status_item_count)

                        for settings in item.getElementsByTagName('MediaSettings'):
                            settings_audio_boost = helpers.get_xml_attr(settings, 'audioBoost')
                            settings_music_bitrate = helpers.get_xml_attr(settings, 'musicBitrate')
                            settings_photo_quality = helpers.get_xml_attr(settings, 'photoQuality')
                            settings_photo_resolution = helpers.get_xml_attr(settings, 'photoResolution')
                            settings_video_quality = helpers.get_xml_attr(settings, 'videoQuality')
                            settings_video_resolution = helpers.get_xml_attr(settings, 'videoResolution')

                        for location in item.getElementsByTagName('Location'):
                            clean_uri = helpers.get_xml_attr(location, 'uri').split('%2F')

                        rating_key = next((clean_uri[(idx + 1) % len(clean_uri)] 
                                           for idx, item in enumerate(clean_uri) if item == 'metadata'), None)

                        sync_details = {"device_name": helpers.sanitize(device_name),
                                        "platform": helpers.sanitize(device_platform),
                                        "username": helpers.sanitize(device_username),
                                        "friendly_name": helpers.sanitize(device_friendly_name),
                                        "user_id": device_user_id,
                                        "root_title": helpers.sanitize(sync_root_title),
                                        "title": helpers.sanitize(sync_title),
                                        "metadata_type": sync_metadata_type,
                                        "content_type": sync_content_type,
                                        "rating_key": rating_key,
                                        "state": status_state,
                                        "item_count": status_item_count,
                                        "item_complete_count": status_item_complete_count,
                                        "item_downloaded_count": status_item_downloaded_count,
                                        "item_downloaded_percent_complete": status_item_download_percent_complete,
                                        "music_bitrate": settings_music_bitrate,
                                        "photo_quality": settings_photo_quality,
                                        "video_quality": settings_video_quality,
                                        "total_size": status_total_size,
                                        "failure": status_failure,
                                        "sync_id": sync_id
                                        }

                        synced_items.append(sync_details)

        return synced_items
Beispiel #11
0
def notify(stream_data=None, notify_action=None):
    from plexpy import users

    if stream_data and notify_action:
        # Check if notifications enabled for user
        user_data = users.Users()
        user_details = user_data.get_user_friendly_name(
            user=stream_data['user'])

        if not user_details['do_notify']:
            return

        if (stream_data['media_type'] == 'movie' and plexpy.CONFIG.MOVIE_NOTIFY_ENABLE) \
            or (stream_data['media_type'] == 'episode' and plexpy.CONFIG.TV_NOTIFY_ENABLE):

            progress_percent = helpers.get_percent(stream_data['view_offset'],
                                                   stream_data['duration'])

            for agent in notifiers.available_notification_agents():
                if agent['on_play'] and notify_action == 'play':
                    # Build and send notification
                    notify_strings = build_notify_text(session=stream_data,
                                                       state=notify_action)
                    notifiers.send_notification(config_id=agent['id'],
                                                subject=notify_strings[0],
                                                body=notify_strings[1])
                    # Set the notification state in the db
                    set_notify_state(session=stream_data,
                                     state=notify_action,
                                     agent_info=agent)

                elif agent['on_stop'] and notify_action == 'stop' \
                    and (plexpy.CONFIG.NOTIFY_CONSECUTIVE or progress_percent < plexpy.CONFIG.NOTIFY_WATCHED_PERCENT):
                    # Build and send notification
                    notify_strings = build_notify_text(session=stream_data,
                                                       state=notify_action)
                    notifiers.send_notification(config_id=agent['id'],
                                                subject=notify_strings[0],
                                                body=notify_strings[1])

                    set_notify_state(session=stream_data,
                                     state=notify_action,
                                     agent_info=agent)

                elif agent['on_pause'] and notify_action == 'pause' \
                    and (plexpy.CONFIG.NOTIFY_CONSECUTIVE or progress_percent < 99):
                    # Build and send notification
                    notify_strings = build_notify_text(session=stream_data,
                                                       state=notify_action)
                    notifiers.send_notification(config_id=agent['id'],
                                                subject=notify_strings[0],
                                                body=notify_strings[1])

                    set_notify_state(session=stream_data,
                                     state=notify_action,
                                     agent_info=agent)

                elif agent['on_resume'] and notify_action == 'resume' \
                    and (plexpy.CONFIG.NOTIFY_CONSECUTIVE or progress_percent < 99):
                    # Build and send notification
                    notify_strings = build_notify_text(session=stream_data,
                                                       state=notify_action)
                    notifiers.send_notification(config_id=agent['id'],
                                                subject=notify_strings[0],
                                                body=notify_strings[1])

                    set_notify_state(session=stream_data,
                                     state=notify_action,
                                     agent_info=agent)

                elif agent['on_buffer'] and notify_action == 'buffer':
                    # Build and send notification
                    notify_strings = build_notify_text(session=stream_data,
                                                       state=notify_action)
                    notifiers.send_notification(config_id=agent['id'],
                                                subject=notify_strings[0],
                                                body=notify_strings[1])

                    set_notify_state(session=stream_data,
                                     state=notify_action,
                                     agent_info=agent)

                elif agent['on_watched'] and notify_action == 'watched':
                    # Get the current states for notifications from our db
                    notify_states = get_notify_state(session=stream_data)

                    # If there is nothing in the notify_log for our agent id but it is enabled we should notify
                    if not any(d['agent_id'] == agent['id']
                               for d in notify_states):
                        # Build and send notification
                        notify_strings = build_notify_text(session=stream_data,
                                                           state=notify_action)
                        notifiers.send_notification(config_id=agent['id'],
                                                    subject=notify_strings[0],
                                                    body=notify_strings[1])
                        # Set the notification state in the db
                        set_notify_state(session=stream_data,
                                         state=notify_action,
                                         agent_info=agent)

                    else:
                        # Check in our notify log if the notification has already been sent
                        for notify_state in notify_states:
                            if not notify_state['on_watched'] and (
                                    notify_state['agent_id'] == agent['id']):
                                # Build and send notification
                                notify_strings = build_notify_text(
                                    session=stream_data, state=notify_action)
                                notifiers.send_notification(
                                    config_id=agent['id'],
                                    subject=notify_strings[0],
                                    body=notify_strings[1])
                                # Set the notification state in the db
                                set_notify_state(session=stream_data,
                                                 state=notify_action,
                                                 agent_info=agent)

        elif (stream_data['media_type'] == 'track'
              and plexpy.CONFIG.MUSIC_NOTIFY_ENABLE):

            for agent in notifiers.available_notification_agents():
                if agent['on_play'] and notify_action == 'play':
                    # Build and send notification
                    notify_strings = build_notify_text(session=stream_data,
                                                       state=notify_action)
                    notifiers.send_notification(config_id=agent['id'],
                                                subject=notify_strings[0],
                                                body=notify_strings[1])
                    # Set the notification state in the db
                    set_notify_state(session=stream_data,
                                     state=notify_action,
                                     agent_info=agent)

                elif agent['on_stop'] and notify_action == 'stop':
                    # Build and send notification
                    notify_strings = build_notify_text(session=stream_data,
                                                       state=notify_action)
                    notifiers.send_notification(config_id=agent['id'],
                                                subject=notify_strings[0],
                                                body=notify_strings[1])
                    # Set the notification state in the db
                    set_notify_state(session=stream_data,
                                     state=notify_action,
                                     agent_info=agent)

                elif agent['on_pause'] and notify_action == 'pause':
                    # Build and send notification
                    notify_strings = build_notify_text(session=stream_data,
                                                       state=notify_action)
                    notifiers.send_notification(config_id=agent['id'],
                                                subject=notify_strings[0],
                                                body=notify_strings[1])
                    # Set the notification state in the db
                    set_notify_state(session=stream_data,
                                     state=notify_action,
                                     agent_info=agent)

                elif agent['on_resume'] and notify_action == 'resume':
                    # Build and send notification
                    notify_strings = build_notify_text(session=stream_data,
                                                       state=notify_action)
                    notifiers.send_notification(config_id=agent['id'],
                                                subject=notify_strings[0],
                                                body=notify_strings[1])
                    # Set the notification state in the db
                    set_notify_state(session=stream_data,
                                     state=notify_action,
                                     agent_info=agent)

                elif agent['on_buffer'] and notify_action == 'buffer':
                    # Build and send notification
                    notify_strings = build_notify_text(session=stream_data,
                                                       state=notify_action)
                    notifiers.send_notification(config_id=agent['id'],
                                                subject=notify_strings[0],
                                                body=notify_strings[1])
                    # Set the notification state in the db
                    set_notify_state(session=stream_data,
                                     state=notify_action,
                                     agent_info=agent)

        elif stream_data['media_type'] == 'clip':
            pass
        else:
            #logger.debug(u"PlexPy Notifier :: Notify called with unsupported media type.")
            pass
    else:
        logger.debug(
            u"PlexPy Notifier :: Notify called but incomplete data received.")
Beispiel #12
0
    def get_synced_items(self, machine_id=None, user_id=None):
        sync_list = self.get_plextv_sync_lists(machine_id)
        user_data = users.Users()

        synced_items = []

        try:
            xml_parse = minidom.parseString(sync_list)
        except Exception as e:
            logger.warn(
                u"PlexPy PlexTV :: Unable to parse XML for get_synced_items: %s"
                % e)
            return []
        except:
            logger.warn(
                u"PlexPy PlexTV :: Unable to parse XML for get_synced_items.")
            return []

        xml_head = xml_parse.getElementsByTagName('SyncList')

        if not xml_head:
            logger.warn(
                u"PlexPy PlexTV :: Unable to parse XML for get_synced_items.")
        else:
            for a in xml_head:
                client_id = helpers.get_xml_attr(a, 'id')
                sync_device = a.getElementsByTagName('Device')
                for device in sync_device:
                    device_user_id = helpers.get_xml_attr(device, 'userID')
                    try:
                        device_username = user_data.get_details(
                            user_id=device_user_id)['username']
                        device_friendly_name = user_data.get_details(
                            user_id=device_user_id)['friendly_name']
                    except:
                        device_username = ''
                        device_friendly_name = ''
                    device_name = helpers.get_xml_attr(device, 'name')
                    device_product = helpers.get_xml_attr(device, 'product')
                    device_product_version = helpers.get_xml_attr(
                        device, 'productVersion')
                    device_platform = helpers.get_xml_attr(device, 'platform')
                    device_platform_version = helpers.get_xml_attr(
                        device, 'platformVersion')
                    device_type = helpers.get_xml_attr(device, 'device')
                    device_model = helpers.get_xml_attr(device, 'model')
                    device_last_seen = helpers.get_xml_attr(
                        device, 'lastSeenAt')

                # Filter by user_id
                if user_id and user_id != device_user_id:
                    continue

                for synced in a.getElementsByTagName('SyncItems'):
                    sync_item = synced.getElementsByTagName('SyncItem')
                    for item in sync_item:
                        sync_id = helpers.get_xml_attr(item, 'id')
                        sync_version = helpers.get_xml_attr(item, 'version')
                        sync_root_title = helpers.get_xml_attr(
                            item, 'rootTitle')
                        sync_title = helpers.get_xml_attr(item, 'title')
                        sync_metadata_type = helpers.get_xml_attr(
                            item, 'metadataType')
                        sync_content_type = helpers.get_xml_attr(
                            item, 'contentType')

                        for status in item.getElementsByTagName('Status'):
                            status_failure_code = helpers.get_xml_attr(
                                status, 'failureCode')
                            status_failure = helpers.get_xml_attr(
                                status, 'failure')
                            status_state = helpers.get_xml_attr(
                                status, 'state')
                            status_item_count = helpers.get_xml_attr(
                                status, 'itemsCount')
                            status_item_complete_count = helpers.get_xml_attr(
                                status, 'itemsCompleteCount')
                            status_item_downloaded_count = helpers.get_xml_attr(
                                status, 'itemsDownloadedCount')
                            status_item_ready_count = helpers.get_xml_attr(
                                status, 'itemsReadyCount')
                            status_item_successful_count = helpers.get_xml_attr(
                                status, 'itemsSuccessfulCount')
                            status_total_size = helpers.get_xml_attr(
                                status, 'totalSize')
                            status_item_download_percent_complete = helpers.get_percent(
                                status_item_downloaded_count,
                                status_item_count)

                        for settings in item.getElementsByTagName(
                                'MediaSettings'):
                            settings_audio_boost = helpers.get_xml_attr(
                                settings, 'audioBoost')
                            settings_music_bitrate = helpers.get_xml_attr(
                                settings, 'musicBitrate')
                            settings_photo_quality = helpers.get_xml_attr(
                                settings, 'photoQuality')
                            settings_photo_resolution = helpers.get_xml_attr(
                                settings, 'photoResolution')
                            settings_video_quality = helpers.get_xml_attr(
                                settings, 'videoQuality')
                            settings_video_resolution = helpers.get_xml_attr(
                                settings, 'videoResolution')

                        for location in item.getElementsByTagName('Location'):
                            clean_uri = helpers.get_xml_attr(
                                location, 'uri').split('%2F')

                        rating_key = next(
                            (clean_uri[(idx + 1) % len(clean_uri)]
                             for idx, item in enumerate(clean_uri)
                             if item == 'metadata'), None)

                        sync_details = {
                            "device_name": helpers.sanitize(device_name),
                            "platform": helpers.sanitize(device_platform),
                            "username": helpers.sanitize(device_username),
                            "friendly_name":
                            helpers.sanitize(device_friendly_name),
                            "user_id": device_user_id,
                            "root_title": helpers.sanitize(sync_root_title),
                            "title": helpers.sanitize(sync_title),
                            "metadata_type": sync_metadata_type,
                            "content_type": sync_content_type,
                            "rating_key": rating_key,
                            "state": status_state,
                            "item_count": status_item_count,
                            "item_complete_count": status_item_complete_count,
                            "item_downloaded_count":
                            status_item_downloaded_count,
                            "item_downloaded_percent_complete":
                            status_item_download_percent_complete,
                            "music_bitrate": settings_music_bitrate,
                            "photo_quality": settings_photo_quality,
                            "video_quality": settings_video_quality,
                            "total_size": status_total_size,
                            "failure": status_failure,
                            "sync_id": sync_id
                        }

                        synced_items.append(sync_details)

        return synced_items
Beispiel #13
0
def build_notify_text(session=None, timeline=None, state=None):
    # Get time formats
    date_format = plexpy.CONFIG.DATE_FORMAT.replace('Do','').replace('zz','')
    time_format = plexpy.CONFIG.TIME_FORMAT.replace('Do','').replace('zz','')
    duration_format = plexpy.CONFIG.TIME_FORMAT.replace('Do','').replace('zz','').replace('a','').replace('A','')

    # Get the server name
    server_name = plexpy.CONFIG.PMS_NAME

    # Get the server uptime
    plex_tv = plextv.PlexTV()
    server_times = plex_tv.get_server_times()

    if server_times:
        updated_at = server_times[0]['updated_at']
        server_uptime = helpers.human_duration(int(time.time() - helpers.cast_to_int(updated_at)))
    else:
        logger.error(u"PlexPy NotificationHandler :: Unable to retrieve server uptime.")
        server_uptime = 'N/A'

    # Get metadata feed for item
    if session:
        rating_key = session['rating_key']
    elif timeline:
        rating_key = timeline['rating_key']

    pms_connect = pmsconnect.PmsConnect()
    metadata_list = pms_connect.get_metadata_details(rating_key=rating_key)

    stream_count = pms_connect.get_current_activity().get('stream_count', '')

    if metadata_list:
        metadata = metadata_list['metadata']
    else:
        logger.error(u"PlexPy NotificationHandler :: Unable to retrieve metadata for rating_key %s" % str(rating_key))
        return []

    # Check for exclusion tags
    if metadata['media_type'] == 'movie':
        # Regex pattern to remove the text in the tags we don't want
        pattern = re.compile('\n*<tv>[^>]+.</tv>\n*|\n*<music>[^>]+.</music>\n*', re.IGNORECASE | re.DOTALL)
    elif metadata['media_type'] == 'show' or metadata['media_type'] == 'episode':
        # Regex pattern to remove the text in the tags we don't want
        pattern = re.compile('\n*<movie>[^>]+.</movie>\n*|\n*?<music>[^>]+.</music>\n*', re.IGNORECASE | re.DOTALL)
    elif metadata['media_type'] == 'artist' or metadata['media_type'] == 'track':
        # Regex pattern to remove the text in the tags we don't want
        pattern = re.compile('\n*<tv>[^>]+.</tv>\n*|\n*<movie>[^>]+.</movie>\n*', re.IGNORECASE | re.DOTALL)
    else:
        pattern = None

    if metadata['media_type'] == 'movie' \
        or metadata['media_type'] == 'show' or metadata['media_type'] == 'episode' \
        or metadata['media_type'] == 'artist' or metadata['media_type'] == 'track' \
        and pattern:
        # Remove the unwanted tags and strip any unmatch tags too.
        on_start_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_START_SUBJECT_TEXT))
        on_start_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_START_BODY_TEXT))
        on_stop_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_STOP_SUBJECT_TEXT))
        on_stop_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_STOP_BODY_TEXT))
        on_pause_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_PAUSE_SUBJECT_TEXT))
        on_pause_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_PAUSE_BODY_TEXT))
        on_resume_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_RESUME_SUBJECT_TEXT))
        on_resume_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_RESUME_BODY_TEXT))
        on_buffer_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_BUFFER_SUBJECT_TEXT))
        on_buffer_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_BUFFER_BODY_TEXT))
        on_watched_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_WATCHED_SUBJECT_TEXT))
        on_watched_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_WATCHED_BODY_TEXT))
        on_created_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_CREATED_SUBJECT_TEXT))
        on_created_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_CREATED_BODY_TEXT))
        script_args_text = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_SCRIPTS_ARGS_TEXT))
    else:
        on_start_subject = plexpy.CONFIG.NOTIFY_ON_START_SUBJECT_TEXT
        on_start_body = plexpy.CONFIG.NOTIFY_ON_START_BODY_TEXT
        on_stop_subject = plexpy.CONFIG.NOTIFY_ON_STOP_SUBJECT_TEXT
        on_stop_body = plexpy.CONFIG.NOTIFY_ON_STOP_BODY_TEXT
        on_pause_subject = plexpy.CONFIG.NOTIFY_ON_PAUSE_SUBJECT_TEXT
        on_pause_body = plexpy.CONFIG.NOTIFY_ON_PAUSE_BODY_TEXT
        on_resume_subject = plexpy.CONFIG.NOTIFY_ON_RESUME_SUBJECT_TEXT
        on_resume_body = plexpy.CONFIG.NOTIFY_ON_RESUME_BODY_TEXT
        on_buffer_subject = plexpy.CONFIG.NOTIFY_ON_BUFFER_SUBJECT_TEXT
        on_buffer_body = plexpy.CONFIG.NOTIFY_ON_BUFFER_BODY_TEXT
        on_watched_subject = plexpy.CONFIG.NOTIFY_ON_WATCHED_SUBJECT_TEXT
        on_watched_body = plexpy.CONFIG.NOTIFY_ON_WATCHED_BODY_TEXT
        on_created_subject = plexpy.CONFIG.NOTIFY_ON_CREATED_SUBJECT_TEXT
        on_created_body = plexpy.CONFIG.NOTIFY_ON_CREATED_BODY_TEXT
        script_args_text = plexpy.CONFIG.NOTIFY_SCRIPTS_ARGS_TEXT

    # Create a title
    if metadata['media_type'] == 'episode' or metadata['media_type'] == 'track':
        full_title = '%s - %s' % (metadata['grandparent_title'],
                                  metadata['title'])
    else:
        full_title = metadata['title']

    # Session values
    if session is None:
        session = {}

    # Generate a combined transcode decision value
    if session.get('video_decision','') == 'transcode' or session.get('audio_decision','') == 'transcode':
        transcode_decision = 'Transcode'
    elif session.get('video_decision','') == 'copy' or session.get('audio_decision','') == 'copy':
        transcode_decision = 'Direct Stream'
    else:
        transcode_decision = 'Direct Play'
    
    if state != 'play':
        stream_duration = int((time.time() -
                               helpers.cast_to_int(session.get('started', 0)) -
                               helpers.cast_to_int(session.get('paused_counter', 0))) / 60)
    else:
        stream_duration = 0

    view_offset = helpers.convert_milliseconds_to_minutes(session.get('view_offset', 0))
    duration = helpers.convert_milliseconds_to_minutes(metadata['duration'])
    progress_percent = helpers.get_percent(view_offset, duration)
    remaining_duration = duration - view_offset

    # Get media IDs from guid and build URLs
    if 'imdb://' in metadata['guid']:
        metadata['imdb_id'] = metadata['guid'].split('imdb://')[1].split('?')[0]
        metadata['imdb_url'] = 'https://www.imdb.com/title/' + metadata['imdb_id']
        metadata['trakt_url'] = 'https://trakt.tv/search/imdb/' + metadata['imdb_id']

    if 'thetvdb://' in metadata['guid']:
        metadata['thetvdb_id'] = metadata['guid'].split('thetvdb://')[1].split('/')[0]
        metadata['thetvdb_url'] = 'https://thetvdb.com/?tab=series&id=' + metadata['thetvdb_id']
        metadata['trakt_url'] = 'https://trakt.tv/search/tvdb/' + metadata['thetvdb_id'] + '?id_type=show'

    elif 'thetvdbdvdorder://' in metadata['guid']:
        metadata['thetvdb_id'] = metadata['guid'].split('thetvdbdvdorder://')[1].split('/')[0]
        metadata['thetvdb_url'] = 'https://thetvdb.com/?tab=series&id=' + metadata['thetvdb_id']
        metadata['trakt_url'] = 'https://trakt.tv/search/tvdb/' + metadata['thetvdb_id'] + '?id_type=show'

    if 'themoviedb://' in metadata['guid']:
        if metadata['media_type'] == 'movie':
            metadata['themoviedb_id'] = metadata['guid'].split('themoviedb://')[1].split('?')[0]
            metadata['themoviedb_url'] = 'https://www.themoviedb.org/movie/' + metadata['themoviedb_id']
            metadata['trakt_url'] = 'https://trakt.tv/search/tmdb/' + metadata['themoviedb_id'] + '?id_type=movie'

        elif metadata['media_type'] == 'show' or metadata['media_type'] == 'episode':
            metadata['themoviedb_id'] = metadata['guid'].split('themoviedb://')[1].split('/')[0]
            metadata['themoviedb_url'] = 'https://www.themoviedb.org/tv/' + metadata['themoviedb_id']
            metadata['trakt_url'] = 'https://trakt.tv/search/tmdb/' + metadata['themoviedb_id'] + '?id_type=show'

    if 'lastfm://' in metadata['guid']:
        metadata['lastfm_id'] = metadata['guid'].split('lastfm://')[1].rsplit('/', 1)[0]
        metadata['lastfm_url'] = 'https://www.last.fm/music/' + metadata['lastfm_id']

    if metadata['media_type'] == 'movie' or metadata['media_type'] == 'show' or metadata['media_type'] == 'artist':
        thumb = metadata['thumb']
    elif metadata['media_type'] == 'episode':
        thumb = metadata['grandparent_thumb']
    elif metadata['media_type'] == 'track':
        thumb = metadata['parent_thumb']
    else:
        thumb = None

    if thumb:
        # Retrieve the poster from Plex and cache to file
        urllib.urlretrieve(plexpy.CONFIG.PMS_URL + thumb + '?X-Plex-Token=' + plexpy.CONFIG.PMS_TOKEN,
                           os.path.join(plexpy.CONFIG.CACHE_DIR, 'cache-poster.jpg'))
        # Upload thumb to Imgur and get link
        metadata['poster_url'] = helpers.uploadToImgur(os.path.join(plexpy.CONFIG.CACHE_DIR, 'cache-poster.jpg'), full_title)

    # Fix metadata params for notify recently added grandparent
    if state == 'created' and plexpy.CONFIG.NOTIFY_RECENTLY_ADDED_GRANDPARENT:
        show_name = metadata['title']
        episode_name = ''
        artist_name = metadata['title']
        album_name = ''
        track_name = ''
    else:
        show_name = metadata['grandparent_title']
        episode_name = metadata['title']
        artist_name = metadata['grandparent_title']
        album_name = metadata['parent_title']
        track_name = metadata['title']

    available_params = {# Global paramaters
                        'server_name': server_name,
                        'server_uptime': server_uptime,
                        'action': state.title(),
                        'datestamp': arrow.now().format(date_format),
                        'timestamp': arrow.now().format(time_format),
                        # Stream parameters
                        'streams': stream_count,
                        'user': session.get('friendly_name',''),
                        'platform': session.get('platform',''),
                        'player': session.get('player',''),
                        'ip_address': session.get('ip_address','N/A'),
                        'stream_duration': stream_duration,
                        'stream_time': arrow.get(stream_duration * 60).format(duration_format),
                        'remaining_duration': remaining_duration,
                        'remaining_time': arrow.get(remaining_duration * 60).format(duration_format),
                        'progress_duration': view_offset,
                        'progress_time': arrow.get(view_offset * 60).format(duration_format),
                        'progress_percent': progress_percent,
                        'container': session.get('container',''),
                        'video_codec': session.get('video_codec',''),
                        'video_bitrate': session.get('bitrate',''),
                        'video_width': session.get('width',''),
                        'video_height': session.get('height',''),
                        'video_resolution': session.get('video_resolution',''),
                        'video_framerate': session.get('video_framerate',''),
                        'aspect_ratio': session.get('aspect_ratio',''),
                        'audio_codec': session.get('audio_codec',''),
                        'audio_channels': session.get('audio_channels',''),
                        'transcode_decision': transcode_decision,
                        'video_decision': session.get('video_decision','').title(),
                        'audio_decision': session.get('audio_decision','').title(),
                        'transcode_container': session.get('transcode_container',''),
                        'transcode_video_codec': session.get('transcode_video_codec',''),
                        'transcode_video_width': session.get('transcode_width',''),
                        'transcode_video_height': session.get('transcode_height',''),
                        'transcode_audio_codec': session.get('transcode_audio_codec',''),
                        'transcode_audio_channels': session.get('transcode_audio_channels',''),
                        'session_key': session.get('session_key',''),
                        'user_id': session.get('user_id',''),
                        'machine_id': session.get('machine_id',''),
                        # Metadata parameters
                        'media_type': metadata['media_type'],
                        'title': full_title,
                        'library_name': metadata['library_name'],
                        'show_name': show_name,
                        'episode_name': episode_name,
                        'artist_name': artist_name,
                        'album_name': album_name,
                        'track_name': track_name,
                        'season_num': metadata['parent_media_index'].zfill(1),
                        'season_num00': metadata['parent_media_index'].zfill(2),
                        'episode_num': metadata['media_index'].zfill(1),
                        'episode_num00': metadata['media_index'].zfill(2),
                        'track_num': metadata['media_index'].zfill(1),
                        'track_num00': metadata['media_index'].zfill(2),
                        'year': metadata['year'],
                        'studio': metadata['studio'],
                        'content_rating': metadata['content_rating'],
                        'directors': ', '.join(metadata['directors']),
                        'writers': ', '.join(metadata['writers']),
                        'actors': ', '.join(metadata['actors']),
                        'genres': ', '.join(metadata['genres']),
                        'summary': metadata['summary'],
                        'tagline': metadata['tagline'],
                        'rating': metadata['rating'],
                        'duration': duration,
                        'poster_url': metadata.get('poster_url',''),
                        'imdb_id': metadata.get('imdb_id',''),
                        'imdb_url': metadata.get('imdb_url',''),
                        'thetvdb_id': metadata.get('thetvdb_id',''),
                        'thetvdb_url': metadata.get('thetvdb_url',''),
                        'themoviedb_id': metadata.get('themoviedb_id',''),
                        'themoviedb_url': metadata.get('themoviedb_url',''),
                        'lastfm_url': metadata.get('lastfm_url',''),
                        'trakt_url': metadata.get('trakt_url',''),
                        'section_id': metadata['section_id'],
                        'rating_key': metadata['rating_key'],
                        'parent_rating_key': metadata['parent_rating_key'],
                        'grandparent_rating_key': metadata['grandparent_rating_key']
                        }

    # Default subject text
    subject_text = 'PlexPy (%s)' % server_name

    # Default scripts args
    script_args = []

    if script_args_text:
        try:
            script_args = [unicode(arg).format(**available_params) for arg in script_args_text.split()]
        except LookupError as e:
            logger.error(u"PlexPy Notifier :: Unable to parse field %s in script argument. Using fallback." % e)
        except Exception as e:
            logger.error(u"PlexPy Notifier :: Unable to parse custom script arguments %s. Using fallback." % e)

    if state == 'play':
        # Default body text
        body_text = '%s (%s) started playing %s' % (session['friendly_name'],
                                                    session['player'],
                                                    full_title)

        if on_start_subject and on_start_body:
            try:
                subject_text = unicode(on_start_subject).format(**available_params)
            except LookupError, e:
                logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification subject. Using fallback." % e)
            except:
Beispiel #14
0
    def get_synced_items(self,
                         machine_id=None,
                         client_id_filter=None,
                         user_id_filter=None,
                         rating_key_filter=None,
                         sync_id_filter=None,
                         server_id_filter=None):

        if isinstance(rating_key_filter, list):
            rating_key_filter = [str(k) for k in rating_key_filter]
        elif rating_key_filter:
            rating_key_filter = [str(rating_key_filter)]

        if isinstance(user_id_filter, list):
            user_id_filter = [str(k) for k in user_id_filter]
        elif user_id_filter:
            user_id_filter = [str(user_id_filter)]

        user_data = users.Users()

        synced_items = []

        for server in plexpy.PMS_SERVERS:
            if server_id_filter and int(server_id_filter) != server.CONFIG.ID:
                continue
            if not session.allow_session_server(server.CONFIG.ID):
                continue

            machine_id = server.CONFIG.PMS_IDENTIFIER
            sync_list = self.get_plextv_sync_lists(machine_id,
                                                   output_format='xml')

            try:
                xml_head = sync_list.getElementsByTagName('SyncList')
            except Exception as e:
                logger.warn(
                    u"Tautulli PlexTV :: Unable to parse XML for get_synced_items: %s."
                    % e)
                return {}

            for a in xml_head:
                client_id = helpers.get_xml_attr(a, 'clientIdentifier')

                # Filter by client_id
                if client_id_filter and str(client_id_filter) != client_id:
                    continue

                sync_list_id = helpers.get_xml_attr(a, 'id')
                sync_device = a.getElementsByTagName('Device')

                for device in sync_device:
                    device_user_id = helpers.get_xml_attr(device, 'userID')
                    try:
                        device_username = user_data.get_details(
                            user_id=device_user_id)['username']
                        device_friendly_name = user_data.get_details(
                            user_id=device_user_id)['friendly_name']
                    except:
                        device_username = ''
                        device_friendly_name = ''
                    device_name = helpers.get_xml_attr(device, 'name')
                    device_product = helpers.get_xml_attr(device, 'product')
                    device_product_version = helpers.get_xml_attr(
                        device, 'productVersion')
                    device_platform = helpers.get_xml_attr(device, 'platform')
                    device_platform_version = helpers.get_xml_attr(
                        device, 'platformVersion')
                    device_type = helpers.get_xml_attr(device, 'device')
                    device_model = helpers.get_xml_attr(device, 'model')
                    device_last_seen = helpers.get_xml_attr(
                        device, 'lastSeenAt')

                # Filter by user_id
                if user_id_filter and device_user_id not in user_id_filter:
                    continue

                for synced in a.getElementsByTagName('SyncItems'):
                    sync_item = synced.getElementsByTagName('SyncItem')
                    for item in sync_item:

                        for location in item.getElementsByTagName('Location'):
                            clean_uri = helpers.get_xml_attr(
                                location, 'uri').split('%2F')

                        rating_key = next(
                            (clean_uri[(idx + 1) % len(clean_uri)]
                             for idx, item in enumerate(clean_uri)
                             if item == 'metadata'), None)

                        # Filter by rating_key
                        if rating_key_filter and rating_key not in rating_key_filter:
                            continue

                        sync_id = helpers.get_xml_attr(item, 'id')

                        # Filter by sync_id
                        if sync_id_filter and str(sync_id_filter) != sync_id:
                            continue

                        sync_version = helpers.get_xml_attr(item, 'version')
                        sync_root_title = helpers.get_xml_attr(
                            item, 'rootTitle')
                        sync_title = helpers.get_xml_attr(item, 'title')
                        sync_metadata_type = helpers.get_xml_attr(
                            item, 'metadataType')
                        sync_content_type = helpers.get_xml_attr(
                            item, 'contentType')

                        for status in item.getElementsByTagName('Status'):
                            status_failure_code = helpers.get_xml_attr(
                                status, 'failureCode')
                            status_failure = helpers.get_xml_attr(
                                status, 'failure')
                            status_state = helpers.get_xml_attr(
                                status, 'state')
                            status_item_count = helpers.get_xml_attr(
                                status, 'itemsCount')
                            status_item_complete_count = helpers.get_xml_attr(
                                status, 'itemsCompleteCount')
                            status_item_downloaded_count = helpers.get_xml_attr(
                                status, 'itemsDownloadedCount')
                            status_item_ready_count = helpers.get_xml_attr(
                                status, 'itemsReadyCount')
                            status_item_successful_count = helpers.get_xml_attr(
                                status, 'itemsSuccessfulCount')
                            status_total_size = helpers.get_xml_attr(
                                status, 'totalSize')
                            status_item_download_percent_complete = helpers.get_percent(
                                status_item_downloaded_count,
                                status_item_count)

                        for settings in item.getElementsByTagName(
                                'MediaSettings'):
                            settings_video_bitrate = helpers.get_xml_attr(
                                settings, 'maxVideoBitrate')
                            settings_video_quality = helpers.get_xml_attr(
                                settings, 'videoQuality')
                            settings_video_resolution = helpers.get_xml_attr(
                                settings, 'videoResolution')
                            settings_audio_boost = helpers.get_xml_attr(
                                settings, 'audioBoost')
                            settings_audio_bitrate = helpers.get_xml_attr(
                                settings, 'musicBitrate')
                            settings_photo_quality = helpers.get_xml_attr(
                                settings, 'photoQuality')
                            settings_photo_resolution = helpers.get_xml_attr(
                                settings, 'photoResolution')

                        sync_details = {
                            "device_name": helpers.sanitize(device_name),
                            "server_id": server.CONFIG.ID,
                            "server_name": server.CONFIG.PMS_NAME,
                            "platform": helpers.sanitize(device_platform),
                            "user_id": device_user_id,
                            "user": helpers.sanitize(device_friendly_name),
                            "username": helpers.sanitize(device_username),
                            "root_title": helpers.sanitize(sync_root_title),
                            "sync_title": helpers.sanitize(sync_title),
                            "metadata_type": sync_metadata_type,
                            "content_type": sync_content_type,
                            "rating_key": rating_key,
                            "state": status_state,
                            "item_count": status_item_count,
                            "item_complete_count": status_item_complete_count,
                            "item_downloaded_count":
                            status_item_downloaded_count,
                            "item_downloaded_percent_complete":
                            status_item_download_percent_complete,
                            "video_bitrate": settings_video_bitrate,
                            "audio_bitrate": settings_audio_bitrate,
                            "photo_quality": settings_photo_quality,
                            "video_quality": settings_video_quality,
                            "total_size": status_total_size,
                            "failure": status_failure,
                            "client_id": client_id,
                            "sync_id": sync_id
                        }

                        synced_items.append(sync_details)

        return session.filter_session_info(synced_items, filter_key='user_id')
Beispiel #15
0
    def get_session_each(self, stream_type='', session=None):
        session_output = None
        plex_watch = plexwatch.PlexWatch()
        if stream_type == 'track':
            if session.getElementsByTagName('TranscodeSession'):
                transcode_session = session.getElementsByTagName('TranscodeSession')[0]
                audio_decision = helpers.get_xml_attr(transcode_session, 'audioDecision')
                audio_channels = helpers.get_xml_attr(transcode_session, 'audioChannels')
                audio_codec = helpers.get_xml_attr(transcode_session, 'audioCodec')
                duration = helpers.get_xml_attr(transcode_session, 'duration')
                progress = helpers.get_xml_attr(session, 'viewOffset')
            else:
                media_info = session.getElementsByTagName('Media')[0]
                audio_decision = 'direct play'
                audio_channels = helpers.get_xml_attr(media_info, 'audioChannels')
                audio_codec = helpers.get_xml_attr(media_info, 'audioCodec')
                duration = helpers.get_xml_attr(media_info, 'duration')
                progress = helpers.get_xml_attr(session, 'viewOffset')

            session_output = {'session_key': helpers.get_xml_attr(session, 'sessionKey'),
                              'art': helpers.get_xml_attr(session, 'art'),
                              'parent_thumb': helpers.get_xml_attr(session, 'parentThumb'),
                              'thumb': helpers.get_xml_attr(session, 'thumb'),
                              'user': helpers.get_xml_attr(session.getElementsByTagName('User')[0], 'title'),
                              'friendly_name': plex_watch.get_user_friendly_name(
                                  helpers.get_xml_attr(session.getElementsByTagName('User')[0], 'title')),
                              'player': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'platform'),
                              'state': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'state'),
                              'grandparent_title': helpers.get_xml_attr(session, 'grandparentTitle'),
                              'parent_title': helpers.get_xml_attr(session, 'parentTitle'),
                              'title': helpers.get_xml_attr(session, 'title'),
                              'rating_key': helpers.get_xml_attr(session, 'ratingKey'),
                              'audio_decision': audio_decision,
                              'audio_channels': audio_channels,
                              'audio_codec': audio_codec,
                              'video_decision': '',
                              'video_codec': '',
                              'height': '',
                              'width': '',
                              'duration': duration,
                              'progress': progress,
                              'progress_percent': str(helpers.get_percent(progress, duration)),
                              'type': 'track',
                              'indexes': 0
                              }
        elif stream_type == 'video':
            if session.getElementsByTagName('TranscodeSession'):
                transcode_session = session.getElementsByTagName('TranscodeSession')[0]
                audio_decision = helpers.get_xml_attr(transcode_session, 'audioDecision')
                audio_channels = helpers.get_xml_attr(transcode_session, 'audioChannels')
                audio_codec = helpers.get_xml_attr(transcode_session, 'audioCodec')
                video_decision = helpers.get_xml_attr(transcode_session, 'videoDecision')
                video_codec = helpers.get_xml_attr(transcode_session, 'videoCodec')
                width = helpers.get_xml_attr(transcode_session, 'width')
                height = helpers.get_xml_attr(transcode_session, 'height')
                duration = helpers.get_xml_attr(session, 'duration')
                progress = helpers.get_xml_attr(session, 'viewOffset')
            else:
                media_info = session.getElementsByTagName('Media')[0]
                audio_decision = 'direct play'
                audio_channels = helpers.get_xml_attr(media_info, 'audioChannels')
                audio_codec = helpers.get_xml_attr(media_info, 'audioCodec')
                video_decision = 'direct play'
                video_codec = helpers.get_xml_attr(media_info, 'videoCodec')
                width = helpers.get_xml_attr(media_info, 'width')
                height = helpers.get_xml_attr(media_info, 'height')
                duration = helpers.get_xml_attr(media_info, 'duration')
                progress = helpers.get_xml_attr(session, 'viewOffset')

            media_info = session.getElementsByTagName('Media')[0]
            if media_info.getElementsByTagName('Part'):
                indexes = helpers.get_xml_attr(media_info.getElementsByTagName('Part')[0], 'indexes')
                part_id = helpers.get_xml_attr(media_info.getElementsByTagName('Part')[0], 'id')
                if indexes == 'sd':
                    bif_thumb = '/library/parts/' + part_id + '/indexes/sd/' + progress
                else:
                    bif_thumb = ''
            else:
                indexes = ''
                bif_thumb = ''

            if plexpy.CONFIG.PMS_USE_BIF and indexes == 'sd':
                thumb = bif_thumb
                use_indexes = 1
            else:
                thumb = helpers.get_xml_attr(session, 'thumb')
                use_indexes = 0

            if helpers.get_xml_attr(session, 'type') == 'episode':
                session_output = {'session_key': helpers.get_xml_attr(session, 'sessionKey'),
                                  'art': helpers.get_xml_attr(session, 'art'),
                                  'parent_thumb': helpers.get_xml_attr(session, 'parentThumb'),
                                  'thumb': thumb,
                                  'user': helpers.get_xml_attr(session.getElementsByTagName('User')[0], 'title'),
                                  'friendly_name': plex_watch.get_user_friendly_name(
                                      helpers.get_xml_attr(session.getElementsByTagName('User')[0], 'title')),
                                  'player': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'platform'),
                                  'state': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'state'),
                                  'grandparent_title': helpers.get_xml_attr(session, 'grandparentTitle'),
                                  'parent_title': helpers.get_xml_attr(session, 'parentTitle'),
                                  'title': helpers.get_xml_attr(session, 'title'),
                                  'rating_key': helpers.get_xml_attr(session, 'ratingKey'),
                                  'audio_decision': audio_decision,
                                  'audio_channels': audio_channels,
                                  'audio_codec': audio_codec,
                                  'video_decision': video_decision,
                                  'video_codec': video_codec,
                                  'height': height,
                                  'width': width,
                                  'duration': duration,
                                  'progress': progress,
                                  'progress_percent': str(helpers.get_percent(progress, duration)),
                                  'type': helpers.get_xml_attr(session, 'type'),
                                  'indexes': use_indexes
                                  }
            elif helpers.get_xml_attr(session, 'type') == 'movie':
                session_output = {'session_key': helpers.get_xml_attr(session, 'sessionKey'),
                                  'art': helpers.get_xml_attr(session, 'art'),
                                  'thumb': thumb,
                                  'parent_thumb': helpers.get_xml_attr(session, 'parentThumb'),
                                  'user': helpers.get_xml_attr(session.getElementsByTagName('User')[0], 'title'),
                                  'friendly_name': plex_watch.get_user_friendly_name(
                                      helpers.get_xml_attr(session.getElementsByTagName('User')[0], 'title')),
                                  'player': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'platform'),
                                  'state': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'state'),
                                  'grandparent_title': helpers.get_xml_attr(session, 'grandparentTitle'),
                                  'parent_title': helpers.get_xml_attr(session, 'parentTitle'),
                                  'title': helpers.get_xml_attr(session, 'title'),
                                  'rating_key': helpers.get_xml_attr(session, 'ratingKey'),
                                  'audio_decision': audio_decision,
                                  'audio_channels': audio_channels,
                                  'audio_codec': audio_codec,
                                  'video_decision': video_decision,
                                  'video_codec': video_codec,
                                  'height': height,
                                  'width': width,
                                  'duration': duration,
                                  'progress': progress,
                                  'progress_percent': str(helpers.get_percent(progress, duration)),
                                  'type': helpers.get_xml_attr(session, 'type'),
                                  'indexes': use_indexes
                                  }
            elif helpers.get_xml_attr(session, 'type') == 'clip':
                session_output = {'session_key': helpers.get_xml_attr(session, 'sessionKey'),
                                  'art': helpers.get_xml_attr(session, 'art'),
                                  'thumb': thumb,
                                  'parent_thumb': helpers.get_xml_attr(session, 'parentThumb'),
                                  'user': helpers.get_xml_attr(session.getElementsByTagName('User')[0], 'title'),
                                  'friendly_name': plex_watch.get_user_friendly_name(
                                      helpers.get_xml_attr(session.getElementsByTagName('User')[0], 'title')),
                                  'player': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'platform'),
                                  'state': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'state'),
                                  'grandparent_title': helpers.get_xml_attr(session, 'grandparentTitle'),
                                  'parent_title': helpers.get_xml_attr(session, 'parentTitle'),
                                  'title': helpers.get_xml_attr(session, 'title'),
                                  'rating_key': helpers.get_xml_attr(session, 'ratingKey'),
                                  'audio_decision': audio_decision,
                                  'audio_channels': audio_channels,
                                  'audio_codec': audio_codec,
                                  'video_decision': video_decision,
                                  'video_codec': video_codec,
                                  'height': height,
                                  'width': width,
                                  'duration': duration,
                                  'progress': progress,
                                  'progress_percent': str(helpers.get_percent(progress, duration)),
                                  'type': helpers.get_xml_attr(session, 'type'),
                                  'indexes': 0
                                  }
        else:
            logger.warn(u"No known stream types found in session list.")

        return session_output
Beispiel #16
0
    def get_session_each(self, stream_type='', session=None):
        session_output = None
        if stream_type == 'track':
            if session.getElementsByTagName('TranscodeSession'):
                transcode_session = session.getElementsByTagName('TranscodeSession')[0]
                audio_decision = self.get_xml_attr(transcode_session, 'audioDecision')
                audio_channels = self.get_xml_attr(transcode_session, 'audioChannels')
                audio_codec = self.get_xml_attr(transcode_session, 'audioCodec')
                duration = self.get_xml_attr(transcode_session, 'duration')
                progress = self.get_xml_attr(session, 'viewOffset')
            else:
                media_info = session.getElementsByTagName('Media')[0]
                audio_decision = 'direct play'
                audio_channels = self.get_xml_attr(media_info, 'audioChannels')
                audio_codec = self.get_xml_attr(media_info, 'audioCodec')
                duration = self.get_xml_attr(media_info, 'duration')
                progress = self.get_xml_attr(session, 'viewOffset')

            session_output = {'sessionKey': self.get_xml_attr(session, 'sessionKey'),
                              'parentThumb': self.get_xml_attr(session, 'parentThumb'),
                              'thumb': self.get_xml_attr(session, 'thumb'),
                              'user': self.get_xml_attr(session.getElementsByTagName('User')[0], 'title'),
                              'player': self.get_xml_attr(session.getElementsByTagName('Player')[0], 'platform'),
                              'state': self.get_xml_attr(session.getElementsByTagName('Player')[0], 'state'),
                              'artist': self.get_xml_attr(session, 'grandparentTitle'),
                              'album': self.get_xml_attr(session, 'parentTitle'),
                              'track': self.get_xml_attr(session, 'title'),
                              'ratingKey': self.get_xml_attr(session, 'ratingKey'),
                              'audioDecision': audio_decision,
                              'audioChannels': audio_channels,
                              'audioCodec': audio_codec,
                              'duration': duration,
                              'progress': progress,
                              'progressPercent': str(helpers.get_percent(progress, duration)),
                              'type': 'track'
                              }
        elif stream_type == 'video':
            if session.getElementsByTagName('TranscodeSession'):
                transcode_session = session.getElementsByTagName('TranscodeSession')[0]
                audio_decision = self.get_xml_attr(transcode_session, 'audioDecision')
                audio_channels = self.get_xml_attr(transcode_session, 'audioChannels')
                audio_codec = self.get_xml_attr(transcode_session, 'audioCodec')
                video_decision = self.get_xml_attr(transcode_session, 'videoDecision')
                video_codec = self.get_xml_attr(transcode_session, 'videoCodec')
                width = self.get_xml_attr(transcode_session, 'width')
                height = self.get_xml_attr(transcode_session, 'height')
                duration = self.get_xml_attr(session, 'duration')
                progress = self.get_xml_attr(session, 'viewOffset')
            else:
                media_info = session.getElementsByTagName('Media')[0]
                audio_decision = 'direct play'
                audio_channels = self.get_xml_attr(media_info, 'audioChannels')
                audio_codec = self.get_xml_attr(media_info, 'audioCodec')
                video_decision = 'direct play'
                video_codec = self.get_xml_attr(media_info, 'videoCodec')
                width = self.get_xml_attr(media_info, 'width')
                height = self.get_xml_attr(media_info, 'height')
                duration = self.get_xml_attr(media_info, 'duration')
                progress = self.get_xml_attr(session, 'viewOffset')

            if self.get_xml_attr(session, 'type') == 'episode':
                session_output = {'sessionKey': self.get_xml_attr(session, 'sessionKey'),
                                  'art': self.get_xml_attr(session, 'art'),
                                  'thumb': self.get_xml_attr(session, 'thumb'),
                                  'user': self.get_xml_attr(session.getElementsByTagName('User')[0], 'title'),
                                  'player': self.get_xml_attr(session.getElementsByTagName('Player')[0], 'platform'),
                                  'state': self.get_xml_attr(session.getElementsByTagName('Player')[0], 'state'),
                                  'grandparentTitle': self.get_xml_attr(session, 'grandparentTitle'),
                                  'title': self.get_xml_attr(session, 'title'),
                                  'ratingKey': self.get_xml_attr(session, 'ratingKey'),
                                  'audioDecision': audio_decision,
                                  'audioChannels': audio_channels,
                                  'audioCodec': audio_codec,
                                  'videoDecision': video_decision,
                                  'videoCodec': video_codec,
                                  'height': height,
                                  'width': width,
                                  'duration': duration,
                                  'progress': progress,
                                  'progressPercent': str(helpers.get_percent(progress, duration)),
                                  'type': self.get_xml_attr(session, 'type')
                                  }
            elif self.get_xml_attr(session, 'type') == 'movie':
                session_output = {'sessionKey': self.get_xml_attr(session, 'sessionKey'),
                                  'art': self.get_xml_attr(session, 'art'),
                                  'thumb': self.get_xml_attr(session, 'thumb'),
                                  'user': self.get_xml_attr(session.getElementsByTagName('User')[0], 'title'),
                                  'player': self.get_xml_attr(session.getElementsByTagName('Player')[0], 'platform'),
                                  'state': self.get_xml_attr(session.getElementsByTagName('Player')[0], 'state'),
                                  'title': self.get_xml_attr(session, 'title'),
                                  'ratingKey': self.get_xml_attr(session, 'ratingKey'),
                                  'audioDecision': audio_decision,
                                  'audioChannels': audio_channels,
                                  'audioCodec': audio_codec,
                                  'videoDecision': video_decision,
                                  'videoCodec': video_codec,
                                  'height': height,
                                  'width': width,
                                  'duration': duration,
                                  'progress': progress,
                                  'progressPercent': str(helpers.get_percent(progress, duration)),
                                  'type': self.get_xml_attr(session, 'type')
                                  }
        else:
            logger.warn(u"No known stream types found in session list.")

        return session_output
def build_notify_text(session=None, timeline=None, state=None):
    # Get time formats
    date_format = plexpy.CONFIG.DATE_FORMAT.replace("Do", "").replace("zz", "")
    time_format = plexpy.CONFIG.TIME_FORMAT.replace("Do", "").replace("zz", "")
    duration_format = plexpy.CONFIG.TIME_FORMAT.replace("Do", "").replace("zz", "").replace("a", "").replace("A", "")

    # Get the server name
    server_name = plexpy.CONFIG.PMS_NAME

    # Get the server uptime
    plex_tv = plextv.PlexTV()
    server_times = plex_tv.get_server_times()

    if server_times:
        updated_at = server_times[0]["updated_at"]
        server_uptime = helpers.human_duration(int(time.time() - helpers.cast_to_float(updated_at)))
    else:
        logger.error(u"PlexPy NotificationHandler :: Unable to retrieve server uptime.")
        server_uptime = "N/A"

    # Get metadata feed for item
    if session:
        rating_key = session["rating_key"]
    elif timeline:
        rating_key = timeline["rating_key"]

    pms_connect = pmsconnect.PmsConnect()
    metadata_list = pms_connect.get_metadata_details(rating_key=rating_key)

    stream_count = pms_connect.get_current_activity().get("stream_count", "")

    if metadata_list:
        metadata = metadata_list["metadata"]
    else:
        logger.error(u"PlexPy NotificationHandler :: Unable to retrieve metadata for rating_key %s" % str(rating_key))
        return []

    # Check for exclusion tags
    if metadata["media_type"] == "movie":
        # Regex pattern to remove the text in the tags we don't want
        pattern = re.compile("\n*<tv>[^>]+.</tv>\n*|\n*<music>[^>]+.</music>\n*", re.IGNORECASE | re.DOTALL)
    elif metadata["media_type"] == "show" or metadata["media_type"] == "episode":
        # Regex pattern to remove the text in the tags we don't want
        pattern = re.compile("\n*<movie>[^>]+.</movie>\n*|\n*?<music>[^>]+.</music>\n*", re.IGNORECASE | re.DOTALL)
    elif metadata["media_type"] == "artist" or metadata["media_type"] == "track":
        # Regex pattern to remove the text in the tags we don't want
        pattern = re.compile("\n*<tv>[^>]+.</tv>\n*|\n*<movie>[^>]+.</movie>\n*", re.IGNORECASE | re.DOTALL)
    else:
        pattern = None

    if (
        metadata["media_type"] == "movie"
        or metadata["media_type"] == "show"
        or metadata["media_type"] == "episode"
        or metadata["media_type"] == "artist"
        or metadata["media_type"] == "track"
        and pattern
    ):
        # Remove the unwanted tags and strip any unmatch tags too.
        on_start_subject = strip_tag(re.sub(pattern, "", plexpy.CONFIG.NOTIFY_ON_START_SUBJECT_TEXT))
        on_start_body = strip_tag(re.sub(pattern, "", plexpy.CONFIG.NOTIFY_ON_START_BODY_TEXT))
        on_stop_subject = strip_tag(re.sub(pattern, "", plexpy.CONFIG.NOTIFY_ON_STOP_SUBJECT_TEXT))
        on_stop_body = strip_tag(re.sub(pattern, "", plexpy.CONFIG.NOTIFY_ON_STOP_BODY_TEXT))
        on_pause_subject = strip_tag(re.sub(pattern, "", plexpy.CONFIG.NOTIFY_ON_PAUSE_SUBJECT_TEXT))
        on_pause_body = strip_tag(re.sub(pattern, "", plexpy.CONFIG.NOTIFY_ON_PAUSE_BODY_TEXT))
        on_resume_subject = strip_tag(re.sub(pattern, "", plexpy.CONFIG.NOTIFY_ON_RESUME_SUBJECT_TEXT))
        on_resume_body = strip_tag(re.sub(pattern, "", plexpy.CONFIG.NOTIFY_ON_RESUME_BODY_TEXT))
        on_buffer_subject = strip_tag(re.sub(pattern, "", plexpy.CONFIG.NOTIFY_ON_BUFFER_SUBJECT_TEXT))
        on_buffer_body = strip_tag(re.sub(pattern, "", plexpy.CONFIG.NOTIFY_ON_BUFFER_BODY_TEXT))
        on_watched_subject = strip_tag(re.sub(pattern, "", plexpy.CONFIG.NOTIFY_ON_WATCHED_SUBJECT_TEXT))
        on_watched_body = strip_tag(re.sub(pattern, "", plexpy.CONFIG.NOTIFY_ON_WATCHED_BODY_TEXT))
        on_created_subject = strip_tag(re.sub(pattern, "", plexpy.CONFIG.NOTIFY_ON_CREATED_SUBJECT_TEXT))
        on_created_body = strip_tag(re.sub(pattern, "", plexpy.CONFIG.NOTIFY_ON_CREATED_BODY_TEXT))
        script_args_text = strip_tag(re.sub(pattern, "", plexpy.CONFIG.NOTIFY_SCRIPTS_ARGS_TEXT))
    else:
        on_start_subject = plexpy.CONFIG.NOTIFY_ON_START_SUBJECT_TEXT
        on_start_body = plexpy.CONFIG.NOTIFY_ON_START_BODY_TEXT
        on_stop_subject = plexpy.CONFIG.NOTIFY_ON_STOP_SUBJECT_TEXT
        on_stop_body = plexpy.CONFIG.NOTIFY_ON_STOP_BODY_TEXT
        on_pause_subject = plexpy.CONFIG.NOTIFY_ON_PAUSE_SUBJECT_TEXT
        on_pause_body = plexpy.CONFIG.NOTIFY_ON_PAUSE_BODY_TEXT
        on_resume_subject = plexpy.CONFIG.NOTIFY_ON_RESUME_SUBJECT_TEXT
        on_resume_body = plexpy.CONFIG.NOTIFY_ON_RESUME_BODY_TEXT
        on_buffer_subject = plexpy.CONFIG.NOTIFY_ON_BUFFER_SUBJECT_TEXT
        on_buffer_body = plexpy.CONFIG.NOTIFY_ON_BUFFER_BODY_TEXT
        on_watched_subject = plexpy.CONFIG.NOTIFY_ON_WATCHED_SUBJECT_TEXT
        on_watched_body = plexpy.CONFIG.NOTIFY_ON_WATCHED_BODY_TEXT
        on_created_subject = plexpy.CONFIG.NOTIFY_ON_CREATED_SUBJECT_TEXT
        on_created_body = plexpy.CONFIG.NOTIFY_ON_CREATED_BODY_TEXT
        script_args_text = plexpy.CONFIG.NOTIFY_SCRIPTS_ARGS_TEXT

    # Create a title
    if metadata["media_type"] == "episode" or metadata["media_type"] == "track":
        full_title = "%s - %s" % (metadata["grandparent_title"], metadata["title"])
    else:
        full_title = metadata["title"]

    # Session values
    if session is None:
        session = {}

    # Generate a combined transcode decision value
    if session.get("video_decision", "") == "transcode" or session.get("audio_decision", "") == "transcode":
        transcode_decision = "Transcode"
    elif session.get("video_decision", "") == "copy" or session.get("audio_decision", "") == "copy":
        transcode_decision = "Direct Stream"
    else:
        transcode_decision = "Direct Play"

    if state != "play":
        stream_duration = helpers.convert_seconds_to_minutes(
            time.time()
            - helpers.cast_to_float(session.get("started", 0))
            - helpers.cast_to_float(session.get("paused_counter", 0))
        )
    else:
        stream_duration = 0

    view_offset = helpers.convert_milliseconds_to_minutes(session.get("view_offset", 0))
    duration = helpers.convert_milliseconds_to_minutes(metadata["duration"])
    progress_percent = helpers.get_percent(view_offset, duration)
    remaining_duration = duration - view_offset

    # Fix metadata params for notify recently added grandparent
    if state == "created" and plexpy.CONFIG.NOTIFY_RECENTLY_ADDED_GRANDPARENT:
        show_name = metadata["title"]
        episode_name = ""
        artist_name = metadata["title"]
        album_name = ""
        track_name = ""
    else:
        show_name = metadata["grandparent_title"]
        episode_name = metadata["title"]
        artist_name = metadata["grandparent_title"]
        album_name = metadata["parent_title"]
        track_name = metadata["title"]

    available_params = {  # Global paramaters
        "server_name": server_name,
        "server_uptime": server_uptime,
        "action": state.title(),
        "datestamp": arrow.now().format(date_format),
        "timestamp": arrow.now().format(time_format),
        # Stream parameters
        "streams": stream_count,
        "user": session.get("friendly_name", ""),
        "platform": session.get("platform", ""),
        "player": session.get("player", ""),
        "ip_address": session.get("ip_address", "N/A"),
        "stream_duration": stream_duration,
        "stream_time": arrow.get(stream_duration * 60).format(duration_format),
        "remaining_duration": remaining_duration,
        "remaining_time": arrow.get(remaining_duration * 60).format(duration_format),
        "progress_duration": view_offset,
        "progress_time": arrow.get(view_offset * 60).format(duration_format),
        "progress_percent": progress_percent,
        "container": session.get("container", ""),
        "video_codec": session.get("video_codec", ""),
        "video_bitrate": session.get("bitrate", ""),
        "video_width": session.get("width", ""),
        "video_height": session.get("height", ""),
        "video_resolution": session.get("video_resolution", ""),
        "video_framerate": session.get("video_framerate", ""),
        "aspect_ratio": session.get("aspect_ratio", ""),
        "audio_codec": session.get("audio_codec", ""),
        "audio_channels": session.get("audio_channels", ""),
        "transcode_decision": transcode_decision,
        "video_decision": session.get("video_decision", "").title(),
        "audio_decision": session.get("audio_decision", "").title(),
        "transcode_container": session.get("transcode_container", ""),
        "transcode_video_codec": session.get("transcode_video_codec", ""),
        "transcode_video_width": session.get("transcode_width", ""),
        "transcode_video_height": session.get("transcode_height", ""),
        "transcode_audio_codec": session.get("transcode_audio_codec", ""),
        "transcode_audio_channels": session.get("transcode_audio_channels", ""),
        "session_key": session.get("session_key", ""),
        "user_id": session.get("user_id", ""),
        # Metadata parameters
        "media_type": metadata["media_type"],
        "title": full_title,
        "library_name": metadata["library_name"],
        "show_name": show_name,
        "episode_name": episode_name,
        "artist_name": artist_name,
        "album_name": album_name,
        "track_name": track_name,
        "season_num": metadata["parent_media_index"].zfill(1),
        "season_num00": metadata["parent_media_index"].zfill(2),
        "episode_num": metadata["media_index"].zfill(1),
        "episode_num00": metadata["media_index"].zfill(2),
        "track_num": metadata["media_index"].zfill(1),
        "track_num00": metadata["media_index"].zfill(2),
        "year": metadata["year"],
        "studio": metadata["studio"],
        "content_rating": metadata["content_rating"],
        "directors": ", ".join(metadata["directors"]),
        "writers": ", ".join(metadata["writers"]),
        "actors": ", ".join(metadata["actors"]),
        "genres": ", ".join(metadata["genres"]),
        "summary": metadata["summary"],
        "tagline": metadata["tagline"],
        "rating": metadata["rating"],
        "duration": metadata["duration"],
        "section_id": metadata["section_id"],
        "rating_key": metadata["rating_key"],
        "parent_rating_key": metadata["parent_rating_key"],
        "grandparent_rating_key": metadata["grandparent_rating_key"],
    }

    # Default subject text
    subject_text = "PlexPy (%s)" % server_name

    # Default scripts args
    script_args = []

    if script_args_text:
        try:
            script_args = [unicode(arg).format(**available_params) for arg in script_args_text.split()]
        except LookupError as e:
            logger.error(u"PlexPy Notifier :: Unable to parse field %s in script argument. Using fallback." % e)
        except Exception as e:
            logger.error(u"PlexPy Notifier :: Unable to parse custom script arguments %s. Using fallback." % e)

    if state == "play":
        # Default body text
        body_text = "%s (%s) started playing %s" % (session["friendly_name"], session["player"], full_title)

        if on_start_subject and on_start_body:
            try:
                subject_text = unicode(on_start_subject).format(**available_params)
            except LookupError, e:
                logger.error(
                    u"PlexPy NotificationHandler :: Unable to parse field %s in notification subject. Using fallback."
                    % e
                )
            except:
Beispiel #18
0
def build_notify_text(session=None, timeline=None, state=None):
    import re

    # Get the server name
    server_name = plexpy.CONFIG.PMS_NAME

    # Get the server uptime
    plex_tv = plextv.PlexTV()
    server_times = plex_tv.get_server_times()

    if server_times:
        updated_at = server_times[0]['updated_at']
        server_uptime = helpers.human_duration(
            int(time.time() - helpers.cast_to_float(updated_at)))
    else:
        logger.error(u"PlexPy Notifier :: Unable to retrieve server uptime.")
        server_uptime = 'N/A'

    # Get metadata feed for item
    if session:
        rating_key = session['rating_key']
    elif timeline:
        rating_key = timeline['rating_key']

    pms_connect = pmsconnect.PmsConnect()
    metadata_list = pms_connect.get_metadata_details(rating_key=rating_key)

    if metadata_list:
        metadata = metadata_list['metadata']
    else:
        logger.error(
            u"PlexPy Notifier :: Unable to retrieve metadata for rating_key %s"
            % str(rating_key))
        return []

    # Check for exclusion tags
    if metadata['media_type'] == 'movie':
        # Regex pattern to remove the text in the tags we don't want
        pattern = re.compile('<tv>[^>]+.</tv>|<music>[^>]+.</music>',
                             re.IGNORECASE)
    elif metadata['media_type'] == 'show' or metadata[
            'media_type'] == 'episode':
        # Regex pattern to remove the text in the tags we don't want
        pattern = re.compile('<movie>[^>]+.</movie>|<music>[^>]+.</music>',
                             re.IGNORECASE)
    elif metadata['media_type'] == 'artist' or metadata[
            'media_type'] == 'track':
        # Regex pattern to remove the text in the tags we don't want
        pattern = re.compile('<tv>[^>]+.</tv>|<movie>[^>]+.</movie>',
                             re.IGNORECASE)
    else:
        pattern = None

    if metadata['media_type'] == 'movie' \
        or metadata['media_type'] == 'show' or metadata['media_type'] == 'episode' \
        or metadata['media_type'] == 'artist' or metadata['media_type'] == 'track' \
        and pattern:
        # Remove the unwanted tags and strip any unmatch tags too.
        on_start_subject = strip_tag(
            re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_START_SUBJECT_TEXT))
        on_start_body = strip_tag(
            re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_START_BODY_TEXT))
        on_stop_subject = strip_tag(
            re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_STOP_SUBJECT_TEXT))
        on_stop_body = strip_tag(
            re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_STOP_BODY_TEXT))
        on_pause_subject = strip_tag(
            re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_PAUSE_SUBJECT_TEXT))
        on_pause_body = strip_tag(
            re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_PAUSE_BODY_TEXT))
        on_resume_subject = strip_tag(
            re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_RESUME_SUBJECT_TEXT))
        on_resume_body = strip_tag(
            re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_RESUME_BODY_TEXT))
        on_buffer_subject = strip_tag(
            re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_BUFFER_SUBJECT_TEXT))
        on_buffer_body = strip_tag(
            re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_BUFFER_BODY_TEXT))
        on_watched_subject = strip_tag(
            re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_WATCHED_SUBJECT_TEXT))
        on_watched_body = strip_tag(
            re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_WATCHED_BODY_TEXT))
        on_created_subject = strip_tag(
            re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_CREATED_SUBJECT_TEXT))
        on_created_body = strip_tag(
            re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_CREATED_BODY_TEXT))
    else:
        on_start_subject = plexpy.CONFIG.NOTIFY_ON_START_SUBJECT_TEXT
        on_start_body = plexpy.CONFIG.NOTIFY_ON_START_BODY_TEXT
        on_stop_subject = plexpy.CONFIG.NOTIFY_ON_STOP_SUBJECT_TEXT
        on_stop_body = plexpy.CONFIG.NOTIFY_ON_STOP_BODY_TEXT
        on_pause_subject = plexpy.CONFIG.NOTIFY_ON_PAUSE_SUBJECT_TEXT
        on_pause_body = plexpy.CONFIG.NOTIFY_ON_PAUSE_BODY_TEXT
        on_resume_subject = plexpy.CONFIG.NOTIFY_ON_RESUME_SUBJECT_TEXT
        on_resume_body = plexpy.CONFIG.NOTIFY_ON_RESUME_BODY_TEXT
        on_buffer_subject = plexpy.CONFIG.NOTIFY_ON_BUFFER_SUBJECT_TEXT
        on_buffer_body = plexpy.CONFIG.NOTIFY_ON_BUFFER_BODY_TEXT
        on_watched_subject = plexpy.CONFIG.NOTIFY_ON_WATCHED_SUBJECT_TEXT
        on_watched_body = plexpy.CONFIG.NOTIFY_ON_WATCHED_BODY_TEXT
        on_created_subject = plexpy.CONFIG.NOTIFY_ON_CREATED_SUBJECT_TEXT
        on_created_body = plexpy.CONFIG.NOTIFY_ON_CREATED_BODY_TEXT

    # Create a title
    if metadata['media_type'] == 'episode' or metadata['media_type'] == 'track':
        full_title = '%s - %s' % (metadata['grandparent_title'],
                                  metadata['title'])
    else:
        full_title = metadata['title']

    duration = helpers.convert_milliseconds_to_minutes(metadata['duration'])

    # Default values
    video_decision = ''
    audio_decision = ''
    transcode_decision = ''
    stream_duration = 0
    view_offset = 0
    user = ''
    platform = ''
    player = ''
    ip_address = 'N/A'

    # Session values
    if session:
        # Generate a combined transcode decision value
        video_decision = session['video_decision'].title()
        audio_decision = session['audio_decision'].title()

        if session['video_decision'] == 'transcode' or session[
                'audio_decision'] == 'transcode':
            transcode_decision = 'Transcode'
        elif session['video_decision'] == 'copy' or session[
                'audio_decision'] == 'copy':
            transcode_decision = 'Direct Stream'
        else:
            transcode_decision = 'Direct Play'

        if state != 'play':
            if session['paused_counter']:
                stream_duration = int(
                    (time.time() - helpers.cast_to_float(session['started']) -
                     helpers.cast_to_float(session['paused_counter'])) / 60)
            else:
                stream_duration = int(
                    (time.time() - helpers.cast_to_float(session['started'])) /
                    60)

        view_offset = helpers.convert_milliseconds_to_minutes(
            session['view_offset'])
        user = session['friendly_name']
        platform = session['platform']
        player = session['player']
        ip_address = session['ip_address'] if session['ip_address'] else 'N/A'

    progress_percent = helpers.get_percent(view_offset, duration)

    available_params = {
        'server_name': server_name,
        'server_uptime': server_uptime,
        'user': user,
        'platform': platform,
        'player': player,
        'ip_address': ip_address,
        'media_type': metadata['media_type'],
        'title': full_title,
        'show_name': metadata['grandparent_title'],
        'episode_name': metadata['title'],
        'artist_name': metadata['grandparent_title'],
        'album_name': metadata['parent_title'],
        'track_name': metadata['title'],
        'season_num': metadata['parent_index'].zfill(1),
        'season_num00': metadata['parent_index'].zfill(2),
        'episode_num': metadata['index'].zfill(1),
        'episode_num00': metadata['index'].zfill(2),
        'video_decision': video_decision,
        'audio_decision': audio_decision,
        'transcode_decision': transcode_decision,
        'year': metadata['year'],
        'studio': metadata['studio'],
        'content_rating': metadata['content_rating'],
        'directors': ', '.join(metadata['directors']),
        'writers': ', '.join(metadata['writers']),
        'actors': ', '.join(metadata['actors']),
        'genres': ', '.join(metadata['genres']),
        'summary': metadata['summary'],
        'tagline': metadata['tagline'],
        'rating': metadata['rating'],
        'duration': duration,
        'stream_duration': stream_duration,
        'remaining_duration': duration - view_offset,
        'progress': view_offset,
        'progress_percent': progress_percent
    }

    # Default subject text
    subject_text = 'PlexPy (%s)' % server_name

    if state == 'play':
        # Default body text
        body_text = '%s (%s) is watching %s' % (session['friendly_name'],
                                                session['player'], full_title)

        if on_start_subject and on_start_body:
            try:
                subject_text = unicode(on_start_subject).format(
                    **available_params)
            except LookupError, e:
                logger.error(
                    u"PlexPy Notifier :: Unable to parse field %s in notification subject. Using fallback."
                    % e)
            except:
Beispiel #19
0
def check_active_sessions(ws_request=False):

    with monitor_lock:
        pms_connect = pmsconnect.PmsConnect()
        session_list = pms_connect.get_current_activity()
        monitor_db = database.MonitorDatabase()
        monitor_process = activity_processor.ActivityProcessor()
        # logger.debug(u"PlexPy Monitor :: Checking for active streams.")

        global int_ping_count

        if session_list:
            if int_ping_count >= 3:
                logger.info(
                    u"PlexPy Monitor :: The Plex Media Server is back up.")

                # Check if any notification agents have notifications enabled
                if any(d['on_intup']
                       for d in notifiers.available_notification_agents()):
                    # Fire off notifications
                    threading.Thread(
                        target=notification_handler.notify_timeline,
                        kwargs=dict(notify_action='intup')).start()
            int_ping_count = 0

            media_container = session_list['sessions']

            # Check our temp table for what we must do with the new streams
            db_streams = monitor_db.select('SELECT * FROM sessions')
            for stream in db_streams:
                if any(d['session_key'] == str(stream['session_key'])
                       and d['rating_key'] == str(stream['rating_key'])
                       for d in media_container):
                    # The user's session is still active
                    for session in media_container:
                        if session['session_key'] == str(stream['session_key']) and \
                                session['rating_key'] == str(stream['rating_key']):
                            # The user is still playing the same media item
                            # Here we can check the play states
                            if session['state'] != stream['state']:
                                if session['state'] == 'paused':
                                    logger.debug(
                                        u"PlexPy Monitor :: Session %s has been paused."
                                        % stream['session_key'])

                                    # Check if any notification agents have notifications enabled
                                    if any(d['on_pause'] for d in notifiers.
                                           available_notification_agents()):
                                        # Push any notifications -
                                        # Push it on it's own thread so we don't hold up our db actions
                                        threading.Thread(
                                            target=notification_handler.notify,
                                            kwargs=dict(stream_data=stream,
                                                        notify_action='pause'
                                                        )).start()

                                if session['state'] == 'playing' and stream[
                                        'state'] == 'paused':
                                    logger.debug(
                                        u"PlexPy Monitor :: Session %s has been resumed."
                                        % stream['session_key'])

                                    # Check if any notification agents have notifications enabled
                                    if any(d['on_resume'] for d in notifiers.
                                           available_notification_agents()):
                                        # Push any notifications -
                                        # Push it on it's own thread so we don't hold up our db actions
                                        threading.Thread(
                                            target=notification_handler.notify,
                                            kwargs=dict(stream_data=stream,
                                                        notify_action='resume'
                                                        )).start()

                            if stream['state'] == 'paused' and not ws_request:
                                # The stream is still paused so we need to increment the paused_counter
                                # Using the set config parameter as the interval, probably not the most accurate but
                                # it will have to do for now. If it's a websocket request don't use this method.
                                paused_counter = int(
                                    stream['paused_counter']
                                ) + plexpy.CONFIG.MONITORING_INTERVAL
                                monitor_db.action(
                                    'UPDATE sessions SET paused_counter = ? '
                                    'WHERE session_key = ? AND rating_key = ?',
                                    [
                                        paused_counter, stream['session_key'],
                                        stream['rating_key']
                                    ])

                            if session[
                                    'state'] == 'buffering' and plexpy.CONFIG.BUFFER_THRESHOLD > 0:
                                # The stream is buffering so we need to increment the buffer_count
                                # We're going just increment on every monitor ping,
                                # would be difficult to keep track otherwise
                                monitor_db.action(
                                    'UPDATE sessions SET buffer_count = buffer_count + 1 '
                                    'WHERE session_key = ? AND rating_key = ?',
                                    [
                                        stream['session_key'],
                                        stream['rating_key']
                                    ])

                                # Check the current buffer count and last buffer to determine if we should notify
                                buffer_values = monitor_db.select(
                                    'SELECT buffer_count, buffer_last_triggered '
                                    'FROM sessions '
                                    'WHERE session_key = ? AND rating_key = ?',
                                    [
                                        stream['session_key'],
                                        stream['rating_key']
                                    ])

                                if buffer_values[0][
                                        'buffer_count'] >= plexpy.CONFIG.BUFFER_THRESHOLD:
                                    # Push any notifications -
                                    # Push it on it's own thread so we don't hold up our db actions
                                    # Our first buffer notification
                                    if buffer_values[0][
                                            'buffer_count'] == plexpy.CONFIG.BUFFER_THRESHOLD:
                                        logger.info(
                                            u"PlexPy Monitor :: User '%s' has triggered a buffer warning."
                                            % stream['user'])
                                        # Set the buffer trigger time
                                        monitor_db.action(
                                            'UPDATE sessions '
                                            'SET buffer_last_triggered = strftime("%s","now") '
                                            'WHERE session_key = ? AND rating_key = ?',
                                            [
                                                stream['session_key'],
                                                stream['rating_key']
                                            ])

                                        # Check if any notification agents have notifications enabled
                                        if any(d['on_buffer']
                                               for d in notifiers.
                                               available_notification_agents(
                                               )):
                                            # Push any notifications -
                                            # Push it on it's own thread so we don't hold up our db actions
                                            threading.Thread(
                                                target=notification_handler.
                                                notify,
                                                kwargs=dict(
                                                    stream_data=stream,
                                                    notify_action='buffer'
                                                )).start()
                                    else:
                                        # Subsequent buffer notifications after wait time
                                        if int(time.time()) > buffer_values[0]['buffer_last_triggered'] + \
                                                plexpy.CONFIG.BUFFER_WAIT:
                                            logger.info(
                                                u"PlexPy Monitor :: User '%s' has triggered multiple buffer warnings."
                                                % stream['user'])
                                            # Set the buffer trigger time
                                            monitor_db.action(
                                                'UPDATE sessions '
                                                'SET buffer_last_triggered = strftime("%s","now") '
                                                'WHERE session_key = ? AND rating_key = ?',
                                                [
                                                    stream['session_key'],
                                                    stream['rating_key']
                                                ])

                                            # Check if any notification agents have notifications enabled
                                            if any(d['on_buffer']
                                                   for d in notifiers.
                                                   available_notification_agents(
                                                   )):
                                                # Push any notifications -
                                                # Push it on it's own thread so we don't hold up our db actions
                                                threading.Thread(
                                                    target=notification_handler
                                                    .notify,
                                                    kwargs=dict(
                                                        stream_data=stream,
                                                        notify_action='buffer'
                                                    )).start()

                                logger.debug(
                                    u"PlexPy Monitor :: Session %s is buffering. Count is now %s. Last triggered %s."
                                    %
                                    (stream['session_key'],
                                     buffer_values[0]['buffer_count'],
                                     buffer_values[0]['buffer_last_triggered'])
                                )

                            # Check if the user has reached the offset in the media we defined as the "watched" percent
                            # Don't trigger if state is buffer as some clients push the progress to the end when
                            # buffering on start.
                            if session['view_offset'] and session[
                                    'duration'] and session[
                                        'state'] != 'buffering':
                                if helpers.get_percent(
                                        session['view_offset'],
                                        session['duration']
                                ) > plexpy.CONFIG.NOTIFY_WATCHED_PERCENT:
                                    # Check if any notification agents have notifications enabled
                                    if any(d['on_watched'] for d in notifiers.
                                           available_notification_agents()):
                                        # Push any notifications -
                                        # Push it on it's own thread so we don't hold up our db actions
                                        threading.Thread(
                                            target=notification_handler.notify,
                                            kwargs=dict(stream_data=stream,
                                                        notify_action='watched'
                                                        )).start()

                else:
                    # The user has stopped playing a stream
                    if stream['state'] != 'stopped':
                        logger.debug(
                            u"PlexPy Monitor :: Session %s has stopped." %
                            stream['session_key'])

                        # Set the stream stop time
                        stream['stopped'] = int(time.time())
                        monitor_db.action(
                            'UPDATE sessions SET stopped = ?, state = ? '
                            'WHERE session_key = ? AND rating_key = ?', [
                                stream['stopped'], 'stopped',
                                stream['session_key'], stream['rating_key']
                            ])

                        # Check if the user has reached the offset in the media we defined as the "watched" percent
                        if stream['view_offset'] and stream['duration']:
                            if helpers.get_percent(
                                    stream['view_offset'], stream['duration']
                            ) > plexpy.CONFIG.NOTIFY_WATCHED_PERCENT:
                                # Check if any notification agents have notifications enabled
                                if any(d['on_watched'] for d in notifiers.
                                       available_notification_agents()):
                                    # Push any notifications -
                                    # Push it on it's own thread so we don't hold up our db actions
                                    threading.Thread(
                                        target=notification_handler.notify,
                                        kwargs=dict(
                                            stream_data=stream,
                                            notify_action='watched')).start()

                        # Check if any notification agents have notifications enabled
                        if any(d['on_stop'] for d in
                               notifiers.available_notification_agents()):
                            # Push any notifications - Push it on it's own thread so we don't hold up our db actions
                            threading.Thread(
                                target=notification_handler.notify,
                                kwargs=dict(stream_data=stream,
                                            notify_action='stop')).start()

                    # Write the item history on playback stop
                    success = monitor_process.write_session_history(
                        session=stream)

                    if success:
                        # If session is written to the databaase successfully, remove the session from the session table
                        logger.debug(
                            u"PlexPy Monitor :: Removing sessionKey %s ratingKey %s from session queue"
                            % (stream['session_key'], stream['rating_key']))
                        monitor_db.action(
                            'DELETE FROM sessions WHERE session_key = ? AND rating_key = ?',
                            [stream['session_key'], stream['rating_key']])
                    else:
                        logger.warn(u"PlexPy Monitor :: Failed to write sessionKey %s ratingKey %s to the database. " \
                                    "Will try again on the next pass." % (stream['session_key'], stream['rating_key']))

            # Process the newly received session data
            for session in media_container:
                new_session = monitor_process.write_session(session)

                if new_session:
                    logger.debug(u"PlexPy Monitor :: Session %s has started." %
                                 session['session_key'])

        else:
            logger.debug(u"PlexPy Monitor :: Unable to read session list.")

            int_ping_count += 1
            logger.warn(u"PlexPy Monitor :: Unable to get an internal response from the server, ping attempt %s." \
                        % str(int_ping_count))

        if int_ping_count == 3:
            # Check if any notification agents have notifications enabled
            if any(d['on_intdown']
                   for d in notifiers.available_notification_agents()):
                # Fire off notifications
                threading.Thread(target=notification_handler.notify_timeline,
                                 kwargs=dict(notify_action='intdown')).start()
Beispiel #20
0
def check_active_sessions():

    with monitor_lock:
        pms_connect = pmsconnect.PmsConnect()
        session_list = pms_connect.get_current_activity()
        monitor_db = database.MonitorDatabase()
        monitor_process = MonitorProcessing()
        # logger.debug(u"PlexPy Monitor :: Checking for active streams.")

        if session_list:
            media_container = session_list["sessions"]

            # Check our temp table for what we must do with the new streams
            db_streams = monitor_db.select(
                "SELECT started, session_key, rating_key, media_type, title, parent_title, "
                "grandparent_title, user_id, user, friendly_name, ip_address, player, "
                "platform, machine_id, parent_rating_key, grandparent_rating_key, state, "
                "view_offset, duration, video_decision, audio_decision, width, height, "
                "container, video_codec, audio_codec, bitrate, video_resolution, "
                "video_framerate, aspect_ratio, audio_channels, transcode_protocol, "
                "transcode_container, transcode_video_codec, transcode_audio_codec, "
                "transcode_audio_channels, transcode_width, transcode_height, paused_counter "
                "FROM sessions"
            )
            for result in db_streams:
                # Build a result dictionary for easier referencing
                stream = {
                    "started": result[0],
                    "session_key": result[1],
                    "rating_key": result[2],
                    "media_type": result[3],
                    "title": result[4],
                    "parent_title": result[5],
                    "grandparent_title": result[6],
                    "user_id": result[7],
                    "user": result[8],
                    "friendly_name": result[9],
                    "ip_address": result[10],
                    "player": result[11],
                    "platform": result[12],
                    "machine_id": result[13],
                    "parent_rating_key": result[14],
                    "grandparent_rating_key": result[15],
                    "state": result[16],
                    "view_offset": result[17],
                    "duration": result[18],
                    "video_decision": result[19],
                    "audio_decision": result[20],
                    "width": result[21],
                    "height": result[22],
                    "container": result[23],
                    "video_codec": result[24],
                    "audio_codec": result[25],
                    "bitrate": result[26],
                    "video_resolution": result[27],
                    "video_framerate": result[28],
                    "aspect_ratio": result[29],
                    "audio_channels": result[30],
                    "transcode_protocol": result[31],
                    "transcode_container": result[32],
                    "transcode_video_codec": result[33],
                    "transcode_audio_codec": result[34],
                    "transcode_audio_channels": result[35],
                    "transcode_width": result[36],
                    "transcode_height": result[37],
                    "paused_counter": result[38],
                }

                if any(
                    d["session_key"] == str(stream["session_key"]) and d["rating_key"] == str(stream["rating_key"])
                    for d in media_container
                ):
                    # The user's session is still active
                    for session in media_container:
                        if session["session_key"] == str(stream["session_key"]) and session["rating_key"] == str(
                            stream["rating_key"]
                        ):
                            # The user is still playing the same media item
                            # Here we can check the play states
                            if session["state"] != stream["state"]:
                                if session["state"] == "paused":
                                    # Push any notifications -
                                    # Push it on it's own thread so we don't hold up our db actions
                                    threading.Thread(
                                        target=notification_handler.notify,
                                        kwargs=dict(stream_data=stream, notify_action="pause"),
                                    ).start()
                            if stream["state"] == "paused":
                                # The stream is still paused so we need to increment the paused_counter
                                # Using the set config parameter as the interval, probably not the most accurate but
                                # it will have to do for now.
                                paused_counter = int(stream["paused_counter"]) + plexpy.CONFIG.MONITORING_INTERVAL
                                monitor_db.action(
                                    "UPDATE sessions SET paused_counter = ? "
                                    "WHERE session_key = ? AND rating_key = ?",
                                    [paused_counter, stream["session_key"], stream["rating_key"]],
                                )
                            # Check if the user has reached the offset in the media we defined as the "watched" percent
                            if session["progress"] and session["duration"]:
                                if (
                                    helpers.get_percent(session["progress"], session["duration"])
                                    > plexpy.CONFIG.NOTIFY_WATCHED_PERCENT
                                ):
                                    # Push any notifications -
                                    # Push it on it's own thread so we don't hold up our db actions
                                    threading.Thread(
                                        target=notification_handler.notify,
                                        kwargs=dict(stream_data=stream, notify_action="watched"),
                                    ).start()

                else:
                    # The user has stopped playing a stream
                    logger.debug(
                        u"PlexPy Monitor :: Removing sessionKey %s ratingKey %s from session queue"
                        % (stream["session_key"], stream["rating_key"])
                    )
                    monitor_db.action(
                        "DELETE FROM sessions WHERE session_key = ? AND rating_key = ?",
                        [stream["session_key"], stream["rating_key"]],
                    )

                    # Check if the user has reached the offset in the media we defined as the "watched" percent
                    if stream["view_offset"] and stream["duration"]:
                        if (
                            helpers.get_percent(stream["view_offset"], stream["duration"])
                            > plexpy.CONFIG.NOTIFY_WATCHED_PERCENT
                        ):
                            # Push any notifications -
                            # Push it on it's own thread so we don't hold up our db actions
                            threading.Thread(
                                target=notification_handler.notify,
                                kwargs=dict(stream_data=stream, notify_action="watched"),
                            ).start()

                    # Push any notifications - Push it on it's own thread so we don't hold up our db actions
                    threading.Thread(
                        target=notification_handler.notify, kwargs=dict(stream_data=stream, notify_action="stop")
                    ).start()

                    # Write the item history on playback stop
                    monitor_process.write_session_history(session=stream)

            # Process the newly received session data
            for session in media_container:
                monitor_process.write_session(session)
        else:
            logger.debug(u"PlexPy Monitor :: Unable to read session list.")
Beispiel #21
0
def notify(stream_data=None, notify_action=None):
    from plexpy import users

    if stream_data and notify_action:
        # Check if notifications enabled for user
        user_data = users.Users()
        user_details = user_data.get_user_friendly_name(user=stream_data["user"])

        if not user_details["do_notify"]:
            return

        if stream_data["media_type"] == "movie" or stream_data["media_type"] == "episode":
            if plexpy.CONFIG.MOVIE_NOTIFY_ENABLE or plexpy.CONFIG.TV_NOTIFY_ENABLE:

                progress_percent = helpers.get_percent(stream_data["view_offset"], stream_data["duration"])

                for agent in notifiers.available_notification_agents():
                    if agent["on_play"] and notify_action == "play":
                        # Build and send notification
                        notify_strings = build_notify_text(session=stream_data, state=notify_action)
                        notifiers.send_notification(
                            config_id=agent["id"], subject=notify_strings[0], body=notify_strings[1]
                        )
                        # Set the notification state in the db
                        set_notify_state(session=stream_data, state="play", agent_info=agent)

                    elif (
                        agent["on_stop"]
                        and notify_action == "stop"
                        and (
                            plexpy.CONFIG.NOTIFY_CONSECUTIVE or progress_percent < plexpy.CONFIG.NOTIFY_WATCHED_PERCENT
                        )
                    ):
                        # Build and send notification
                        notify_strings = build_notify_text(session=stream_data, state=notify_action)
                        notifiers.send_notification(
                            config_id=agent["id"], subject=notify_strings[0], body=notify_strings[1]
                        )

                        set_notify_state(session=stream_data, state="stop", agent_info=agent)

                    elif (
                        agent["on_pause"]
                        and notify_action == "pause"
                        and (plexpy.CONFIG.NOTIFY_CONSECUTIVE or progress_percent < 99)
                    ):
                        # Build and send notification
                        notify_strings = build_notify_text(session=stream_data, state=notify_action)
                        notifiers.send_notification(
                            config_id=agent["id"], subject=notify_strings[0], body=notify_strings[1]
                        )

                        set_notify_state(session=stream_data, state="pause", agent_info=agent)

                    elif (
                        agent["on_resume"]
                        and notify_action == "resume"
                        and (plexpy.CONFIG.NOTIFY_CONSECUTIVE or progress_percent < 99)
                    ):
                        # Build and send notification
                        notify_strings = build_notify_text(session=stream_data, state=notify_action)
                        notifiers.send_notification(
                            config_id=agent["id"], subject=notify_strings[0], body=notify_strings[1]
                        )

                        set_notify_state(session=stream_data, state="resume", agent_info=agent)

                    elif agent["on_buffer"] and notify_action == "buffer":
                        # Build and send notification
                        notify_strings = build_notify_text(session=stream_data, state=notify_action)
                        notifiers.send_notification(
                            config_id=agent["id"], subject=notify_strings[0], body=notify_strings[1]
                        )

                        set_notify_state(session=stream_data, state="buffer", agent_info=agent)

                    elif agent["on_watched"] and notify_action == "watched":
                        # Get the current states for notifications from our db
                        notify_states = get_notify_state(session=stream_data)

                        # If there is nothing in the notify_log for our agent id but it is enabled we should notify
                        if not any(d["agent_id"] == agent["id"] for d in notify_states):
                            # Build and send notification
                            notify_strings = build_notify_text(session=stream_data, state=notify_action)
                            notifiers.send_notification(
                                config_id=agent["id"], subject=notify_strings[0], body=notify_strings[1]
                            )
                            # Set the notification state in the db
                            set_notify_state(session=stream_data, state="watched", agent_info=agent)

                        else:
                            # Check in our notify log if the notification has already been sent
                            for notify_state in notify_states:
                                if not notify_state["on_watched"] and (notify_state["agent_id"] == agent["id"]):
                                    # Build and send notification
                                    notify_strings = build_notify_text(session=stream_data, state=notify_action)
                                    notifiers.send_notification(
                                        config_id=agent["id"], subject=notify_strings[0], body=notify_strings[1]
                                    )
                                    # Set the notification state in the db
                                    set_notify_state(session=stream_data, state="watched", agent_info=agent)

        elif stream_data["media_type"] == "track":
            if plexpy.CONFIG.MUSIC_NOTIFY_ENABLE:

                for agent in notifiers.available_notification_agents():
                    if agent["on_play"] and notify_action == "play":
                        # Build and send notification
                        notify_strings = build_notify_text(session=stream_data, state=notify_action)
                        notifiers.send_notification(
                            config_id=agent["id"], subject=notify_strings[0], body=notify_strings[1]
                        )
                        # Set the notification state in the db
                        set_notify_state(session=stream_data, state="play", agent_info=agent)

                    elif agent["on_stop"] and notify_action == "stop":
                        # Build and send notification
                        notify_strings = build_notify_text(session=stream_data, state=notify_action)
                        notifiers.send_notification(
                            config_id=agent["id"], subject=notify_strings[0], body=notify_strings[1]
                        )
                        # Set the notification state in the db
                        set_notify_state(session=stream_data, state="stop", agent_info=agent)

                    elif agent["on_pause"] and notify_action == "pause":
                        # Build and send notification
                        notify_strings = build_notify_text(session=stream_data, state=notify_action)
                        notifiers.send_notification(
                            config_id=agent["id"], subject=notify_strings[0], body=notify_strings[1]
                        )
                        # Set the notification state in the db
                        set_notify_state(session=stream_data, state="pause", agent_info=agent)

                    elif agent["on_resume"] and notify_action == "resume":
                        # Build and send notification
                        notify_strings = build_notify_text(session=stream_data, state=notify_action)
                        notifiers.send_notification(
                            config_id=agent["id"], subject=notify_strings[0], body=notify_strings[1]
                        )
                        # Set the notification state in the db
                        set_notify_state(session=stream_data, state="resume", agent_info=agent)

                    elif agent["on_buffer"] and notify_action == "buffer":
                        # Build and send notification
                        notify_strings = build_notify_text(session=stream_data, state=notify_action)
                        notifiers.send_notification(
                            config_id=agent["id"], subject=notify_strings[0], body=notify_strings[1]
                        )
                        # Set the notification state in the db
                        set_notify_state(session=stream_data, state="buffer", agent_info=agent)

        elif stream_data["media_type"] == "clip":
            pass
        else:
            logger.debug(u"PlexPy Notifier :: Notify called with unsupported media type.")
            pass
    else:
        logger.debug(u"PlexPy Notifier :: Notify called but incomplete data received.")
Beispiel #22
0
def check_active_sessions():

    with monitor_lock:
        pms_connect = pmsconnect.PmsConnect()
        session_list = pms_connect.get_current_activity()
        monitor_db = database.MonitorDatabase()
        monitor_process = MonitorProcessing()
        # logger.debug(u"PlexPy Monitor :: Checking for active streams.")

        if session_list:
            media_container = session_list['sessions']

            # Check our temp table for what we must do with the new streams
            db_streams = monitor_db.select('SELECT started, session_key, rating_key, media_type, title, parent_title, '
                                           'grandparent_title, user_id, user, friendly_name, ip_address, player, '
                                           'platform, machine_id, parent_rating_key, grandparent_rating_key, state, '
                                           'view_offset, duration, video_decision, audio_decision, width, height, '
                                           'container, video_codec, audio_codec, bitrate, video_resolution, '
                                           'video_framerate, aspect_ratio, audio_channels, transcode_protocol, '
                                           'transcode_container, transcode_video_codec, transcode_audio_codec, '
                                           'transcode_audio_channels, transcode_width, transcode_height, paused_counter '
                                           'FROM sessions')
            for stream in db_streams:
                if any(d['session_key'] == str(stream['session_key']) and d['rating_key'] == str(stream['rating_key'])
                       for d in media_container):
                    # The user's session is still active
                    for session in media_container:
                        if session['session_key'] == str(stream['session_key']) and \
                                session['rating_key'] == str(stream['rating_key']):
                            # The user is still playing the same media item
                            # Here we can check the play states
                            if session['state'] != stream['state']:
                                if session['state'] == 'paused':
                                    # Push any notifications -
                                    # Push it on it's own thread so we don't hold up our db actions
                                    threading.Thread(target=notification_handler.notify,
                                                     kwargs=dict(stream_data=stream, notify_action='pause')).start()
                                if session['state'] == 'playing' and stream['state'] == 'paused':
                                    # Push any notifications -
                                    # Push it on it's own thread so we don't hold up our db actions
                                    threading.Thread(target=notification_handler.notify,
                                                     kwargs=dict(stream_data=stream, notify_action='resume')).start()
                            if stream['state'] == 'paused':
                                # The stream is still paused so we need to increment the paused_counter
                                # Using the set config parameter as the interval, probably not the most accurate but
                                # it will have to do for now.
                                paused_counter = int(stream['paused_counter']) + plexpy.CONFIG.MONITORING_INTERVAL
                                monitor_db.action('UPDATE sessions SET paused_counter = ? '
                                                  'WHERE session_key = ? AND rating_key = ?',
                                                  [paused_counter, stream['session_key'], stream['rating_key']])
                            if session['state'] == 'buffering':
                                # The stream is buffering so we need to increment the buffer_count
                                # We're going just increment on every monitor ping,
                                # would be difficult to keep track otherwise
                                monitor_db.action('UPDATE sessions SET buffer_count = buffer_count + 1 '
                                                  'WHERE session_key = ? AND rating_key = ?',
                                                  [stream['session_key'], stream['rating_key']])

                                # Check the current buffer count and last buffer to determine if we should notify
                                buffer_values = monitor_db.select('SELECT buffer_count, buffer_last_triggered '
                                                                  'FROM sessions '
                                                                  'WHERE session_key = ? AND rating_key = ?',
                                                                  [stream['session_key'], stream['rating_key']])

                                if buffer_values[0]['buffer_count'] >= plexpy.CONFIG.BUFFER_THRESHOLD:
                                    # Push any notifications -
                                    # Push it on it's own thread so we don't hold up our db actions
                                    # Our first buffer notification
                                    if buffer_values[0]['buffer_count'] == plexpy.CONFIG.BUFFER_THRESHOLD:
                                        logger.info(u"PlexPy Monitor :: User '%s' has triggered a buffer warning."
                                                    % stream['user'])
                                        # Set the buffer trigger time
                                        monitor_db.action('UPDATE sessions '
                                                          'SET buffer_last_triggered = strftime("%s","now") '
                                                          'WHERE session_key = ? AND rating_key = ?',
                                                          [stream['session_key'], stream['rating_key']])

                                        threading.Thread(target=notification_handler.notify,
                                                         kwargs=dict(stream_data=stream, notify_action='buffer')).start()
                                    else:
                                        # Subsequent buffer notifications after wait time
                                        if int(time.time()) > buffer_values[0]['buffer_last_triggered'] + \
                                                plexpy.CONFIG.BUFFER_WAIT:
                                            logger.info(u"PlexPy Monitor :: User '%s' has triggered multiple buffer warnings."
                                                    % stream['user'])
                                            threading.Thread(target=notification_handler.notify,
                                                             kwargs=dict(stream_data=stream, notify_action='buffer')).start()

                                logger.debug(u"PlexPy Monitor :: Stream buffering. Count is now %s. Last triggered %s."
                                             % (buffer_values[0][0], buffer_values[0][1]))

                            # Check if the user has reached the offset in the media we defined as the "watched" percent
                            # Don't trigger if state is buffer as some clients push the progress to the end when
                            # buffering on start.
                            if session['progress'] and session['duration'] and session['state'] != 'buffering':
                                if helpers.get_percent(session['progress'],
                                                       session['duration']) > plexpy.CONFIG.NOTIFY_WATCHED_PERCENT:
                                    # Push any notifications -
                                    # Push it on it's own thread so we don't hold up our db actions
                                    threading.Thread(target=notification_handler.notify,
                                                     kwargs=dict(stream_data=stream, notify_action='watched')).start()

                else:
                    # The user has stopped playing a stream
                    logger.debug(u"PlexPy Monitor :: Removing sessionKey %s ratingKey %s from session queue"
                                 % (stream['session_key'], stream['rating_key']))
                    monitor_db.action('DELETE FROM sessions WHERE session_key = ? AND rating_key = ?',
                                      [stream['session_key'], stream['rating_key']])

                    # Check if the user has reached the offset in the media we defined as the "watched" percent
                    if stream['view_offset'] and stream['duration']:
                        if helpers.get_percent(stream['view_offset'],
                                               stream['duration']) > plexpy.CONFIG.NOTIFY_WATCHED_PERCENT:
                            # Push any notifications -
                            # Push it on it's own thread so we don't hold up our db actions
                            threading.Thread(target=notification_handler.notify,
                                             kwargs=dict(stream_data=stream, notify_action='watched')).start()

                    # Push any notifications - Push it on it's own thread so we don't hold up our db actions
                    threading.Thread(target=notification_handler.notify,
                                     kwargs=dict(stream_data=stream, notify_action='stop')).start()

                    # Write the item history on playback stop
                    monitor_process.write_session_history(session=stream)

            # Process the newly received session data
            for session in media_container:
                monitor_process.write_session(session)
        else:
            logger.debug(u"PlexPy Monitor :: Unable to read session list.")
Beispiel #23
0
def build_notify_text(session, state):
    from plexpy import pmsconnect, helpers
    import re

    # Get the server name
    pms_connect = pmsconnect.PmsConnect()
    server_name = pms_connect.get_server_pref(pref="FriendlyName")

    # Get metadata feed for item
    metadata = pms_connect.get_metadata_details(rating_key=session["rating_key"])

    if metadata:
        item_metadata = metadata["metadata"]
    else:
        logger.error(u"PlexPy Notifier :: Unable to retrieve metadata for rating_key %s" % str(session["rating_key"]))
        return []

    # Check for exclusion tags
    if session["media_type"] == "episode":
        # Regex pattern to remove the text in the tags we don't want
        pattern = re.compile("<movie>[^>]+.</movie>|<music>[^>]+.</music>", re.IGNORECASE)
    elif session["media_type"] == "movie":
        # Regex pattern to remove the text in the tags we don't want
        pattern = re.compile("<tv>[^>]+.</tv>|<music>[^>]+.</music>", re.IGNORECASE)
    elif session["media_type"] == "track":
        # Regex pattern to remove the text in the tags we don't want
        pattern = re.compile("<tv>[^>]+.</tv>|<movie>[^>]+.</movie>", re.IGNORECASE)
    else:
        pattern = None

    if (
        session["media_type"] == "episode"
        or session["media_type"] == "movie"
        or session["media_type"] == "track"
        and pattern
    ):
        # Remove the unwanted tags and strip any unmatch tags too.
        on_start_subject = strip_tag(re.sub(pattern, "", plexpy.CONFIG.NOTIFY_ON_START_SUBJECT_TEXT))
        on_start_body = strip_tag(re.sub(pattern, "", plexpy.CONFIG.NOTIFY_ON_START_BODY_TEXT))
        on_stop_subject = strip_tag(re.sub(pattern, "", plexpy.CONFIG.NOTIFY_ON_STOP_SUBJECT_TEXT))
        on_stop_body = strip_tag(re.sub(pattern, "", plexpy.CONFIG.NOTIFY_ON_STOP_BODY_TEXT))
        on_pause_subject = strip_tag(re.sub(pattern, "", plexpy.CONFIG.NOTIFY_ON_PAUSE_SUBJECT_TEXT))
        on_pause_body = strip_tag(re.sub(pattern, "", plexpy.CONFIG.NOTIFY_ON_PAUSE_BODY_TEXT))
        on_resume_subject = strip_tag(re.sub(pattern, "", plexpy.CONFIG.NOTIFY_ON_RESUME_SUBJECT_TEXT))
        on_resume_body = strip_tag(re.sub(pattern, "", plexpy.CONFIG.NOTIFY_ON_RESUME_BODY_TEXT))
        on_buffer_subject = strip_tag(re.sub(pattern, "", plexpy.CONFIG.NOTIFY_ON_BUFFER_SUBJECT_TEXT))
        on_buffer_body = strip_tag(re.sub(pattern, "", plexpy.CONFIG.NOTIFY_ON_BUFFER_BODY_TEXT))
        on_watched_subject = strip_tag(re.sub(pattern, "", plexpy.CONFIG.NOTIFY_ON_WATCHED_SUBJECT_TEXT))
        on_watched_body = strip_tag(re.sub(pattern, "", plexpy.CONFIG.NOTIFY_ON_WATCHED_BODY_TEXT))
    else:
        on_start_subject = plexpy.CONFIG.NOTIFY_ON_START_SUBJECT_TEXT
        on_start_body = plexpy.CONFIG.NOTIFY_ON_START_BODY_TEXT
        on_stop_subject = plexpy.CONFIG.NOTIFY_ON_STOP_SUBJECT_TEXT
        on_stop_body = plexpy.CONFIG.NOTIFY_ON_STOP_BODY_TEXT
        on_pause_subject = plexpy.CONFIG.NOTIFY_ON_PAUSE_SUBJECT_TEXT
        on_pause_body = plexpy.CONFIG.NOTIFY_ON_PAUSE_BODY_TEXT
        on_resume_subject = plexpy.CONFIG.NOTIFY_ON_RESUME_SUBJECT_TEXT
        on_resume_body = plexpy.CONFIG.NOTIFY_ON_RESUME_BODY_TEXT
        on_buffer_subject = plexpy.CONFIG.NOTIFY_ON_BUFFER_SUBJECT_TEXT
        on_buffer_body = plexpy.CONFIG.NOTIFY_ON_BUFFER_BODY_TEXT
        on_watched_subject = plexpy.CONFIG.NOTIFY_ON_WATCHED_SUBJECT_TEXT
        on_watched_body = plexpy.CONFIG.NOTIFY_ON_WATCHED_BODY_TEXT

    # Create a title
    if session["media_type"] == "episode":
        full_title = "%s - %s" % (session["grandparent_title"], session["title"])
    elif session["media_type"] == "track":
        full_title = "%s - %s" % (session["grandparent_title"], session["title"])
    else:
        full_title = session["title"]

    # Generate a combined transcode decision value
    if session["video_decision"]:
        if session["video_decision"] == "transcode":
            transcode_decision = "Transcode"
        elif session["video_decision"] == "copy" or session["audio_decision"] == "copy":
            transcode_decision = "Direct Stream"
        else:
            transcode_decision = "Direct Play"
    else:
        if session["audio_decision"] == "transcode":
            transcode_decision = "Transcode"
        else:
            transcode_decision = "Direct Play"

    duration = helpers.convert_milliseconds_to_minutes(item_metadata["duration"])
    view_offset = helpers.convert_milliseconds_to_minutes(session["view_offset"])
    stream_duration = 0
    if state != "play":
        if session["paused_counter"]:
            stream_duration = int(
                (
                    time.time()
                    - helpers.cast_to_float(session["started"])
                    - helpers.cast_to_float(session["paused_counter"])
                )
                / 60
            )
        else:
            stream_duration = int((time.time() - helpers.cast_to_float(session["started"])) / 60)

    progress_percent = helpers.get_percent(view_offset, duration)

    available_params = {
        "server_name": server_name,
        "user": session["friendly_name"],
        "platform": session["platform"],
        "player": session["player"],
        "media_type": session["media_type"],
        "title": full_title,
        "show_name": item_metadata["grandparent_title"],
        "episode_name": item_metadata["title"],
        "artist_name": item_metadata["grandparent_title"],
        "album_name": item_metadata["parent_title"],
        "season_num": item_metadata["parent_index"],
        "season_num00": item_metadata["parent_index"].zfill(2),
        "episode_num": item_metadata["index"],
        "episode_num00": item_metadata["index"].zfill(2),
        "transcode_decision": transcode_decision,
        "year": item_metadata["year"],
        "studio": item_metadata["studio"],
        "content_rating": item_metadata["content_rating"],
        "summary": item_metadata["summary"],
        "rating": item_metadata["rating"],
        "duration": duration,
        "stream_duration": stream_duration,
        "remaining_duration": duration - view_offset,
        "progress": view_offset,
        "progress_percent": progress_percent,
    }

    # Default subject text
    subject_text = "PlexPy (%s)" % server_name

    if state == "play":
        # Default body text
        body_text = "%s (%s) is watching %s" % (session["friendly_name"], session["player"], full_title)

        if on_start_subject and on_start_body:
            try:
                subject_text = unicode(on_start_subject).format(**available_params)
            except LookupError, e:
                logger.error(
                    u"PlexPy Notifier :: Unable to parse field %s in notification subject. Using fallback." % e
                )
            except:
def check_active_sessions(server=None, ws_request=False):
    if server.WS and server.WS.WS_CONNECTION and server.WS.WS_CONNECTION.connected:
        with server.monitor_lock:
            session_list = server.get_current_activity()
            monitor_db = database.MonitorDatabase()
            monitor_process = activity_processor.ActivityProcessor(server)
            logger.debug(
                u"Tautulli Monitor :: %s: Checking for active streams." %
                server.CONFIG.PMS_NAME)

            if session_list:
                media_container = session_list['sessions']

                # Check our temp table for what we must do with the new streams
                db_streams = monitor_process.get_sessions()
                for stream in db_streams:
                    if any(d['session_key'] == str(stream['session_key'])
                           and d['rating_key'] == str(stream['rating_key'])
                           for d in media_container):
                        # The user's session is still active
                        for session in media_container:
                            if session['session_key'] == str(stream['session_key']) and \
                                    session['rating_key'] == str(stream['rating_key']):
                                # The user is still playing the same media item
                                # Here we can check the play states
                                if session['state'] != stream['state']:
                                    if session['state'] == 'paused':
                                        logger.debug(
                                            u"Tautulli Monitor :: %s: Session %s paused."
                                            % (server.CONFIG.PMS_NAME,
                                               stream['session_key']))

                                        plexpy.NOTIFY_QUEUE.put({
                                            'stream_data':
                                            stream.copy(),
                                            'notify_action':
                                            'on_pause'
                                        })

                                    if session['state'] == 'playing' and stream[
                                            'state'] == 'paused':
                                        logger.debug(
                                            u"Tautulli Monitor :: %s: Session %s resumed."
                                            % (server.CONFIG.PMS_NAME,
                                               stream['session_key']))

                                        plexpy.NOTIFY_QUEUE.put({
                                            'stream_data':
                                            stream.copy(),
                                            'notify_action':
                                            'on_resume'
                                        })

                                if stream[
                                        'state'] == 'paused' and not ws_request:
                                    # The stream is still paused so we need to increment the paused_counter
                                    # Using the set config parameter as the interval, probably not the most accurate but
                                    # it will have to do for now. If it's a websocket request don't use this method.
                                    paused_counter = int(
                                        stream['paused_counter']
                                    ) + plexpy.CONFIG.MONITORING_INTERVAL
                                    monitor_db.action(
                                        'UPDATE sessions SET paused_counter = ? '
                                        'WHERE session_key = ? AND rating_key = ?',
                                        [
                                            paused_counter,
                                            stream['session_key'],
                                            stream['rating_key']
                                        ])

                                if session[
                                        'state'] == 'buffering' and plexpy.CONFIG.BUFFER_THRESHOLD > 0:
                                    # The stream is buffering so we need to increment the buffer_count
                                    # We're going just increment on every monitor ping,
                                    # would be difficult to keep track otherwise
                                    monitor_db.action(
                                        'UPDATE sessions SET buffer_count = buffer_count + 1 '
                                        'WHERE session_key = ? AND rating_key = ?',
                                        [
                                            stream['session_key'],
                                            stream['rating_key']
                                        ])

                                    # Check the current buffer count and last buffer to determine if we should notify
                                    buffer_values = monitor_db.select(
                                        'SELECT buffer_count, buffer_last_triggered '
                                        'FROM sessions '
                                        'WHERE session_key = ? AND rating_key = ?',
                                        [
                                            stream['session_key'],
                                            stream['rating_key']
                                        ])

                                    if buffer_values[0][
                                            'buffer_count'] >= plexpy.CONFIG.BUFFER_THRESHOLD:
                                        # Push any notifications -
                                        # Push it on it's own thread so we don't hold up our db actions
                                        # Our first buffer notification
                                        if buffer_values[0][
                                                'buffer_count'] == plexpy.CONFIG.BUFFER_THRESHOLD:
                                            logger.info(
                                                u"Tautulli Monitor :: %s: User '%s' has triggered a buffer warning."
                                                % (server.CONFIG.PMS_NAME,
                                                   stream['user']))
                                            # Set the buffer trigger time
                                            monitor_db.action(
                                                'UPDATE sessions '
                                                'SET buffer_last_triggered = strftime("%s","now") '
                                                'WHERE session_key = ? AND rating_key = ?',
                                                [
                                                    stream['session_key'],
                                                    stream['rating_key']
                                                ])

                                            plexpy.NOTIFY_QUEUE.put({
                                                'stream_data':
                                                stream.copy(),
                                                'notify_action':
                                                'on_buffer'
                                            })

                                        else:
                                            # Subsequent buffer notifications after wait time
                                            if int(time.time()) > buffer_values[0]['buffer_last_triggered'] + \
                                                    plexpy.CONFIG.BUFFER_WAIT:
                                                logger.info(
                                                    u"Tautulli Monitor :: %s: User '%s' has triggered multiple buffer warnings."
                                                    % (server.CONFIG.PMS_NAME,
                                                       stream['user']))
                                                # Set the buffer trigger time
                                                monitor_db.action(
                                                    'UPDATE sessions '
                                                    'SET buffer_last_triggered = strftime("%s","now") '
                                                    'WHERE session_key = ? AND rating_key = ?',
                                                    [
                                                        stream['session_key'],
                                                        stream['rating_key']
                                                    ])

                                                plexpy.NOTIFY_QUEUE.put({
                                                    'stream_data':
                                                    stream.copy(),
                                                    'notify_action':
                                                    'on_buffer'
                                                })

                                    logger.debug(
                                        u"Tautulli Monitor :: %s: Session %s is buffering. Count is now %s. Last triggered %s."
                                        % (server.CONFIG.PMS_NAME,
                                           stream['session_key'],
                                           buffer_values[0]['buffer_count'],
                                           buffer_values[0]
                                           ['buffer_last_triggered']))

                                # Check if the user has reached the offset in the media we defined as the "watched" percent
                                # Don't trigger if state is buffer as some clients push the progress to the end when
                                # buffering on start.
                                if session['state'] != 'buffering':
                                    progress_percent = helpers.get_percent(
                                        session['view_offset'],
                                        session['duration'])
                                    notify_states = notification_handler.get_notify_state(
                                        session=session)
                                    if (session['media_type'] == 'movie' and progress_percent >= plexpy.CONFIG.MOVIE_WATCHED_PERCENT or
                                        session['media_type'] == 'episode' and progress_percent >= plexpy.CONFIG.TV_WATCHED_PERCENT or
                                        session['media_type'] == 'track' and progress_percent >= plexpy.CONFIG.MUSIC_WATCHED_PERCENT) \
                                        and not any(d['notify_action'] == 'on_watched' for d in notify_states):
                                        plexpy.NOTIFY_QUEUE.put({
                                            'stream_data':
                                            stream.copy(),
                                            'notify_action':
                                            'on_watched'
                                        })

                    else:
                        # The user has stopped playing a stream
                        if stream['state'] != 'stopped':
                            logger.debug(
                                u"Tautulli Monitor :: %s: Session %s stopped."
                                % (server.CONFIG.PMS_NAME,
                                   stream['session_key']))

                            if not stream['stopped']:
                                # Set the stream stop time
                                stream['stopped'] = int(time.time())
                                monitor_db.action(
                                    'UPDATE sessions SET stopped = ?, state = ? '
                                    'WHERE session_key = ? AND rating_key = ?',
                                    [
                                        stream['stopped'], 'stopped',
                                        stream['session_key'],
                                        stream['rating_key']
                                    ])

                            progress_percent = helpers.get_percent(
                                stream['view_offset'], stream['duration'])
                            notify_states = notification_handler.get_notify_state(
                                session=stream)
                            if (stream['media_type'] == 'movie' and progress_percent >= plexpy.CONFIG.MOVIE_WATCHED_PERCENT or
                                stream['media_type'] == 'episode' and progress_percent >= plexpy.CONFIG.TV_WATCHED_PERCENT or
                                stream['media_type'] == 'track' and progress_percent >= plexpy.CONFIG.MUSIC_WATCHED_PERCENT) \
                                and not any(d['notify_action'] == 'on_watched' for d in notify_states):
                                plexpy.NOTIFY_QUEUE.put({
                                    'stream_data':
                                    stream.copy(),
                                    'notify_action':
                                    'on_watched'
                                })

                            plexpy.NOTIFY_QUEUE.put({
                                'stream_data':
                                stream.copy(),
                                'notify_action':
                                'on_stop'
                            })

                        # Write the item history on playback stop
                        row_id = monitor_process.write_session_history(
                            session=stream)

                        if row_id:
                            # If session is written to the databaase successfully, remove the session from the session table
                            logger.debug(
                                u"Tautulli Monitor :: %s: Removing sessionKey %s ratingKey %s from session queue"
                                %
                                (server.CONFIG.PMS_NAME, stream['session_key'],
                                 stream['rating_key']))
                            monitor_process.delete_session(row_id=row_id)
                        else:
                            stream['write_attempts'] += 1

                            if stream[
                                    'write_attempts'] < plexpy.CONFIG.SESSION_DB_WRITE_ATTEMPTS:
                                logger.warn(u"Tautulli Monitor :: %s: Failed to write sessionKey %s ratingKey %s to the database. " \
                                            "Will try again on the next pass. Write attempt %s."
                                            % (server.CONFIG.PMS_NAME, stream['session_key'], stream['rating_key'],
                                               str(stream['write_attempts'])))
                                monitor_process.increment_write_attempts(
                                    session_key=stream['session_key'])
                            else:
                                logger.warn(u"Tautulli Monitor :: %s: Failed to write sessionKey %s ratingKey %s to the database. " \
                                            "Removing session from the database. Write attempt %s."
                                            % (server.CONFIG.PMS_NAME, stream['session_key'],
                                               stream['rating_key'], str(stream['write_attempts'])))
                                logger.debug(
                                    u"Tautulli Monitor :: %s: Removing sessionKey %s ratingKey %s from session queue"
                                    % (server.CONFIG.PMS_NAME,
                                       stream['session_key'],
                                       stream['rating_key']))
                                monitor_process.delete_session(
                                    session_key=stream['session_key'])

                # Process the newly received session data
                for session in media_container:
                    new_session = monitor_process.write_session(session)

                    if new_session:
                        logger.debug(
                            u"Tautulli Monitor :: %s: Session %s started by user %s with ratingKey %s."
                            % (server.CONFIG.PMS_NAME, session['session_key'],
                               session['user_id'], session['rating_key']))

            else:
                logger.debug(
                    u"Tautulli Monitor :: %s: Unable to read session list." %
                    server.CONFIG.PMS_NAME)
Beispiel #25
0
    def get_session_each(self, stream_type='', session=None):
        session_output = None
        data_factory = datafactory.DataFactory()
        if stream_type == 'track':

            media_info = session.getElementsByTagName('Media')[0]
            audio_decision = 'direct play'
            audio_channels = helpers.get_xml_attr(media_info, 'audioChannels')
            audio_codec = helpers.get_xml_attr(media_info, 'audioCodec')
            container = helpers.get_xml_attr(media_info, 'container')
            bitrate = helpers.get_xml_attr(media_info, 'bitrate')
            duration = helpers.get_xml_attr(media_info, 'duration')
            progress = helpers.get_xml_attr(session, 'viewOffset')

            if session.getElementsByTagName('TranscodeSession'):
                transcode_session = session.getElementsByTagName('TranscodeSession')[0]
                audio_decision = helpers.get_xml_attr(transcode_session, 'audioDecision')
                transcode_audio_channels = helpers.get_xml_attr(transcode_session, 'audioChannels')
                transcode_audio_codec = helpers.get_xml_attr(transcode_session, 'audioCodec')
                transcode_container = helpers.get_xml_attr(transcode_session, 'container')
                transcode_protocol = helpers.get_xml_attr(transcode_session, 'protocol')
                duration = helpers.get_xml_attr(transcode_session, 'duration')
            else:
                transcode_audio_channels = ''
                transcode_audio_codec = ''
                transcode_container = ''
                transcode_protocol = ''

            user_details = data_factory.get_user_details(
                user=helpers.get_xml_attr(session.getElementsByTagName('User')[0], 'title'))

            if helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'machineIdentifier').endswith('_Track'):
                machine_id = helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'machineIdentifier')[:-6]
            else:
                machine_id = helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'machineIdentifier')

            session_output = {'session_key': helpers.get_xml_attr(session, 'sessionKey'),
                              'media_index': helpers.get_xml_attr(session, 'index'),
                              'parent_media_index': helpers.get_xml_attr(session, 'parentIndex'),
                              'art': helpers.get_xml_attr(session, 'art'),
                              'parent_thumb': helpers.get_xml_attr(session, 'parentThumb'),
                              'grandparent_thumb': helpers.get_xml_attr(session, 'grandparentThumb'),
                              'thumb': helpers.get_xml_attr(session, 'thumb'),
                              'bif_thumb': '',
                              'user': helpers.get_xml_attr(session.getElementsByTagName('User')[0], 'title'),
                              'user_id': user_details['user_id'],
                              'friendly_name': user_details['friendly_name'],
                              'player': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'title'),
                              'platform': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'platform'),
                              'machine_id': machine_id,
                              'state': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'state'),
                              'grandparent_title': helpers.get_xml_attr(session, 'grandparentTitle'),
                              'parent_title': helpers.get_xml_attr(session, 'parentTitle'),
                              'title': helpers.get_xml_attr(session, 'title'),
                              'rating_key': helpers.get_xml_attr(session, 'ratingKey'),
                              'parent_rating_key': helpers.get_xml_attr(session, 'parentRatingKey'),
                              'grandparent_rating_key': helpers.get_xml_attr(session, 'grandparentRatingKey'),
                              'audio_decision': audio_decision,
                              'audio_channels': audio_channels,
                              'audio_codec': audio_codec,
                              'video_decision': '',
                              'video_codec': '',
                              'height': '',
                              'width': '',
                              'container': container,
                              'bitrate': bitrate,
                              'video_resolution': '',
                              'video_framerate': '',
                              'aspect_ratio': '',
                              'transcode_audio_channels': transcode_audio_channels,
                              'transcode_audio_codec': transcode_audio_codec,
                              'transcode_video_codec': '',
                              'transcode_width': '',
                              'transcode_height': '',
                              'transcode_container': transcode_container,
                              'transcode_protocol': transcode_protocol,
                              'duration': duration,
                              'progress': progress,
                              'progress_percent': str(helpers.get_percent(progress, duration)),
                              'type': 'track',
                              'indexes': 0
                              }
        elif stream_type == 'video':
            media_info = session.getElementsByTagName('Media')[0]
            audio_decision = 'direct play'
            audio_channels = helpers.get_xml_attr(media_info, 'audioChannels')
            audio_codec = helpers.get_xml_attr(media_info, 'audioCodec')
            video_decision = 'direct play'
            video_codec = helpers.get_xml_attr(media_info, 'videoCodec')
            container = helpers.get_xml_attr(media_info, 'container')
            bitrate = helpers.get_xml_attr(media_info, 'bitrate')
            video_resolution = helpers.get_xml_attr(media_info, 'videoResolution')
            video_framerate = helpers.get_xml_attr(media_info, 'videoFrameRate')
            aspect_ratio = helpers.get_xml_attr(media_info, 'aspectRatio')
            width = helpers.get_xml_attr(media_info, 'width')
            height = helpers.get_xml_attr(media_info, 'height')
            duration = helpers.get_xml_attr(media_info, 'duration')
            progress = helpers.get_xml_attr(session, 'viewOffset')

            if session.getElementsByTagName('TranscodeSession'):
                transcode_session = session.getElementsByTagName('TranscodeSession')[0]
                audio_decision = helpers.get_xml_attr(transcode_session, 'audioDecision')
                transcode_audio_channels = helpers.get_xml_attr(transcode_session, 'audioChannels')
                transcode_audio_codec = helpers.get_xml_attr(transcode_session, 'audioCodec')
                video_decision = helpers.get_xml_attr(transcode_session, 'videoDecision')
                transcode_video_codec = helpers.get_xml_attr(transcode_session, 'videoCodec')
                transcode_width = helpers.get_xml_attr(transcode_session, 'width')
                transcode_height = helpers.get_xml_attr(transcode_session, 'height')
                transcode_container = helpers.get_xml_attr(transcode_session, 'container')
                transcode_protocol = helpers.get_xml_attr(transcode_session, 'protocol')
            else:
                transcode_audio_channels = ''
                transcode_audio_codec = ''
                transcode_video_codec = ''
                transcode_width = ''
                transcode_height = ''
                transcode_container = ''
                transcode_protocol = ''

            media_info = session.getElementsByTagName('Media')[0]
            if media_info.getElementsByTagName('Part'):
                indexes = helpers.get_xml_attr(media_info.getElementsByTagName('Part')[0], 'indexes')
                part_id = helpers.get_xml_attr(media_info.getElementsByTagName('Part')[0], 'id')
                if indexes == 'sd':
                    bif_thumb = '/library/parts/' + part_id + '/indexes/sd/' + progress
                else:
                    bif_thumb = ''
            else:
                indexes = ''
                bif_thumb = ''

            if plexpy.CONFIG.PMS_USE_BIF and indexes == 'sd':
                use_indexes = 1
            else:
                use_indexes = 0

            user_details = data_factory.get_user_details(
                user=helpers.get_xml_attr(session.getElementsByTagName('User')[0], 'title'))

            if helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'machineIdentifier').endswith('_Video'):
                machine_id = helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'machineIdentifier')[:-6]
            else:
                machine_id = helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'machineIdentifier')

            if helpers.get_xml_attr(session, 'type') == 'episode':
                session_output = {'session_key': helpers.get_xml_attr(session, 'sessionKey'),
                                  'media_index': helpers.get_xml_attr(session, 'index'),
                                  'parent_media_index': helpers.get_xml_attr(session, 'parentIndex'),
                                  'art': helpers.get_xml_attr(session, 'art'),
                                  'parent_thumb': helpers.get_xml_attr(session, 'parentThumb'),
                                  'grandparent_thumb': helpers.get_xml_attr(session, 'grandparentThumb'),
                                  'thumb': helpers.get_xml_attr(session, 'thumb'),
                                  'bif_thumb': bif_thumb,
                                  'user': helpers.get_xml_attr(session.getElementsByTagName('User')[0], 'title'),
                                  'user_id': user_details['user_id'],
                                  'friendly_name': user_details['friendly_name'],
                                  'player': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'title'),
                                  'platform': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'platform'),
                                  'machine_id': machine_id,
                                  'state': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'state'),
                                  'grandparent_title': helpers.get_xml_attr(session, 'grandparentTitle'),
                                  'parent_title': helpers.get_xml_attr(session, 'parentTitle'),
                                  'title': helpers.get_xml_attr(session, 'title'),
                                  'rating_key': helpers.get_xml_attr(session, 'ratingKey'),
                                  'parent_rating_key': helpers.get_xml_attr(session, 'parentRatingKey'),
                                  'grandparent_rating_key': helpers.get_xml_attr(session, 'grandparentRatingKey'),
                                  'audio_decision': audio_decision,
                                  'audio_channels': audio_channels,
                                  'audio_codec': audio_codec,
                                  'video_decision': video_decision,
                                  'video_codec': video_codec,
                                  'height': height,
                                  'width': width,
                                  'container': container,
                                  'bitrate': bitrate,
                                  'video_resolution': video_resolution,
                                  'video_framerate': video_framerate,
                                  'aspect_ratio': aspect_ratio,
                                  'transcode_audio_channels': transcode_audio_channels,
                                  'transcode_audio_codec': transcode_audio_codec,
                                  'transcode_video_codec': transcode_video_codec,
                                  'transcode_width': transcode_width,
                                  'transcode_height': transcode_height,
                                  'transcode_container': transcode_container,
                                  'transcode_protocol': transcode_protocol,
                                  'duration': duration,
                                  'progress': progress,
                                  'progress_percent': str(helpers.get_percent(progress, duration)),
                                  'type': helpers.get_xml_attr(session, 'type'),
                                  'indexes': use_indexes
                                  }
            elif helpers.get_xml_attr(session, 'type') == 'movie':
                session_output = {'session_key': helpers.get_xml_attr(session, 'sessionKey'),
                                  'media_index': helpers.get_xml_attr(session, 'index'),
                                  'parent_media_index': helpers.get_xml_attr(session, 'parentIndex'),
                                  'art': helpers.get_xml_attr(session, 'art'),
                                  'thumb': helpers.get_xml_attr(session, 'thumb'),
                                  'bif_thumb': bif_thumb,
                                  'parent_thumb': helpers.get_xml_attr(session, 'parentThumb'),
                                  'grandparent_thumb': helpers.get_xml_attr(session, 'grandparentThumb'),
                                  'user': helpers.get_xml_attr(session.getElementsByTagName('User')[0], 'title'),
                                  'user_id': user_details['user_id'],
                                  'friendly_name': user_details['friendly_name'],
                                  'player': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'title'),
                                  'platform': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'platform'),
                                  'machine_id': machine_id,
                                  'state': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'state'),
                                  'grandparent_title': helpers.get_xml_attr(session, 'grandparentTitle'),
                                  'parent_title': helpers.get_xml_attr(session, 'parentTitle'),
                                  'title': helpers.get_xml_attr(session, 'title'),
                                  'rating_key': helpers.get_xml_attr(session, 'ratingKey'),
                                  'parent_rating_key': helpers.get_xml_attr(session, 'parentRatingKey'),
                                  'grandparent_rating_key': helpers.get_xml_attr(session, 'grandparentRatingKey'),
                                  'audio_decision': audio_decision,
                                  'audio_channels': audio_channels,
                                  'audio_codec': audio_codec,
                                  'video_decision': video_decision,
                                  'video_codec': video_codec,
                                  'height': height,
                                  'width': width,
                                  'container': container,
                                  'bitrate': bitrate,
                                  'video_resolution': video_resolution,
                                  'video_framerate': video_framerate,
                                  'aspect_ratio': aspect_ratio,
                                  'transcode_audio_channels': transcode_audio_channels,
                                  'transcode_audio_codec': transcode_audio_codec,
                                  'transcode_video_codec': transcode_video_codec,
                                  'transcode_width': transcode_width,
                                  'transcode_height': transcode_height,
                                  'transcode_container': transcode_container,
                                  'transcode_protocol': transcode_protocol,
                                  'duration': duration,
                                  'progress': progress,
                                  'progress_percent': str(helpers.get_percent(progress, duration)),
                                  'type': helpers.get_xml_attr(session, 'type'),
                                  'indexes': use_indexes
                                  }
            elif helpers.get_xml_attr(session, 'type') == 'clip':
                session_output = {'session_key': helpers.get_xml_attr(session, 'sessionKey'),
                                  'media_index': helpers.get_xml_attr(session, 'index'),
                                  'parent_media_index': helpers.get_xml_attr(session, 'parentIndex'),
                                  'art': helpers.get_xml_attr(session, 'art'),
                                  'thumb': helpers.get_xml_attr(session, 'thumb'),
                                  'bif_thumb': bif_thumb,
                                  'parent_thumb': helpers.get_xml_attr(session, 'parentThumb'),
                                  'grandparent_thumb': helpers.get_xml_attr(session, 'grandparentThumb'),
                                  'user': helpers.get_xml_attr(session.getElementsByTagName('User')[0], 'title'),
                                  'user_id': user_details['user_id'],
                                  'friendly_name': user_details['friendly_name'],
                                  'player': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'title'),
                                  'platform': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'platform'),
                                  'machine_id': machine_id,
                                  'state': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'state'),
                                  'grandparent_title': helpers.get_xml_attr(session, 'grandparentTitle'),
                                  'parent_title': helpers.get_xml_attr(session, 'parentTitle'),
                                  'title': helpers.get_xml_attr(session, 'title'),
                                  'rating_key': helpers.get_xml_attr(session, 'ratingKey'),
                                  'parent_rating_key': helpers.get_xml_attr(session, 'parentRatingKey'),
                                  'grandparent_rating_key': helpers.get_xml_attr(session, 'grandparentRatingKey'),
                                  'audio_decision': audio_decision,
                                  'audio_channels': audio_channels,
                                  'audio_codec': audio_codec,
                                  'video_decision': video_decision,
                                  'video_codec': video_codec,
                                  'height': height,
                                  'width': width,
                                  'container': container,
                                  'bitrate': bitrate,
                                  'video_resolution': video_resolution,
                                  'video_framerate': video_framerate,
                                  'aspect_ratio': aspect_ratio,
                                  'transcode_audio_channels': transcode_audio_channels,
                                  'transcode_audio_codec': transcode_audio_codec,
                                  'transcode_video_codec': transcode_video_codec,
                                  'transcode_width': transcode_width,
                                  'transcode_height': transcode_height,
                                  'transcode_container': transcode_container,
                                  'transcode_protocol': transcode_protocol,
                                  'duration': duration,
                                  'progress': progress,
                                  'progress_percent': str(helpers.get_percent(progress, duration)),
                                  'type': helpers.get_xml_attr(session, 'type'),
                                  'indexes': 0
                                  }
        else:
            logger.warn(u"No known stream types found in session list.")

        return session_output
Beispiel #26
0
def check_active_sessions(ws_request=False):

    with monitor_lock:
        pms_connect = pmsconnect.PmsConnect()
        session_list = pms_connect.get_current_activity()
        monitor_db = database.MonitorDatabase()
        monitor_process = activity_processor.ActivityProcessor()
        # logger.debug(u"PlexPy Monitor :: Checking for active streams.")

        if session_list:
            media_container = session_list['sessions']

            # Check our temp table for what we must do with the new streams
            db_streams = monitor_db.select(
                'SELECT started, session_key, rating_key, media_type, title, parent_title, '
                'grandparent_title, user_id, user, friendly_name, ip_address, player, '
                'platform, machine_id, parent_rating_key, grandparent_rating_key, state, '
                'view_offset, duration, video_decision, audio_decision, width, height, '
                'container, video_codec, audio_codec, bitrate, video_resolution, '
                'video_framerate, aspect_ratio, audio_channels, transcode_protocol, '
                'transcode_container, transcode_video_codec, transcode_audio_codec, '
                'transcode_audio_channels, transcode_width, transcode_height, '
                'paused_counter, last_paused '
                'FROM sessions')
            for stream in db_streams:
                if any(d['session_key'] == str(stream['session_key'])
                       and d['rating_key'] == str(stream['rating_key'])
                       for d in media_container):
                    # The user's session is still active
                    for session in media_container:
                        if session['session_key'] == str(stream['session_key']) and \
                                session['rating_key'] == str(stream['rating_key']):
                            # The user is still playing the same media item
                            # Here we can check the play states
                            if session['state'] != stream['state']:
                                if session['state'] == 'paused':
                                    # Push any notifications -
                                    # Push it on it's own thread so we don't hold up our db actions
                                    threading.Thread(
                                        target=notification_handler.notify,
                                        kwargs=dict(
                                            stream_data=stream,
                                            notify_action='pause')).start()

                                if session['state'] == 'playing' and stream[
                                        'state'] == 'paused':
                                    # Push any notifications -
                                    # Push it on it's own thread so we don't hold up our db actions
                                    threading.Thread(
                                        target=notification_handler.notify,
                                        kwargs=dict(
                                            stream_data=stream,
                                            notify_action='resume')).start()

                            if stream['state'] == 'paused' and not ws_request:
                                # The stream is still paused so we need to increment the paused_counter
                                # Using the set config parameter as the interval, probably not the most accurate but
                                # it will have to do for now. If it's a websocket request don't use this method.
                                paused_counter = int(
                                    stream['paused_counter']
                                ) + plexpy.CONFIG.MONITORING_INTERVAL
                                monitor_db.action(
                                    'UPDATE sessions SET paused_counter = ? '
                                    'WHERE session_key = ? AND rating_key = ?',
                                    [
                                        paused_counter, stream['session_key'],
                                        stream['rating_key']
                                    ])

                            if session[
                                    'state'] == 'buffering' and plexpy.CONFIG.BUFFER_THRESHOLD > 0:
                                # The stream is buffering so we need to increment the buffer_count
                                # We're going just increment on every monitor ping,
                                # would be difficult to keep track otherwise
                                monitor_db.action(
                                    'UPDATE sessions SET buffer_count = buffer_count + 1 '
                                    'WHERE session_key = ? AND rating_key = ?',
                                    [
                                        stream['session_key'],
                                        stream['rating_key']
                                    ])

                                # Check the current buffer count and last buffer to determine if we should notify
                                buffer_values = monitor_db.select(
                                    'SELECT buffer_count, buffer_last_triggered '
                                    'FROM sessions '
                                    'WHERE session_key = ? AND rating_key = ?',
                                    [
                                        stream['session_key'],
                                        stream['rating_key']
                                    ])

                                if buffer_values[0][
                                        'buffer_count'] >= plexpy.CONFIG.BUFFER_THRESHOLD:
                                    # Push any notifications -
                                    # Push it on it's own thread so we don't hold up our db actions
                                    # Our first buffer notification
                                    if buffer_values[0][
                                            'buffer_count'] == plexpy.CONFIG.BUFFER_THRESHOLD:
                                        logger.info(
                                            u"PlexPy Monitor :: User '%s' has triggered a buffer warning."
                                            % stream['user'])
                                        # Set the buffer trigger time
                                        monitor_db.action(
                                            'UPDATE sessions '
                                            'SET buffer_last_triggered = strftime("%s","now") '
                                            'WHERE session_key = ? AND rating_key = ?',
                                            [
                                                stream['session_key'],
                                                stream['rating_key']
                                            ])

                                        threading.Thread(
                                            target=notification_handler.notify,
                                            kwargs=dict(stream_data=stream,
                                                        notify_action='buffer'
                                                        )).start()
                                    else:
                                        # Subsequent buffer notifications after wait time
                                        if int(time.time()) > buffer_values[0]['buffer_last_triggered'] + \
                                                plexpy.CONFIG.BUFFER_WAIT:
                                            logger.info(
                                                u"PlexPy Monitor :: User '%s' has triggered multiple buffer warnings."
                                                % stream['user'])
                                            # Set the buffer trigger time
                                            monitor_db.action(
                                                'UPDATE sessions '
                                                'SET buffer_last_triggered = strftime("%s","now") '
                                                'WHERE session_key = ? AND rating_key = ?',
                                                [
                                                    stream['session_key'],
                                                    stream['rating_key']
                                                ])

                                            threading.Thread(
                                                target=notification_handler.
                                                notify,
                                                kwargs=dict(
                                                    stream_data=stream,
                                                    notify_action='buffer'
                                                )).start()

                                logger.debug(
                                    u"PlexPy Monitor :: Stream buffering. Count is now %s. Last triggered %s."
                                    %
                                    (buffer_values[0][0], buffer_values[0][1]))

                            # Check if the user has reached the offset in the media we defined as the "watched" percent
                            # Don't trigger if state is buffer as some clients push the progress to the end when
                            # buffering on start.
                            if session['view_offset'] and session[
                                    'duration'] and session[
                                        'state'] != 'buffering':
                                if helpers.get_percent(
                                        session['view_offset'],
                                        session['duration']
                                ) > plexpy.CONFIG.NOTIFY_WATCHED_PERCENT:
                                    # Push any notifications -
                                    # Push it on it's own thread so we don't hold up our db actions
                                    threading.Thread(
                                        target=notification_handler.notify,
                                        kwargs=dict(
                                            stream_data=stream,
                                            notify_action='watched')).start()

                else:
                    # The user has stopped playing a stream
                    logger.debug(
                        u"PlexPy Monitor :: Removing sessionKey %s ratingKey %s from session queue"
                        % (stream['session_key'], stream['rating_key']))
                    monitor_db.action(
                        'DELETE FROM sessions WHERE session_key = ? AND rating_key = ?',
                        [stream['session_key'], stream['rating_key']])

                    # Check if the user has reached the offset in the media we defined as the "watched" percent
                    if stream['view_offset'] and stream['duration']:
                        if helpers.get_percent(
                                stream['view_offset'], stream['duration']
                        ) > plexpy.CONFIG.NOTIFY_WATCHED_PERCENT:
                            # Push any notifications -
                            # Push it on it's own thread so we don't hold up our db actions
                            threading.Thread(
                                target=notification_handler.notify,
                                kwargs=dict(stream_data=stream,
                                            notify_action='watched')).start()

                    # Push any notifications - Push it on it's own thread so we don't hold up our db actions
                    threading.Thread(target=notification_handler.notify,
                                     kwargs=dict(
                                         stream_data=stream,
                                         notify_action='stop')).start()

                    # Write the item history on playback stop
                    monitor_process.write_session_history(session=stream)

            # Process the newly received session data
            for session in media_container:
                monitor_process.write_session(session)
        else:
            logger.debug(u"PlexPy Monitor :: Unable to read session list.")
def build_notify_text(session, state):
    from plexpy import pmsconnect, helpers
    import re

    # Get the server name
    pms_connect = pmsconnect.PmsConnect()
    server_name = pms_connect.get_server_pref(pref='FriendlyName')

    # Get metadata feed for item
    metadata = pms_connect.get_metadata_details(rating_key=session['rating_key'])

    if metadata:
        item_metadata = metadata['metadata']
    else:
        logger.error(u"PlexPy Notifier :: Unable to retrieve metadata for rating_key %s" % str(session['rating_key']))
        return []

    # Check for exclusion tags
    if session['media_type'] == 'episode':
        # Regex pattern to remove the text in the tags we don't want
        pattern = re.compile('<movie>[^>]+.</movie>|<music>[^>]+.</music>', re.IGNORECASE)
    elif session['media_type'] == 'movie':
        # Regex pattern to remove the text in the tags we don't want
        pattern = re.compile('<tv>[^>]+.</tv>|<music>[^>]+.</music>', re.IGNORECASE)
    elif session['media_type'] == 'track':
        # Regex pattern to remove the text in the tags we don't want
        pattern = re.compile('<tv>[^>]+.</tv>|<movie>[^>]+.</movie>', re.IGNORECASE)
    else:
        pattern = None

    if session['media_type'] == 'episode' or session['media_type'] == 'movie' or session['media_type'] == 'track' \
            and pattern:
        # Remove the unwanted tags and strip any unmatch tags too.
        on_start_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_START_SUBJECT_TEXT))
        on_start_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_START_BODY_TEXT))
        on_stop_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_STOP_SUBJECT_TEXT))
        on_stop_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_STOP_BODY_TEXT))
        on_pause_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_PAUSE_SUBJECT_TEXT))
        on_pause_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_PAUSE_BODY_TEXT))
        on_resume_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_RESUME_SUBJECT_TEXT))
        on_resume_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_RESUME_BODY_TEXT))
        on_buffer_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_BUFFER_SUBJECT_TEXT))
        on_buffer_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_BUFFER_BODY_TEXT))
        on_watched_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_WATCHED_SUBJECT_TEXT))
        on_watched_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_WATCHED_BODY_TEXT))
    else:
        on_start_subject = plexpy.CONFIG.NOTIFY_ON_START_SUBJECT_TEXT
        on_start_body = plexpy.CONFIG.NOTIFY_ON_START_BODY_TEXT
        on_stop_subject = plexpy.CONFIG.NOTIFY_ON_STOP_SUBJECT_TEXT
        on_stop_body = plexpy.CONFIG.NOTIFY_ON_STOP_BODY_TEXT
        on_pause_subject = plexpy.CONFIG.NOTIFY_ON_PAUSE_SUBJECT_TEXT
        on_pause_body = plexpy.CONFIG.NOTIFY_ON_PAUSE_BODY_TEXT
        on_resume_subject = plexpy.CONFIG.NOTIFY_ON_RESUME_SUBJECT_TEXT
        on_resume_body = plexpy.CONFIG.NOTIFY_ON_RESUME_BODY_TEXT
        on_buffer_subject = plexpy.CONFIG.NOTIFY_ON_BUFFER_SUBJECT_TEXT
        on_buffer_body = plexpy.CONFIG.NOTIFY_ON_BUFFER_BODY_TEXT
        on_watched_subject = plexpy.CONFIG.NOTIFY_ON_WATCHED_SUBJECT_TEXT
        on_watched_body = plexpy.CONFIG.NOTIFY_ON_WATCHED_BODY_TEXT

    # Create a title
    if session['media_type'] == 'episode':
        full_title = '%s - %s' % (session['grandparent_title'],
                                  session['title'])
    elif session['media_type'] == 'track':
        full_title = '%s - %s' % (session['grandparent_title'],
                                  session['title'])
    else:
        full_title = session['title']

    # Generate a combined transcode decision value
    if session['video_decision']:
        if session['video_decision'] == 'transcode':
            transcode_decision = 'Transcode'
        elif session['video_decision'] == 'copy' or session['audio_decision'] == 'copy':
            transcode_decision = 'Direct Stream'
        else:
            transcode_decision = 'Direct Play'
    else:
        if session['audio_decision'] == 'transcode':
            transcode_decision = 'Transcode'
        else:
            transcode_decision = 'Direct Play'

    duration = helpers.convert_milliseconds_to_minutes(item_metadata['duration'])
    view_offset = helpers.convert_milliseconds_to_minutes(session['view_offset'])
    stream_duration = 0
    if state != 'play':
        if session['paused_counter']:
            stream_duration = int((time.time() - helpers.cast_to_float(session['started']) -
                                   helpers.cast_to_float(session['paused_counter'])) / 60)
        else:
            stream_duration = int((time.time() - helpers.cast_to_float(session['started'])) / 60)

    progress_percent = helpers.get_percent(view_offset, duration)

    available_params = {'server_name': server_name,
                        'user': session['friendly_name'],
                        'player': session['player'],
                        'title': full_title,
                        'show_name': item_metadata['grandparent_title'],
                        'episode_name': item_metadata['title'],
                        'platform': session['platform'],
                        'media_type': session['media_type'],
                        'transcode_decision': transcode_decision,
                        'year': item_metadata['year'],
                        'studio': item_metadata['studio'],
                        'content_rating': item_metadata['content_rating'],
                        'summary': item_metadata['summary'],
                        'season_num': item_metadata['parent_index'],
                        'season_num00': item_metadata['parent_index'].zfill(2),
                        'episode_num': item_metadata['index'],
                        'episode_num00': item_metadata['index'].zfill(2),
                        'album_name': item_metadata['parent_title'],
                        'rating': item_metadata['rating'],
                        'duration': duration,
                        'stream_duration': stream_duration,
                        'progress': view_offset,
                        'progress_percent': progress_percent
                        }

    # Default subject text
    subject_text = 'PlexPy (%s)' % server_name

    if state == 'play':
        # Default body text
        body_text = '%s (%s) is watching %s' % (session['friendly_name'],
                                                session['player'],
                                                full_title)

        if on_start_subject and on_start_body:
            try:
                subject_text = unicode(on_start_subject).format(**available_params)
            except LookupError, e:
                logger.error(u"PlexPy Notifier :: Unable to parse field %s in notification subject. Using fallback." % e)
            except:
Beispiel #28
0
                        sync_title = helpers.get_xml_attr(item, "title")
                        sync_metadata_type = helpers.get_xml_attr(item, "metadataType")
                        sync_content_type = helpers.get_xml_attr(item, "contentType")

                        for status in item.getElementsByTagName("Status"):
                            status_failure_code = helpers.get_xml_attr(status, "failureCode")
                            status_failure = helpers.get_xml_attr(status, "failure")
                            status_state = helpers.get_xml_attr(status, "state")
                            status_item_count = helpers.get_xml_attr(status, "itemsCount")
                            status_item_complete_count = helpers.get_xml_attr(status, "itemsCompleteCount")
                            status_item_downloaded_count = helpers.get_xml_attr(status, "itemsDownloadedCount")
                            status_item_ready_count = helpers.get_xml_attr(status, "itemsReadyCount")
                            status_item_successful_count = helpers.get_xml_attr(status, "itemsSuccessfulCount")
                            status_total_size = helpers.get_xml_attr(status, "totalSize")
                            status_item_download_percent_complete = helpers.get_percent(
                                status_item_downloaded_count, status_item_count
                            )

                        for settings in item.getElementsByTagName("MediaSettings"):
                            settings_audio_boost = helpers.get_xml_attr(settings, "audioBoost")
                            settings_music_bitrate = helpers.get_xml_attr(settings, "musicBitrate")
                            settings_photo_quality = helpers.get_xml_attr(settings, "photoQuality")
                            settings_photo_resolution = helpers.get_xml_attr(settings, "photoResolution")
                            settings_video_quality = helpers.get_xml_attr(settings, "videoQuality")
                            settings_video_resolution = helpers.get_xml_attr(settings, "videoResolution")

                        if helpers.get_xml_attr(item.getElementsByTagName("Location")[0], "uri").endswith(
                            "%2Fchildren"
                        ):
                            clean_uri = helpers.get_xml_attr(item.getElementsByTagName("Location")[0], "uri")[:-11]
                        else:
Beispiel #29
0
def build_notify_text(session=None, timeline=None, state=None):
    # Get the server name
    server_name = plexpy.CONFIG.PMS_NAME

    # Get the server uptime
    plex_tv = plextv.PlexTV()
    server_times = plex_tv.get_server_times()

    if server_times:
        updated_at = server_times[0]['updated_at']
        server_uptime = helpers.human_duration(int(time.time() - helpers.cast_to_float(updated_at)))
    else:
        logger.error(u"PlexPy NotificationHandler :: Unable to retrieve server uptime.")
        server_uptime = 'N/A'

    # Get metadata feed for item
    if session:
        rating_key = session['rating_key']
    elif timeline:
        rating_key = timeline['rating_key']

    pms_connect = pmsconnect.PmsConnect()
    metadata_list = pms_connect.get_metadata_details(rating_key=rating_key)

    stream_count = pms_connect.get_current_activity().get('stream_count', '')

    if metadata_list:
        metadata = metadata_list['metadata']
    else:
        logger.error(u"PlexPy NotificationHandler :: Unable to retrieve metadata for rating_key %s" % str(rating_key))
        return []

    # Check for exclusion tags
    if metadata['media_type'] == 'movie':
        # Regex pattern to remove the text in the tags we don't want
        pattern = re.compile('\n*<tv>[^>]+.</tv>\n*|\n*<music>[^>]+.</music>\n*', re.IGNORECASE | re.DOTALL)
    elif metadata['media_type'] == 'show' or metadata['media_type'] == 'episode':
        # Regex pattern to remove the text in the tags we don't want
        pattern = re.compile('\n*<movie>[^>]+.</movie>\n*|\n*?<music>[^>]+.</music>\n*', re.IGNORECASE | re.DOTALL)
    elif metadata['media_type'] == 'artist' or metadata['media_type'] == 'track':
        # Regex pattern to remove the text in the tags we don't want
        pattern = re.compile('\n*<tv>[^>]+.</tv>\n*|\n*<movie>[^>]+.</movie>\n*', re.IGNORECASE | re.DOTALL)
    else:
        pattern = None

    if metadata['media_type'] == 'movie' \
        or metadata['media_type'] == 'show' or metadata['media_type'] == 'episode' \
        or metadata['media_type'] == 'artist' or metadata['media_type'] == 'track' \
        and pattern:
        # Remove the unwanted tags and strip any unmatch tags too.
        on_start_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_START_SUBJECT_TEXT))
        on_start_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_START_BODY_TEXT))
        on_stop_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_STOP_SUBJECT_TEXT))
        on_stop_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_STOP_BODY_TEXT))
        on_pause_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_PAUSE_SUBJECT_TEXT))
        on_pause_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_PAUSE_BODY_TEXT))
        on_resume_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_RESUME_SUBJECT_TEXT))
        on_resume_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_RESUME_BODY_TEXT))
        on_buffer_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_BUFFER_SUBJECT_TEXT))
        on_buffer_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_BUFFER_BODY_TEXT))
        on_watched_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_WATCHED_SUBJECT_TEXT))
        on_watched_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_WATCHED_BODY_TEXT))
        on_created_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_CREATED_SUBJECT_TEXT))
        on_created_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_CREATED_BODY_TEXT))
        script_args_text = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_SCRIPTS_ARGS_TEXT))
    else:
        on_start_subject = plexpy.CONFIG.NOTIFY_ON_START_SUBJECT_TEXT
        on_start_body = plexpy.CONFIG.NOTIFY_ON_START_BODY_TEXT
        on_stop_subject = plexpy.CONFIG.NOTIFY_ON_STOP_SUBJECT_TEXT
        on_stop_body = plexpy.CONFIG.NOTIFY_ON_STOP_BODY_TEXT
        on_pause_subject = plexpy.CONFIG.NOTIFY_ON_PAUSE_SUBJECT_TEXT
        on_pause_body = plexpy.CONFIG.NOTIFY_ON_PAUSE_BODY_TEXT
        on_resume_subject = plexpy.CONFIG.NOTIFY_ON_RESUME_SUBJECT_TEXT
        on_resume_body = plexpy.CONFIG.NOTIFY_ON_RESUME_BODY_TEXT
        on_buffer_subject = plexpy.CONFIG.NOTIFY_ON_BUFFER_SUBJECT_TEXT
        on_buffer_body = plexpy.CONFIG.NOTIFY_ON_BUFFER_BODY_TEXT
        on_watched_subject = plexpy.CONFIG.NOTIFY_ON_WATCHED_SUBJECT_TEXT
        on_watched_body = plexpy.CONFIG.NOTIFY_ON_WATCHED_BODY_TEXT
        on_created_subject = plexpy.CONFIG.NOTIFY_ON_CREATED_SUBJECT_TEXT
        on_created_body = plexpy.CONFIG.NOTIFY_ON_CREATED_BODY_TEXT
        script_args_text = plexpy.CONFIG.NOTIFY_SCRIPTS_ARGS_TEXT

    # Create a title
    if metadata['media_type'] == 'episode' or metadata['media_type'] == 'track':
        full_title = '%s - %s' % (metadata['grandparent_title'],
                                  metadata['title'])
    else:
        full_title = metadata['title']

    duration = helpers.convert_milliseconds_to_minutes(metadata['duration'])

    # Default values
    user = ''
    platform = ''
    player = ''
    ip_address = 'N/A'
    stream_duration = 0
    view_offset = 0
    container = ''
    video_codec = ''
    video_bitrate = ''
    video_width = ''
    video_height = ''
    video_resolution = ''
    video_framerate = ''
    aspect_ratio = ''
    audio_codec = ''
    audio_channels = ''
    transcode_decision = ''
    video_decision = ''
    audio_decision = ''
    transcode_container = ''
    transcode_video_codec = ''
    transcode_video_width = ''
    transcode_video_height = ''
    transcode_audio_codec = ''
    transcode_audio_channels = ''

    # Session values
    if session:
        # Generate a combined transcode decision value
        video_decision = session['video_decision'].title()
        audio_decision = session['audio_decision'].title()

        if session['video_decision'] == 'transcode' or session['audio_decision'] == 'transcode':
            transcode_decision = 'Transcode'
        elif session['video_decision'] == 'copy' or session['audio_decision'] == 'copy':
            transcode_decision = 'Direct Stream'
        else:
            transcode_decision = 'Direct Play'

        if state != 'play':
            if session['paused_counter']:
                stream_duration = int((time.time() - helpers.cast_to_float(session['started']) -
                                       helpers.cast_to_float(session['paused_counter'])) / 60)
            else:
                stream_duration = int((time.time() - helpers.cast_to_float(session['started'])) / 60)

        view_offset = helpers.convert_milliseconds_to_minutes(session['view_offset'])
        user = session['friendly_name']
        platform = session['platform']
        player = session['player']
        ip_address = session['ip_address'] if session['ip_address'] else 'N/A'
        container = session['container']
        video_codec = session['video_codec']
        video_bitrate = session['bitrate']
        video_width = session['width']
        video_height = session['height']
        video_resolution = session['video_resolution']
        video_framerate = session['video_framerate']
        aspect_ratio = session['aspect_ratio']
        audio_codec = session['audio_codec']
        audio_channels = session['audio_channels']
        transcode_container = session['transcode_container']
        transcode_video_codec = session['transcode_video_codec']
        transcode_video_width = session['transcode_width']
        transcode_video_height = session['transcode_height']
        transcode_audio_codec = session['transcode_audio_codec']
        transcode_audio_channels = session['transcode_audio_channels']

    progress_percent = helpers.get_percent(view_offset, duration)

    # Fix metadata params for notify recently added grandparent
    if state == 'created' and plexpy.CONFIG.NOTIFY_RECENTLY_ADDED_GRANDPARENT:
        show_name = metadata['title']
        episode_name = ''
        artist_name = metadata['title']
        album_name = ''
        track_name = ''
    else:
        show_name = metadata['grandparent_title']
        episode_name = metadata['title']
        artist_name = metadata['grandparent_title']
        album_name = metadata['parent_title']
        track_name = metadata['title']

    available_params = {'server_name': server_name,
                        'server_uptime': server_uptime,
                        'streams': stream_count,
                        'action': state,
                        'datestamp': arrow.now().format(plexpy.CONFIG.DATE_FORMAT.replace('Do','').replace('zz','')),
                        'timestamp': arrow.now().format(plexpy.CONFIG.TIME_FORMAT.replace('Do','').replace('zz','')),
                        'user': user,
                        'platform': platform,
                        'player': player,
                        'ip_address': ip_address,
                        'media_type': metadata['media_type'],
                        'stream_duration': stream_duration,
                        'remaining_duration': duration - view_offset,
                        'progress': view_offset,
                        'progress_percent': progress_percent,
                        'container': container,
                        'video_codec': video_codec,
                        'video_bitrate': video_bitrate,
                        'video_width': video_width,
                        'video_height': video_height,
                        'video_resolution': video_resolution,
                        'video_framerate': video_framerate,
                        'aspect_ratio': aspect_ratio,
                        'audio_codec': audio_codec,
                        'audio_channels': audio_channels,
                        'transcode_decision': transcode_decision,
                        'video_decision': video_decision,
                        'audio_decision': audio_decision,
                        'transcode_container': transcode_container,
                        'transcode_video_codec': transcode_video_codec,
                        'transcode_video_width': transcode_video_width,
                        'transcode_video_height': transcode_video_height,
                        'transcode_audio_codec': transcode_audio_codec,
                        'transcode_audio_channels': transcode_audio_channels,
                        'title': full_title,
                        'library_name': metadata['library_name'],
                        'show_name': show_name,
                        'episode_name': episode_name,
                        'artist_name': artist_name,
                        'album_name': album_name,
                        'track_name': track_name,
                        'season_num': metadata['parent_media_index'].zfill(1),
                        'season_num00': metadata['parent_media_index'].zfill(2),
                        'episode_num': metadata['media_index'].zfill(1),
                        'episode_num00': metadata['media_index'].zfill(2),
                        'year': metadata['year'],
                        'studio': metadata['studio'],
                        'content_rating': metadata['content_rating'],
                        'directors': ', '.join(metadata['directors']),
                        'writers': ', '.join(metadata['writers']),
                        'actors': ', '.join(metadata['actors']),
                        'genres': ', '.join(metadata['genres']),
                        'summary': metadata['summary'],
                        'tagline': metadata['tagline'],
                        'rating': metadata['rating'],
                        'duration': duration
                        }

    # Default subject text
    subject_text = 'PlexPy (%s)' % server_name

    # Default scripts args
    script_args = []

    # Regex to match {param} but not "{param}"
    params_to_quote = re.compile(r'(?<!\")([\{][^}]+[\}])(?!\"\})')
    script_args_text = re.sub(params_to_quote, r'"\g<0>"', script_args_text)

    if script_args_text:
        try:
            script_args = [unicode(arg).format(**available_params) for arg in script_args_text.split()]
        except LookupError as e:
            logger.error(u"PlexPy Notifier :: Unable to parse field %s in script argument. Using fallback." % e)
        except Exception as e:
            logger.error(u"PlexPy Notifier :: Unable to parse custom script arguments %s. Using fallback." % e)

    if state == 'play':
        # Default body text
        body_text = '%s (%s) is watching %s' % (session['friendly_name'],
                                                session['player'],
                                                full_title)

        if on_start_subject and on_start_body:
            try:
                subject_text = unicode(on_start_subject).format(**available_params)
            except LookupError, e:
                logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification subject. Using fallback." % e)
            except:
Beispiel #30
0
def build_notify_text(session=None, timeline=None, state=None):
    import re

    # Get the server name
    server_name = plexpy.CONFIG.PMS_NAME

    # Get the server uptime
    plex_tv = plextv.PlexTV()
    server_times = plex_tv.get_server_times()

    if server_times:
        updated_at = server_times[0]['updated_at']
        server_uptime = helpers.human_duration(int(time.time() - helpers.cast_to_float(updated_at)))
    else:
        logger.error(u"PlexPy Notifier :: Unable to retrieve server uptime.")
        server_uptime = 'N/A'

    # Get metadata feed for item
    if session:
        rating_key = session['rating_key']
    elif timeline:
        rating_key = timeline['rating_key']

    pms_connect = pmsconnect.PmsConnect()
    metadata_list = pms_connect.get_metadata_details(rating_key=rating_key)

    if metadata_list:
        metadata = metadata_list['metadata']
    else:
        logger.error(u"PlexPy Notifier :: Unable to retrieve metadata for rating_key %s" % str(rating_key))
        return []

    # Check for exclusion tags
    if metadata['media_type'] == 'movie':
        # Regex pattern to remove the text in the tags we don't want
        pattern = re.compile('<tv>[^>]+.</tv>|<music>[^>]+.</music>', re.IGNORECASE)
    elif metadata['media_type'] == 'show' or metadata['media_type'] == 'episode':
        # Regex pattern to remove the text in the tags we don't want
        pattern = re.compile('<movie>[^>]+.</movie>|<music>[^>]+.</music>', re.IGNORECASE)
    elif metadata['media_type'] == 'artist' or metadata['media_type'] == 'track':
        # Regex pattern to remove the text in the tags we don't want
        pattern = re.compile('<tv>[^>]+.</tv>|<movie>[^>]+.</movie>', re.IGNORECASE)
    else:
        pattern = None

    if metadata['media_type'] == 'movie' \
        or metadata['media_type'] == 'show' or metadata['media_type'] == 'episode' \
        or metadata['media_type'] == 'artist' or metadata['media_type'] == 'track' \
        and pattern:
        # Remove the unwanted tags and strip any unmatch tags too.
        on_start_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_START_SUBJECT_TEXT))
        on_start_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_START_BODY_TEXT))
        on_stop_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_STOP_SUBJECT_TEXT))
        on_stop_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_STOP_BODY_TEXT))
        on_pause_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_PAUSE_SUBJECT_TEXT))
        on_pause_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_PAUSE_BODY_TEXT))
        on_resume_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_RESUME_SUBJECT_TEXT))
        on_resume_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_RESUME_BODY_TEXT))
        on_buffer_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_BUFFER_SUBJECT_TEXT))
        on_buffer_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_BUFFER_BODY_TEXT))
        on_watched_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_WATCHED_SUBJECT_TEXT))
        on_watched_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_WATCHED_BODY_TEXT))
        on_created_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_CREATED_SUBJECT_TEXT))
        on_created_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_CREATED_BODY_TEXT))
    else:
        on_start_subject = plexpy.CONFIG.NOTIFY_ON_START_SUBJECT_TEXT
        on_start_body = plexpy.CONFIG.NOTIFY_ON_START_BODY_TEXT
        on_stop_subject = plexpy.CONFIG.NOTIFY_ON_STOP_SUBJECT_TEXT
        on_stop_body = plexpy.CONFIG.NOTIFY_ON_STOP_BODY_TEXT
        on_pause_subject = plexpy.CONFIG.NOTIFY_ON_PAUSE_SUBJECT_TEXT
        on_pause_body = plexpy.CONFIG.NOTIFY_ON_PAUSE_BODY_TEXT
        on_resume_subject = plexpy.CONFIG.NOTIFY_ON_RESUME_SUBJECT_TEXT
        on_resume_body = plexpy.CONFIG.NOTIFY_ON_RESUME_BODY_TEXT
        on_buffer_subject = plexpy.CONFIG.NOTIFY_ON_BUFFER_SUBJECT_TEXT
        on_buffer_body = plexpy.CONFIG.NOTIFY_ON_BUFFER_BODY_TEXT
        on_watched_subject = plexpy.CONFIG.NOTIFY_ON_WATCHED_SUBJECT_TEXT
        on_watched_body = plexpy.CONFIG.NOTIFY_ON_WATCHED_BODY_TEXT
        on_created_subject = plexpy.CONFIG.NOTIFY_ON_CREATED_SUBJECT_TEXT
        on_created_body = plexpy.CONFIG.NOTIFY_ON_CREATED_BODY_TEXT

    # Create a title
    if metadata['media_type'] == 'episode' or metadata['media_type'] == 'track':
        full_title = '%s - %s' % (metadata['grandparent_title'],
                                  metadata['title'])
    else:
        full_title = metadata['title']

    duration = helpers.convert_milliseconds_to_minutes(metadata['duration'])

    # Default values
    video_decision = ''
    audio_decision = ''
    transcode_decision = ''
    stream_duration = 0
    view_offset = 0
    user = ''
    platform = ''
    player = ''
    ip_address = 'N/A'

    # Session values
    if session:
        # Generate a combined transcode decision value
        video_decision = session['video_decision'].title()
        audio_decision = session['audio_decision'].title()

        if session['video_decision'] == 'transcode' or session['audio_decision'] == 'transcode':
            transcode_decision = 'Transcode'
        elif session['video_decision'] == 'copy' or session['audio_decision'] == 'copy':
            transcode_decision = 'Direct Stream'
        else:
            transcode_decision = 'Direct Play'

        if state != 'play':
            if session['paused_counter']:
                stream_duration = int((time.time() - helpers.cast_to_float(session['started']) -
                                       helpers.cast_to_float(session['paused_counter'])) / 60)
            else:
                stream_duration = int((time.time() - helpers.cast_to_float(session['started'])) / 60)

        view_offset = helpers.convert_milliseconds_to_minutes(session['view_offset'])
        user = session['friendly_name']
        platform = session['platform']
        player = session['player']
        ip_address = session['ip_address'] if session['ip_address'] else 'N/A'

    progress_percent = helpers.get_percent(view_offset, duration)

    available_params = {'server_name': server_name,
                        'server_uptime': server_uptime,
                        'user': user,
                        'platform': platform,
                        'player': player,
                        'ip_address': ip_address,
                        'media_type': metadata['media_type'],
                        'title': full_title,
                        'show_name': metadata['grandparent_title'],
                        'episode_name': metadata['title'],
                        'artist_name': metadata['grandparent_title'],
                        'album_name': metadata['parent_title'],
                        'track_name': metadata['title'],
                        'season_num': metadata['parent_index'].zfill(1),
                        'season_num00': metadata['parent_index'].zfill(2),
                        'episode_num': metadata['index'].zfill(1),
                        'episode_num00': metadata['index'].zfill(2),
                        'video_decision': video_decision,
                        'audio_decision': audio_decision,
                        'transcode_decision': transcode_decision,
                        'year': metadata['year'],
                        'studio': metadata['studio'],
                        'content_rating': metadata['content_rating'],
                        'directors': ', '.join(metadata['directors']),
                        'writers': ', '.join(metadata['writers']),
                        'actors': ', '.join(metadata['actors']),
                        'genres': ', '.join(metadata['genres']),
                        'summary': metadata['summary'],
                        'tagline': metadata['tagline'],
                        'rating': metadata['rating'],
                        'duration': duration,
                        'stream_duration': stream_duration,
                        'remaining_duration': duration - view_offset,
                        'progress': view_offset,
                        'progress_percent': progress_percent
                        }

    # Default subject text
    subject_text = 'PlexPy (%s)' % server_name

    if state == 'play':
        # Default body text
        body_text = '%s (%s) is watching %s' % (session['friendly_name'],
                                                session['player'],
                                                full_title)

        if on_start_subject and on_start_body:
            try:
                subject_text = unicode(on_start_subject).format(**available_params)
            except LookupError, e:
                logger.error(u"PlexPy Notifier :: Unable to parse field %s in notification subject. Using fallback." % e)
            except:
    def process(self):
        if self.is_valid_session():
            ap = activity_processor.ActivityProcessor(server=self.server)
            db_session = ap.get_session_by_key(session_key=self.get_session_key())

            this_state = self.timeline['state']
            this_rating_key = str(self.timeline['ratingKey'])
            this_key = self.timeline['key']
            this_transcode_key = self.timeline.get('transcodeSession', '')

            # Get the live tv session uuid
            this_live_uuid = this_key.split('/')[-1] if this_key.startswith('/livetv/sessions') else None

            # If we already have this session in the temp table, check for state changes
            if db_session:
                # Re-schedule the callback to reset the 5 minutes timer
                schedule_callback('session_key-{}-{}'.format(self.server.CONFIG.ID, self.get_session_key()),
                                  func=force_stop_stream,
                                  args=[self.get_session_key(), db_session['full_title'], db_session['user'], self.server.CONFIG.PMS_NAME, self.server],
                                  minutes=5)

                last_state = db_session['state']
                last_rating_key = str(db_session['rating_key'])
                last_live_uuid = db_session['live_uuid']
                last_transcode_key = db_session['transcode_key'].split('/')[-1]
                last_paused = db_session['last_paused']
                buffer_count = db_session['buffer_count']

                # Make sure the same item is being played
                if this_rating_key == last_rating_key or this_live_uuid == last_live_uuid:
                    # Update the session state and viewOffset
                    if this_state == 'playing':
                        # Update the session in our temp session table
                        # if the last set temporary stopped time exceeds 60 seconds
                        if int(time.time()) - db_session['stopped'] > 60:
                            self.update_db_session()

                    # Start our state checks
                    if this_state != last_state:
                        if this_state == 'paused':
                            self.on_pause()
                        elif last_paused and this_state == 'playing':
                            self.on_resume()
                        elif this_state == 'stopped':
                            self.on_stop()

                    elif this_state == 'paused':
                        # Update the session last_paused timestamp
                        self.on_pause(still_paused=True)

                    if this_state == 'buffering':
                        self.on_buffer()

                    if this_transcode_key != last_transcode_key and this_state != 'stopped':
                        self.on_change()

                # If a client doesn't register stop events (I'm looking at you PHT!) check if the ratingKey has changed
                else:
                    # Manually stop and start
                    # Set force_stop so that we don't overwrite our last viewOffset
                    self.on_stop(force_stop=True)
                    self.on_start()

                # Monitor if the stream has reached the watch percentage for notifications
                # The only purpose of this is for notifications
                if not db_session['watched'] and this_state != 'buffering':
                    progress_percent = helpers.get_percent(self.timeline['viewOffset'], db_session['duration'])
                    watched_percent = {'movie': plexpy.CONFIG.MOVIE_WATCHED_PERCENT,
                                       'episode': plexpy.CONFIG.TV_WATCHED_PERCENT,
                                       'track': plexpy.CONFIG.MUSIC_WATCHED_PERCENT,
                                       'clip': plexpy.CONFIG.TV_WATCHED_PERCENT
                                       }
                    if progress_percent >= watched_percent.get(db_session['media_type'], 101):
                        logger.debug(u"Tautulli ActivityHandler :: %s: Session %s watched."
                                     % (self.server.CONFIG.PMS_NAME, str(self.get_session_key())))
                        ap.set_watched(session_key=self.get_session_key())

                        watched_notifiers = notification_handler.get_notify_state_enabled(
                            session=db_session, notify_action='on_watched', notified=False)

                        for d in watched_notifiers:
                            plexpy.NOTIFY_QUEUE.put({'stream_data': db_session.copy(),
                                                     'notifier_id': d['notifier_id'],
                                                     'notify_action': 'on_watched'})

            else:
                # We don't have this session in our table yet, start a new one.
                if this_state != 'buffering':
                    self.on_start()