Example #1
0
    def process(self):
        if self.is_valid_session():
            from plexcs 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 >= plexcs.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()
Example #2
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"Plex:CS Monitor :: Checking for active streams.")

        global int_ping_count

        if session_list:
            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 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']) + plexcs.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 plexcs.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'] >= plexcs.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'] == plexcs.CONFIG.BUFFER_THRESHOLD:
                                        logger.info(u"Plex:CS 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'] + \
                                                plexcs.CONFIG.BUFFER_WAIT:
                                            logger.info(u"Plex:CS 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"Plex:CS 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']) > plexcs.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"Plex:CS 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']) > plexcs.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"Plex:CS Monitor :: Unable to read session list.")

            int_ping_count += 1
            logger.warn(u"Plex:CS 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()
Example #3
0
def build_notify_text(session=None, timeline=None, state=None):
    import re

    # Get the server name
    server_name = plexcs.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"Plex:CS 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"Plex:CS 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(
            '\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, '', plexcs.CONFIG.NOTIFY_ON_START_SUBJECT_TEXT))
        on_start_body = strip_tag(
            re.sub(pattern, '', plexcs.CONFIG.NOTIFY_ON_START_BODY_TEXT))
        on_stop_subject = strip_tag(
            re.sub(pattern, '', plexcs.CONFIG.NOTIFY_ON_STOP_SUBJECT_TEXT))
        on_stop_body = strip_tag(
            re.sub(pattern, '', plexcs.CONFIG.NOTIFY_ON_STOP_BODY_TEXT))
        on_pause_subject = strip_tag(
            re.sub(pattern, '', plexcs.CONFIG.NOTIFY_ON_PAUSE_SUBJECT_TEXT))
        on_pause_body = strip_tag(
            re.sub(pattern, '', plexcs.CONFIG.NOTIFY_ON_PAUSE_BODY_TEXT))
        on_resume_subject = strip_tag(
            re.sub(pattern, '', plexcs.CONFIG.NOTIFY_ON_RESUME_SUBJECT_TEXT))
        on_resume_body = strip_tag(
            re.sub(pattern, '', plexcs.CONFIG.NOTIFY_ON_RESUME_BODY_TEXT))
        on_buffer_subject = strip_tag(
            re.sub(pattern, '', plexcs.CONFIG.NOTIFY_ON_BUFFER_SUBJECT_TEXT))
        on_buffer_body = strip_tag(
            re.sub(pattern, '', plexcs.CONFIG.NOTIFY_ON_BUFFER_BODY_TEXT))
        on_watched_subject = strip_tag(
            re.sub(pattern, '', plexcs.CONFIG.NOTIFY_ON_WATCHED_SUBJECT_TEXT))
        on_watched_body = strip_tag(
            re.sub(pattern, '', plexcs.CONFIG.NOTIFY_ON_WATCHED_BODY_TEXT))
        on_created_subject = strip_tag(
            re.sub(pattern, '', plexcs.CONFIG.NOTIFY_ON_CREATED_SUBJECT_TEXT))
        on_created_body = strip_tag(
            re.sub(pattern, '', plexcs.CONFIG.NOTIFY_ON_CREATED_BODY_TEXT))
    else:
        on_start_subject = plexcs.CONFIG.NOTIFY_ON_START_SUBJECT_TEXT
        on_start_body = plexcs.CONFIG.NOTIFY_ON_START_BODY_TEXT
        on_stop_subject = plexcs.CONFIG.NOTIFY_ON_STOP_SUBJECT_TEXT
        on_stop_body = plexcs.CONFIG.NOTIFY_ON_STOP_BODY_TEXT
        on_pause_subject = plexcs.CONFIG.NOTIFY_ON_PAUSE_SUBJECT_TEXT
        on_pause_body = plexcs.CONFIG.NOTIFY_ON_PAUSE_BODY_TEXT
        on_resume_subject = plexcs.CONFIG.NOTIFY_ON_RESUME_SUBJECT_TEXT
        on_resume_body = plexcs.CONFIG.NOTIFY_ON_RESUME_BODY_TEXT
        on_buffer_subject = plexcs.CONFIG.NOTIFY_ON_BUFFER_SUBJECT_TEXT
        on_buffer_body = plexcs.CONFIG.NOTIFY_ON_BUFFER_BODY_TEXT
        on_watched_subject = plexcs.CONFIG.NOTIFY_ON_WATCHED_SUBJECT_TEXT
        on_watched_body = plexcs.CONFIG.NOTIFY_ON_WATCHED_BODY_TEXT
        on_created_subject = plexcs.CONFIG.NOTIFY_ON_CREATED_SUBJECT_TEXT
        on_created_body = plexcs.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 = 'Plex:CS (%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 as e:
                logger.error(
                    u"Plex:CS Notifier :: Unable to parse field %s in notification subject. Using fallback."
                    % e)
            except:
                logger.error(
                    u"Plex:CS Notifier :: Unable to parse custom notification subject. Using fallback."
                )

            try:
                body_text = unicode(on_start_body).format(**available_params)
            except LookupError as e:
                logger.error(
                    u"Plex:CS Notifier :: Unable to parse field %s in notification body. Using fallback."
                    % e)
            except:
                logger.error(
                    u"Plex:CS Notifier :: Unable to parse custom notification body. Using fallback."
                )

            return [subject_text, body_text]
        else:
            return [subject_text, body_text]
    elif state == 'stop':
        # Default body text
        body_text = '%s (%s) has stopped %s' % (session['friendly_name'],
                                                session['player'], full_title)

        if on_stop_subject and on_stop_body:
            try:
                subject_text = unicode(on_stop_subject).format(
                    **available_params)
            except LookupError as e:
                logger.error(
                    u"Plex:CS Notifier :: Unable to parse field %s in notification subject. Using fallback."
                    % e)
            except:
                logger.error(
                    u"Plex:CS Notifier :: Unable to parse custom notification subject. Using fallback."
                )

            try:
                body_text = unicode(on_stop_body).format(**available_params)
            except LookupError as e:
                logger.error(
                    u"Plex:CS Notifier :: Unable to parse field %s in notification body. Using fallback."
                    % e)
            except:
                logger.error(
                    u"Plex:CS Notifier :: Unable to parse custom notification body. Using fallback."
                )

            return [subject_text, body_text]
        else:
            return [subject_text, body_text]
    elif state == 'pause':
        # Default body text
        body_text = '%s (%s) has paused %s' % (session['friendly_name'],
                                               session['player'], full_title)

        if on_pause_subject and on_pause_body:
            try:
                subject_text = unicode(on_pause_subject).format(
                    **available_params)
            except LookupError as e:
                logger.error(
                    u"Plex:CS Notifier :: Unable to parse field %s in notification subject. Using fallback."
                    % e)
            except:
                logger.error(
                    u"Plex:CS Notifier :: Unable to parse custom notification subject. Using fallback."
                )

            try:
                body_text = unicode(on_pause_body).format(**available_params)
            except LookupError as e:
                logger.error(
                    u"Plex:CS Notifier :: Unable to parse field %s in notification body. Using fallback."
                    % e)
            except:
                logger.error(
                    u"Plex:CS Notifier :: Unable to parse custom notification body. Using fallback."
                )

            return [subject_text, body_text]
        else:
            return [subject_text, body_text]
    elif state == 'resume':
        # Default body text
        body_text = '%s (%s) has resumed %s' % (session['friendly_name'],
                                                session['player'], full_title)

        if on_resume_subject and on_resume_body:
            try:
                subject_text = unicode(on_resume_subject).format(
                    **available_params)
            except LookupError as e:
                logger.error(
                    u"Plex:CS Notifier :: Unable to parse field %s in notification subject. Using fallback."
                    % e)
            except:
                logger.error(
                    u"Plex:CS Notifier :: Unable to parse custom notification subject. Using fallback."
                )

            try:
                body_text = unicode(on_resume_body).format(**available_params)
            except LookupError as e:
                logger.error(
                    u"Plex:CS Notifier :: Unable to parse field %s in notification body. Using fallback."
                    % e)
            except:
                logger.error(
                    u"Plex:CS Notifier :: Unable to parse custom notification body. Using fallback."
                )

            return [subject_text, body_text]
        else:
            return [subject_text, body_text]
    elif state == 'buffer':
        # Default body text
        body_text = '%s (%s) is buffering %s' % (session['friendly_name'],
                                                 session['player'], full_title)

        if on_buffer_subject and on_buffer_body:
            try:
                subject_text = unicode(on_buffer_subject).format(
                    **available_params)
            except LookupError as e:
                logger.error(
                    u"Plex:CS Notifier :: Unable to parse field %s in notification subject. Using fallback."
                    % e)
            except:
                logger.error(
                    u"Plex:CS Notifier :: Unable to parse custom notification subject. Using fallback."
                )

            try:
                body_text = unicode(on_buffer_body).format(**available_params)
            except LookupError as e:
                logger.error(
                    u"Plex:CS Notifier :: Unable to parse field %s in notification body. Using fallback."
                    % e)
            except:
                logger.error(
                    u"Plex:CS Notifier :: Unable to parse custom notification body. Using fallback."
                )

            return [subject_text, body_text]
        else:
            return [subject_text, body_text]
    elif state == 'watched':
        # Default body text
        body_text = '%s (%s) has watched %s' % (session['friendly_name'],
                                                session['player'], full_title)

        if on_watched_subject and on_watched_body:
            try:
                subject_text = unicode(on_watched_subject).format(
                    **available_params)
            except LookupError as e:
                logger.error(
                    u"Plex:CS Notifier :: Unable to parse field %s in notification subject. Using fallback."
                    % e)
            except:
                logger.error(
                    u"Plex:CS Notifier :: Unable to parse custom notification subject. Using fallback."
                )

            try:
                body_text = unicode(on_watched_body).format(**available_params)
            except LookupError as e:
                logger.error(
                    u"Plex:CS Notifier :: Unable to parse field %s in notification body. Using fallback."
                    % e)
            except:
                logger.error(
                    u"Plex:CS Notifier :: Unable to parse custom notification body. Using fallback."
                )

            return [subject_text, body_text]
        else:
            return [subject_text, body_text]
    elif state == 'created':
        # Default body text
        body_text = '%s was recently added to Plex.' % full_title

        if on_created_subject and on_created_body:
            try:
                subject_text = unicode(on_created_subject).format(
                    **available_params)
            except LookupError as e:
                logger.error(
                    u"Plex:CS Notifier :: Unable to parse field %s in notification subject. Using fallback."
                    % e)
            except:
                logger.error(
                    u"Plex:CS Notifier :: Unable to parse custom notification subject. Using fallback."
                )

            try:
                body_text = unicode(on_created_body).format(**available_params)
            except LookupError as e:
                logger.error(
                    u"Plex:CS Notifier :: Unable to parse field %s in notification body. Using fallback."
                    % e)
            except:
                logger.error(
                    u"Plex:CS Notifier :: Unable to parse custom notification body. Using fallback."
                )

            return [subject_text, body_text]
        else:
            return [subject_text, body_text]
    else:
        return None
Example #4
0
def notify(stream_data=None, notify_action=None):
    from plexcs 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 plexcs.CONFIG.MOVIE_NOTIFY_ENABLE) \
            or (stream_data['media_type'] == 'episode' and plexcs.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 (plexcs.CONFIG.NOTIFY_CONSECUTIVE or progress_percent < plexcs.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 (plexcs.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 (plexcs.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 plexcs.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"Plex:CS Notifier :: Notify called with unsupported media type.")
            pass
    else:
        logger.debug(
            u"Plex:CS Notifier :: Notify called but incomplete data received.")
Example #5
0
def build_notify_text(session=None, timeline=None, state=None):
    import re

    # Get the server name
    server_name = plexcs.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"Plex:CS 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"Plex:CS 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("\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, "", plexcs.CONFIG.NOTIFY_ON_START_SUBJECT_TEXT))
        on_start_body = strip_tag(re.sub(pattern, "", plexcs.CONFIG.NOTIFY_ON_START_BODY_TEXT))
        on_stop_subject = strip_tag(re.sub(pattern, "", plexcs.CONFIG.NOTIFY_ON_STOP_SUBJECT_TEXT))
        on_stop_body = strip_tag(re.sub(pattern, "", plexcs.CONFIG.NOTIFY_ON_STOP_BODY_TEXT))
        on_pause_subject = strip_tag(re.sub(pattern, "", plexcs.CONFIG.NOTIFY_ON_PAUSE_SUBJECT_TEXT))
        on_pause_body = strip_tag(re.sub(pattern, "", plexcs.CONFIG.NOTIFY_ON_PAUSE_BODY_TEXT))
        on_resume_subject = strip_tag(re.sub(pattern, "", plexcs.CONFIG.NOTIFY_ON_RESUME_SUBJECT_TEXT))
        on_resume_body = strip_tag(re.sub(pattern, "", plexcs.CONFIG.NOTIFY_ON_RESUME_BODY_TEXT))
        on_buffer_subject = strip_tag(re.sub(pattern, "", plexcs.CONFIG.NOTIFY_ON_BUFFER_SUBJECT_TEXT))
        on_buffer_body = strip_tag(re.sub(pattern, "", plexcs.CONFIG.NOTIFY_ON_BUFFER_BODY_TEXT))
        on_watched_subject = strip_tag(re.sub(pattern, "", plexcs.CONFIG.NOTIFY_ON_WATCHED_SUBJECT_TEXT))
        on_watched_body = strip_tag(re.sub(pattern, "", plexcs.CONFIG.NOTIFY_ON_WATCHED_BODY_TEXT))
        on_created_subject = strip_tag(re.sub(pattern, "", plexcs.CONFIG.NOTIFY_ON_CREATED_SUBJECT_TEXT))
        on_created_body = strip_tag(re.sub(pattern, "", plexcs.CONFIG.NOTIFY_ON_CREATED_BODY_TEXT))
    else:
        on_start_subject = plexcs.CONFIG.NOTIFY_ON_START_SUBJECT_TEXT
        on_start_body = plexcs.CONFIG.NOTIFY_ON_START_BODY_TEXT
        on_stop_subject = plexcs.CONFIG.NOTIFY_ON_STOP_SUBJECT_TEXT
        on_stop_body = plexcs.CONFIG.NOTIFY_ON_STOP_BODY_TEXT
        on_pause_subject = plexcs.CONFIG.NOTIFY_ON_PAUSE_SUBJECT_TEXT
        on_pause_body = plexcs.CONFIG.NOTIFY_ON_PAUSE_BODY_TEXT
        on_resume_subject = plexcs.CONFIG.NOTIFY_ON_RESUME_SUBJECT_TEXT
        on_resume_body = plexcs.CONFIG.NOTIFY_ON_RESUME_BODY_TEXT
        on_buffer_subject = plexcs.CONFIG.NOTIFY_ON_BUFFER_SUBJECT_TEXT
        on_buffer_body = plexcs.CONFIG.NOTIFY_ON_BUFFER_BODY_TEXT
        on_watched_subject = plexcs.CONFIG.NOTIFY_ON_WATCHED_SUBJECT_TEXT
        on_watched_body = plexcs.CONFIG.NOTIFY_ON_WATCHED_BODY_TEXT
        on_created_subject = plexcs.CONFIG.NOTIFY_ON_CREATED_SUBJECT_TEXT
        on_created_body = plexcs.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 = "Plex:CS (%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 as e:
                logger.error(
                    u"Plex:CS Notifier :: Unable to parse field %s in notification subject. Using fallback." % e
                )
            except:
                logger.error(u"Plex:CS Notifier :: Unable to parse custom notification subject. Using fallback.")

            try:
                body_text = unicode(on_start_body).format(**available_params)
            except LookupError as e:
                logger.error(u"Plex:CS Notifier :: Unable to parse field %s in notification body. Using fallback." % e)
            except:
                logger.error(u"Plex:CS Notifier :: Unable to parse custom notification body. Using fallback.")

            return [subject_text, body_text]
        else:
            return [subject_text, body_text]
    elif state == "stop":
        # Default body text
        body_text = "%s (%s) has stopped %s" % (session["friendly_name"], session["player"], full_title)

        if on_stop_subject and on_stop_body:
            try:
                subject_text = unicode(on_stop_subject).format(**available_params)
            except LookupError as e:
                logger.error(
                    u"Plex:CS Notifier :: Unable to parse field %s in notification subject. Using fallback." % e
                )
            except:
                logger.error(u"Plex:CS Notifier :: Unable to parse custom notification subject. Using fallback.")

            try:
                body_text = unicode(on_stop_body).format(**available_params)
            except LookupError as e:
                logger.error(u"Plex:CS Notifier :: Unable to parse field %s in notification body. Using fallback." % e)
            except:
                logger.error(u"Plex:CS Notifier :: Unable to parse custom notification body. Using fallback.")

            return [subject_text, body_text]
        else:
            return [subject_text, body_text]
    elif state == "pause":
        # Default body text
        body_text = "%s (%s) has paused %s" % (session["friendly_name"], session["player"], full_title)

        if on_pause_subject and on_pause_body:
            try:
                subject_text = unicode(on_pause_subject).format(**available_params)
            except LookupError as e:
                logger.error(
                    u"Plex:CS Notifier :: Unable to parse field %s in notification subject. Using fallback." % e
                )
            except:
                logger.error(u"Plex:CS Notifier :: Unable to parse custom notification subject. Using fallback.")

            try:
                body_text = unicode(on_pause_body).format(**available_params)
            except LookupError as e:
                logger.error(u"Plex:CS Notifier :: Unable to parse field %s in notification body. Using fallback." % e)
            except:
                logger.error(u"Plex:CS Notifier :: Unable to parse custom notification body. Using fallback.")

            return [subject_text, body_text]
        else:
            return [subject_text, body_text]
    elif state == "resume":
        # Default body text
        body_text = "%s (%s) has resumed %s" % (session["friendly_name"], session["player"], full_title)

        if on_resume_subject and on_resume_body:
            try:
                subject_text = unicode(on_resume_subject).format(**available_params)
            except LookupError as e:
                logger.error(
                    u"Plex:CS Notifier :: Unable to parse field %s in notification subject. Using fallback." % e
                )
            except:
                logger.error(u"Plex:CS Notifier :: Unable to parse custom notification subject. Using fallback.")

            try:
                body_text = unicode(on_resume_body).format(**available_params)
            except LookupError as e:
                logger.error(u"Plex:CS Notifier :: Unable to parse field %s in notification body. Using fallback." % e)
            except:
                logger.error(u"Plex:CS Notifier :: Unable to parse custom notification body. Using fallback.")

            return [subject_text, body_text]
        else:
            return [subject_text, body_text]
    elif state == "buffer":
        # Default body text
        body_text = "%s (%s) is buffering %s" % (session["friendly_name"], session["player"], full_title)

        if on_buffer_subject and on_buffer_body:
            try:
                subject_text = unicode(on_buffer_subject).format(**available_params)
            except LookupError as e:
                logger.error(
                    u"Plex:CS Notifier :: Unable to parse field %s in notification subject. Using fallback." % e
                )
            except:
                logger.error(u"Plex:CS Notifier :: Unable to parse custom notification subject. Using fallback.")

            try:
                body_text = unicode(on_buffer_body).format(**available_params)
            except LookupError as e:
                logger.error(u"Plex:CS Notifier :: Unable to parse field %s in notification body. Using fallback." % e)
            except:
                logger.error(u"Plex:CS Notifier :: Unable to parse custom notification body. Using fallback.")

            return [subject_text, body_text]
        else:
            return [subject_text, body_text]
    elif state == "watched":
        # Default body text
        body_text = "%s (%s) has watched %s" % (session["friendly_name"], session["player"], full_title)

        if on_watched_subject and on_watched_body:
            try:
                subject_text = unicode(on_watched_subject).format(**available_params)
            except LookupError as e:
                logger.error(
                    u"Plex:CS Notifier :: Unable to parse field %s in notification subject. Using fallback." % e
                )
            except:
                logger.error(u"Plex:CS Notifier :: Unable to parse custom notification subject. Using fallback.")

            try:
                body_text = unicode(on_watched_body).format(**available_params)
            except LookupError as e:
                logger.error(u"Plex:CS Notifier :: Unable to parse field %s in notification body. Using fallback." % e)
            except:
                logger.error(u"Plex:CS Notifier :: Unable to parse custom notification body. Using fallback.")

            return [subject_text, body_text]
        else:
            return [subject_text, body_text]
    elif state == "created":
        # Default body text
        body_text = "%s was recently added to Plex." % full_title

        if on_created_subject and on_created_body:
            try:
                subject_text = unicode(on_created_subject).format(**available_params)
            except LookupError as e:
                logger.error(
                    u"Plex:CS Notifier :: Unable to parse field %s in notification subject. Using fallback." % e
                )
            except:
                logger.error(u"Plex:CS Notifier :: Unable to parse custom notification subject. Using fallback.")

            try:
                body_text = unicode(on_created_body).format(**available_params)
            except LookupError as e:
                logger.error(u"Plex:CS Notifier :: Unable to parse field %s in notification body. Using fallback." % e)
            except:
                logger.error(u"Plex:CS Notifier :: Unable to parse custom notification body. Using fallback.")

            return [subject_text, body_text]
        else:
            return [subject_text, body_text]
    else:
        return None
Example #6
0
def notify(stream_data=None, notify_action=None):
    from plexcs 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 plexcs.CONFIG.MOVIE_NOTIFY_ENABLE) or (
            stream_data["media_type"] == "episode" and plexcs.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 (plexcs.CONFIG.NOTIFY_CONSECUTIVE or progress_percent < plexcs.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 (plexcs.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 (plexcs.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 plexcs.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"Plex:CS Notifier :: Notify called with unsupported media type.")
            pass
    else:
        logger.debug(u"Plex:CS Notifier :: Notify called but incomplete data received.")
Example #7
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("Error parsing XML for Plex sync lists: %s" % e)
            return []
        except:
            logger.warn("Error parsing XML for Plex sync lists.")
            return []

        xml_head = xml_parse.getElementsByTagName('SyncList')

        if not xml_head:
            logger.warn("Error parsing XML for Plex sync lists.")
        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_user_details(user_id=device_user_id)['username']
                        device_friendly_name = user_data.get_user_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')

                        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:
                            clean_uri = helpers.get_xml_attr(item.getElementsByTagName('Location')[0], 'uri')

                        rating_key = clean_uri.rpartition('%2F')[-1]

                        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