def _getHistory(self, user=None, user_id=None, rating_key='', parent_rating_key='', grandparent_rating_key='', start_date='', **kwargs): custom_where = [] if user_id: custom_where = [['user_id', user_id]] elif user: custom_where = [['user', user]] if 'rating_key' in kwargs: rating_key = kwargs.get('rating_key', "") custom_where = [['rating_key', rating_key]] if 'parent_rating_key' in kwargs: rating_key = kwargs.get('parent_rating_key', "") custom_where = [['parent_rating_key', rating_key]] if 'grandparent_rating_key' in kwargs: rating_key = kwargs.get('grandparent_rating_key', "") custom_where = [['grandparent_rating_key', rating_key]] if 'start_date' in kwargs: start_date = kwargs.get('start_date', "") custom_where = [['strftime("%Y-%m-%d", datetime(date, "unixepoch", "localtime"))', start_date]] data_factory = datafactory.DataFactory() history = data_factory.get_history(kwargs=kwargs, custom_where=custom_where) self.data = history return self.data
def get_synced_items(self, machine_id=None, user_id=None): sync_list = self.get_plextv_sync_lists(machine_id) data_factory = datafactory.DataFactory() synced_items = [] try: xml_parse = minidom.parseString(sync_list) except Exception, e: logger.warn("Error parsing XML for Plex sync lists: %s" % e) return []
def on_created(server, rating_key, **kwargs): logger.debug(u"Tautulli TimelineHandler :: %s: Library item %s added to Plex." % (server.CONFIG.PMS_NAME, str(rating_key))) metadata = server.get_metadata_details(rating_key) if metadata: notify = True # now = int(time.time()) # # if helpers.cast_to_int(metadata['added_at']) < now - 86400: # Updated more than 24 hours ago # logger.debug(u"Tautulli TimelineHandler :: %s: Library item %s added more than 24 hours ago. Not notifying." # % (server.CONFIG.PMS_NAME, str(rating_key))) # notify = False data_factory = datafactory.DataFactory() if 'child_keys' not in kwargs: if data_factory.get_recently_added_item(server.CONFIG.ID, rating_key): logger.debug(u"Tautulli TimelineHandler :: %s: Library item %s added already. Not notifying again." % (server.CONFIG.PMS_NAME, str(rating_key))) notify = False if notify: data = {'timeline_data': metadata, 'notify_action': 'on_created'} data.update(kwargs) plexpy.NOTIFY_QUEUE.put(data) all_keys = [rating_key] if 'child_keys' in kwargs: all_keys.extend(kwargs['child_keys']) for key in all_keys: data_factory.set_recently_added_item(server.CONFIG.ID, key) logger.debug(u"Tautulli TimelineHandler :: %s: Added %s items to the recently_added database table." % (server.CONFIG.PMS_NAME, str(len(all_keys)))) else: logger.error(u"Tautulli TimelineHandler :: %s: Unable to retrieve metadata for rating_key %s" % (server.CONFIG.PMS_NAME, str(rating_key)))
def write_session_history(self, session=None, import_metadata=None, is_import=False, import_ignore_interval=0): from plexpy import datafactory data_factory = datafactory.DataFactory() user_details = data_factory.get_user_friendly_name( user=session['user']) if session: logging_enabled = False if is_import: if str(session['stopped']).isdigit(): stopped = session['stopped'] else: stopped = int(time.time()) else: stopped = int(time.time()) if plexpy.CONFIG.VIDEO_LOGGING_ENABLE and \ (session['media_type'] == 'movie' or session['media_type'] == 'episode'): logging_enabled = True elif plexpy.CONFIG.MUSIC_LOGGING_ENABLE and \ session['media_type'] == 'track': logging_enabled = True else: logger.debug( u"PlexPy Monitor :: ratingKey %s not logged. Does not meet logging criteria. " u"Media type is '%s'" % (session['rating_key'], session['media_type'])) if plexpy.CONFIG.LOGGING_IGNORE_INTERVAL and not is_import: if (session['media_type'] == 'movie' or session['media_type'] == 'episode') and \ (int(stopped) - session['started'] < int(plexpy.CONFIG.LOGGING_IGNORE_INTERVAL)): logging_enabled = False logger.debug( u"PlexPy Monitor :: Play duration for ratingKey %s is %s secs which is less than %s " u"seconds, so we're not logging it." % (session['rating_key'], str(int(stopped) - session['started']), plexpy.CONFIG.LOGGING_IGNORE_INTERVAL)) elif is_import and import_ignore_interval: if (session['media_type'] == 'movie' or session['media_type'] == 'episode') and \ (int(stopped) - session['started'] < int(import_ignore_interval)): logging_enabled = False logger.debug( u"PlexPy Monitor :: Play duration for ratingKey %s is %s secs which is less than %s " u"seconds, so we're not logging it." % (session['rating_key'], str(int(stopped) - session['started']), import_ignore_interval)) if not user_details['keep_history'] and not is_import: logging_enabled = False logger.debug( u"PlexPy Monitor :: History logging for user '%s' is disabled." % session['user']) if logging_enabled: # logger.debug(u"PlexPy Monitor :: Attempting to write to session_history table...") query = 'INSERT INTO session_history (started, stopped, rating_key, parent_rating_key, ' \ 'grandparent_rating_key, media_type, user_id, user, ip_address, paused_counter, player, ' \ 'platform, machine_id, view_offset) VALUES ' \ '(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)' args = [ session['started'], stopped, session['rating_key'], session['parent_rating_key'], session['grandparent_rating_key'], session['media_type'], session['user_id'], session['user'], session['ip_address'], session['paused_counter'], session['player'], session['platform'], session['machine_id'], session['view_offset'] ] # logger.debug(u"PlexPy Monitor :: Writing session_history transaction...") self.db.action(query=query, args=args) # logger.debug(u"PlexPy Monitor :: Successfully written history item, last id for session_history is %s" # % last_id) # Write the session_history_media_info table # logger.debug(u"PlexPy Monitor :: Attempting to write to session_history_media_info table...") query = 'INSERT INTO session_history_media_info (id, rating_key, video_decision, audio_decision, ' \ 'duration, 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) VALUES ' \ '(last_insert_rowid(), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)' args = [ session['rating_key'], session['video_decision'], session['audio_decision'], session['duration'], session['width'], session['height'], session['container'], session['video_codec'], session['audio_codec'], session['bitrate'], session['video_resolution'], session['video_framerate'], session['aspect_ratio'], session['audio_channels'], session['transcode_protocol'], session['transcode_container'], session['transcode_video_codec'], session['transcode_audio_codec'], session['transcode_audio_channels'], session['transcode_width'], session['transcode_height'] ] # logger.debug(u"PlexPy Monitor :: Writing session_history_media_info transaction...") self.db.action(query=query, args=args) if not is_import: logger.debug( u"PlexPy Monitor :: Fetching metadata for item ratingKey %s" % session['rating_key']) pms_connect = pmsconnect.PmsConnect() result = pms_connect.get_metadata_details( rating_key=str(session['rating_key'])) metadata = result['metadata'] else: metadata = import_metadata # Write the session_history_metadata table directors = ";".join(metadata['directors']) writers = ";".join(metadata['writers']) actors = ";".join(metadata['actors']) genres = ";".join(metadata['genres']) # Build media item title if session['media_type'] == 'episode' or session[ 'media_type'] == 'track': full_title = '%s - %s' % (metadata['grandparent_title'], metadata['title']) elif session['media_type'] == 'movie': full_title = metadata['title'] else: full_title = metadata['title'] # logger.debug(u"PlexPy Monitor :: Attempting to write to session_history_metadata table...") query = 'INSERT INTO session_history_metadata (id, rating_key, parent_rating_key, ' \ 'grandparent_rating_key, title, parent_title, grandparent_title, full_title, media_index, ' \ 'parent_media_index, thumb, parent_thumb, grandparent_thumb, art, media_type, year, ' \ 'originally_available_at, added_at, updated_at, last_viewed_at, content_rating, summary, ' \ 'rating, duration, guid, directors, writers, actors, genres, studio) VALUES ' \ '(last_insert_rowid(), ' \ '?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)' args = [ session['rating_key'], session['parent_rating_key'], session['grandparent_rating_key'], session['title'], session['parent_title'], session['grandparent_title'], full_title, metadata['index'], metadata['parent_index'], metadata['thumb'], metadata['parent_thumb'], metadata['grandparent_thumb'], metadata['art'], session['media_type'], metadata['year'], metadata['originally_available_at'], metadata['added_at'], metadata['updated_at'], metadata['last_viewed_at'], metadata['content_rating'], metadata['summary'], metadata['rating'], metadata['duration'], metadata['guid'], directors, writers, actors, genres, metadata['studio'] ] # logger.debug(u"PlexPy Monitor :: Writing session_history_metadata transaction...") self.db.action(query=query, args=args)
def notify(stream_data=None, notify_action=None): from plexpy import datafactory if stream_data and notify_action: # Check if notifications enabled for user data_factory = datafactory.DataFactory() user_details = data_factory.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: 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_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_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_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.")
def import_from_plexwatch(database=None, table_name=None, import_ignore_interval=0): try: connection = sqlite3.connect(database, timeout=20) connection.row_factory = sqlite3.Row except sqlite3.OperationalError: logger.error('PlexPy Importer :: Invalid filename.') return None except ValueError: logger.error('PlexPy Importer :: Invalid filename.') return None try: connection.execute('SELECT ratingKey from %s' % table_name) except sqlite3.OperationalError: logger.error( 'PlexPy Importer :: Database specified does not contain the required fields.' ) return None logger.debug(u"PlexPy Importer :: PlexWatch data import in progress...") logger.debug( u"PlexPy Importer :: Disabling monitoring while import in progress.") plexpy.schedule_job(monitor.check_active_sessions, 'Check for active sessions', hours=0, minutes=0, seconds=0) monitor_processing = monitor.MonitorProcessing() data_factory = datafactory.DataFactory() # Get the latest friends list so we can pull user id's try: plextv.refresh_users() except: logger.debug( u"PlexPy Importer :: Unable to refresh the users list. Aborting import." ) return None query = 'SELECT time AS started, ' \ 'stopped, ' \ 'cast(ratingKey as text) AS rating_key, ' \ 'null AS user_id, ' \ 'user, ' \ 'ip_address, ' \ 'paused_counter, ' \ 'platform AS player, ' \ 'null AS platform, ' \ 'null as machine_id, ' \ 'parentRatingKey as parent_rating_key, ' \ 'grandparentRatingKey as grandparent_rating_key, ' \ 'null AS media_type, ' \ 'null AS view_offset, ' \ 'xml, ' \ 'rating as content_rating,' \ 'summary,' \ 'title AS full_title,' \ '(case when orig_title_ep = "" then orig_title else ' \ 'orig_title_ep end) as title,' \ '(case when orig_title_ep != "" then orig_title else ' \ 'null end) as grandparent_title ' \ 'FROM ' + table_name + ' ORDER BY id' result = connection.execute(query) for row in result: # Extract the xml from the Plexwatch db xml field. extracted_xml = extract_plexwatch_xml(row['xml']) # If we get back None from our xml extractor skip over the record and log error. if not extracted_xml: logger.error( u"PlexPy Importer :: Skipping line with ratingKey %s due to malformed xml." % str(row['rating_key'])) continue # If the user_id no longer exists in the friends list, pull it from the xml. if data_factory.get_user_id(user=row['user']): user_id = data_factory.get_user_id(user=row['user']) else: user_id = extracted_xml['user_id'] session_history = { 'started': row['started'], 'stopped': row['stopped'], 'rating_key': row['rating_key'], 'title': row['title'], 'parent_title': extracted_xml['parent_title'], 'grandparent_title': row['grandparent_title'], 'user_id': user_id, 'user': row['user'], 'ip_address': row['ip_address'], 'paused_counter': row['paused_counter'], 'player': row['player'], 'platform': extracted_xml['platform'], 'machine_id': extracted_xml['machine_id'], 'parent_rating_key': row['parent_rating_key'], 'grandparent_rating_key': row['grandparent_rating_key'], 'media_type': extracted_xml['media_type'], 'view_offset': extracted_xml['view_offset'], 'video_decision': extracted_xml['video_decision'], 'audio_decision': extracted_xml['audio_decision'], 'duration': extracted_xml['duration'], 'width': extracted_xml['width'], 'height': extracted_xml['height'], 'container': extracted_xml['container'], 'video_codec': extracted_xml['video_codec'], 'audio_codec': extracted_xml['audio_codec'], 'bitrate': extracted_xml['bitrate'], 'video_resolution': extracted_xml['video_resolution'], 'video_framerate': extracted_xml['video_framerate'], 'aspect_ratio': extracted_xml['aspect_ratio'], 'audio_channels': extracted_xml['audio_channels'], 'transcode_protocol': extracted_xml['transcode_protocol'], 'transcode_container': extracted_xml['transcode_container'], 'transcode_video_codec': extracted_xml['transcode_video_codec'], 'transcode_audio_codec': extracted_xml['transcode_audio_codec'], 'transcode_audio_channels': extracted_xml['transcode_audio_channels'], 'transcode_width': extracted_xml['transcode_width'], 'transcode_height': extracted_xml['transcode_height'] } session_history_metadata = { 'rating_key': helpers.latinToAscii(row['rating_key']), 'parent_rating_key': row['parent_rating_key'], 'grandparent_rating_key': row['grandparent_rating_key'], 'title': row['title'], 'parent_title': extracted_xml['parent_title'], 'grandparent_title': row['grandparent_title'], 'index': extracted_xml['media_index'], 'parent_index': extracted_xml['parent_media_index'], 'thumb': extracted_xml['thumb'], 'parent_thumb': extracted_xml['parent_thumb'], 'grandparent_thumb': extracted_xml['grandparent_thumb'], 'art': extracted_xml['art'], 'media_type': extracted_xml['media_type'], 'year': extracted_xml['year'], 'originally_available_at': extracted_xml['originally_available_at'], 'added_at': extracted_xml['added_at'], 'updated_at': extracted_xml['updated_at'], 'last_viewed_at': extracted_xml['last_viewed_at'], 'content_rating': row['content_rating'], 'summary': row['summary'], 'rating': extracted_xml['rating'], 'duration': extracted_xml['duration'], 'guid': extracted_xml['guid'], 'directors': extracted_xml['directors'], 'writers': extracted_xml['writers'], 'actors': extracted_xml['actors'], 'genres': extracted_xml['genres'], 'studio': extracted_xml['studio'], 'full_title': row['full_title'] } # On older versions of PMS, "clip" items were still classified as "movie" and had bad ratingKey values # Just make sure that the ratingKey is indeed an integer if session_history_metadata['rating_key'].isdigit(): monitor_processing.write_session_history( session=session_history, import_metadata=session_history_metadata, is_import=True, import_ignore_interval=import_ignore_interval) else: logger.debug(u"PlexPy Importer :: Item has bad rating_key: %s" % session_history_metadata['rating_key']) logger.debug(u"PlexPy Importer :: PlexWatch data import complete.") import_users() logger.debug(u"PlexPy Importer :: Re-enabling monitoring.") plexpy.initialize_scheduler()