def get_user_gravatar_image(self, user=None): myDB = db.DBConnection() user_info = None try: query = 'SELECT xml ' \ 'FROM %s ' \ 'WHERE user = ? ' \ 'ORDER BY id DESC LIMIT 1' % self.get_history_table_name() result = myDB.select_single(query, args=[user]) except: logger.warn("Unable to open PlexWatch database.") return None xml_data = helpers.latinToAscii(result) try: xml_parse = minidom.parseString(xml_data) except: logger.warn("Error parsing XML for Plexwatch Database.") return None xml_head = xml_parse.getElementsByTagName('User') if not xml_head: logger.warn("Error parsing XML for Plexwatch Database.") return None for a in xml_head: user_id = self.get_xml_attr(a, 'id') user_thumb = self.get_xml_attr(a, 'thumb') user_info = {'user_id': user_id, 'user_thumb': user_thumb} return user_info
def get_user_gravatar_image(self, user=None): myDB = db.DBConnection() user_info = None try: query = 'SELECT xml ' \ 'FROM %s ' \ 'WHERE user = "******" ' \ 'ORDER BY id DESC LIMIT 1' % (self.get_history_table_name(), user) result = myDB.select_single(query) except: logger.warn("Unable to open PlexWatch database.") return None xml_data = helpers.latinToAscii(result) try: xml_parse = minidom.parseString(xml_data) except: logger.warn("Error parsing XML for Plexwatch Database.") return None xml_head = xml_parse.getElementsByTagName('User') if not xml_head: logger.warn("Error parsing XML for Plexwatch Database.") return None for a in xml_head: user_id = self.get_xml_attr(a, 'id') user_thumb = self.get_xml_attr(a, 'thumb') user_info = {'user_id': user_id, 'user_thumb': user_thumb} return user_info
def get_recently_watched(self, user=None, limit='10'): myDB = db.DBConnection() recently_watched = [] if not limit.isdigit(): limit = '10' try: if user: query = 'SELECT time, user, xml FROM %s WHERE user = ? ORDER BY time DESC LIMIT ?' % \ (self.get_history_table_name()) xml = myDB.select(query, args=[user, limit]) else: query = 'SELECT time, user, xml FROM %s ORDER BY time DESC LIMIT ?' % \ (self.get_history_table_name()) xml = myDB.select(query, args=[limit]) except: logger.warn("Unable to open PlexWatch database.") return None for row in xml: xml_data = helpers.latinToAscii(row[2]) try: xml_parse = minidom.parseString(xml_data) except: logger.warn("Error parsing XML for Plex stream data.") return None xml_head = xml_parse.getElementsByTagName('opt') if not xml_head: logger.warn("Error parsing XML for Plex stream data.") return None for a in xml_head: if self.get_xml_attr(a, 'type') == 'episode': thumb = self.get_xml_attr(a, 'parentThumb') else: thumb = self.get_xml_attr(a, 'thumb') recent_output = { 'type': self.get_xml_attr(a, 'type'), 'rating_key': self.get_xml_attr(a, 'ratingKey'), 'title': self.get_xml_attr(a, 'title'), 'thumb': thumb, 'index': self.get_xml_attr(a, 'index'), 'parentIndex': self.get_xml_attr(a, 'parentIndex'), 'year': self.get_xml_attr(a, 'year'), 'time': row[0], 'user': row[1] } recently_watched.append(recent_output) return recently_watched
def get_recently_watched(self, user=None, limit='10'): myDB = db.DBConnection() recently_watched = [] if not limit.isdigit(): limit = '10' try: if user: query = 'SELECT time, user, xml FROM %s WHERE user = "******" ORDER BY time DESC LIMIT %s' % \ (self.get_history_table_name(), user, limit) xml = myDB.select(query) else: query = 'SELECT time, user, xml FROM %s ORDER BY time DESC LIMIT %s' % \ (self.get_history_table_name(), limit) xml = myDB.select(query) except: logger.warn("Unable to open PlexWatch database.") return None for row in xml: xml_data = helpers.latinToAscii(row[2]) try: xml_parse = minidom.parseString(xml_data) except: logger.warn("Error parsing XML for Plex stream data.") return None xml_head = xml_parse.getElementsByTagName('opt') if not xml_head: logger.warn("Error parsing XML for Plex stream data.") return None for a in xml_head: if self.get_xml_attr(a, 'type') == 'episode': thumb = self.get_xml_attr(a, 'parentThumb') else: thumb = self.get_xml_attr(a, 'thumb') recent_output = {'type': self.get_xml_attr(a, 'type'), 'rating_key': self.get_xml_attr(a, 'ratingKey'), 'title': self.get_xml_attr(a, 'title'), 'thumb': thumb, 'index': self.get_xml_attr(a, 'index'), 'parentIndex': self.get_xml_attr(a, 'parentIndex'), 'year': self.get_xml_attr(a, 'year'), 'time': row[0], 'user': row[1] } recently_watched.append(recent_output) return recently_watched
def get_log_tail(window=20, parsed=True, log_type="server"): if plexpy.CONFIG.PMS_LOGS_FOLDER: log_file = "" if log_type == "server": log_file = os.path.join(plexpy.CONFIG.PMS_LOGS_FOLDER, 'Plex Media Server.log') elif log_type == "scanner": log_file = os.path.join(plexpy.CONFIG.PMS_LOGS_FOLDER, 'Plex Media Scanner.log') else: return [] try: logfile = open(log_file, "r") except IOError as e: logger.error('Unable to open Plex Log file. %s' % e) return [] log_lines = tail(logfile, window) if parsed: line_error = False clean_lines = [] for i in log_lines: try: log_time = i.split(' [')[0] log_level = i.split('] ', 1)[1].split(' - ', 1)[0] log_msg = str(i.split('] ', 1)[1].split(' - ', 1)[1], 'utf-8') full_line = [log_time, log_level, log_msg] clean_lines.append(full_line) except: line_error = True full_line = ['', '', 'Unable to parse log line.'] clean_lines.append(full_line) if line_error: logger.error( 'Tautulli was unable to parse some lines of the Plex Media Server log.' ) return clean_lines else: raw_lines = [] for i in log_lines: raw_lines.append(helpers.latinToAscii(i)) return raw_lines return log_lines
def get_user_platform_stats(self, user=None): myDB = db.DBConnection() platform_stats = [] result_id = 0 try: query = 'SELECT platform, COUNT(platform) as platform_count, xml ' \ 'FROM grouped ' \ 'WHERE user = ? ' \ 'GROUP BY platform ' \ 'ORDER BY platform_count DESC' result = myDB.select(query, args=[user]) except: logger.warn("Unable to open PlexWatch database.") return None for item in result: xml_data = helpers.latinToAscii(item[2]) try: xml_parse = minidom.parseString(xml_data) except: logger.warn("Error parsing XML for Plex stream data.") return None xml_head = xml_parse.getElementsByTagName('Player') if not xml_head: logger.warn("Error parsing XML for Plex stream data.") return None for a in xml_head: platform_type = self.get_xml_attr(a, 'platform') row = { 'platform_name': item[0], 'platform_type': platform_type, 'total_plays': item[1], 'result_id': result_id } platform_stats.append(row) result_id += 1 return platform_stats
def get_user_platform_stats(self, user=None): myDB = db.DBConnection() platform_stats = [] result_id = 0 try: query = 'SELECT platform, COUNT(platform) as platform_count, xml ' \ 'FROM %s ' \ 'WHERE user = "******" ' \ 'GROUP BY platform ' \ 'ORDER BY platform_count DESC' % (self.get_history_table_name(), user) result = myDB.select(query) except: logger.warn("Unable to open PlexWatch database.") return None for item in result: xml_data = helpers.latinToAscii(item[2]) try: xml_parse = minidom.parseString(xml_data) except: logger.warn("Error parsing XML for Plex stream data.") return None xml_head = xml_parse.getElementsByTagName('Player') if not xml_head: logger.warn("Error parsing XML for Plex stream data.") return None for a in xml_head: platform_type = self.get_xml_attr(a, 'platform') row = {'platform_name': item[0], 'platform_type': platform_type, 'total_plays': item[1], 'result_id': result_id } platform_stats.append(row) result_id += 1 return platform_stats
def get_token(self): plextv_response = self.get_plex_auth() if plextv_response: try: xml_parse = minidom.parseString(helpers.latinToAscii(plextv_response)) except IOError, e: logger.warn("Error parsing XML for Plex.tv token: %s" % e) return False xml_head = xml_parse.getElementsByTagName('user') if not xml_head: logger.warn("Error parsing XML for Plex.tv token: %s" % e) return False auth_token = xml_head[0].getAttribute('authenticationToken') return auth_token
def get_stream_details(self, row_id=None): myDB = db.DBConnection() if row_id: query = 'SELECT xml from %s where id = %s' % (self.get_history_table_name(), row_id) xml = myDB.select_single(query) xml_data = helpers.latinToAscii(xml) else: return None try: xml_parse = minidom.parseString(xml_data) except: logger.warn("Error parsing XML for Plex stream data.") return None xml_head = xml_parse.getElementsByTagName('opt') if not xml_head: logger.warn("Error parsing XML for Plex stream data.") return None stream_output = {} for a in xml_head: media_type = self.get_xml_attr(a, 'type') title = self.get_xml_attr(a, 'title') grandparent_title = self.get_xml_attr(a, 'grandparentTitle') if a.getElementsByTagName('TranscodeSession'): transcode_data = a.getElementsByTagName('TranscodeSession') for transcode_session in transcode_data: transcode_video_dec = self.get_xml_attr(transcode_session, 'videoDecision') transcode_video_codec = self.get_xml_attr(transcode_session, 'videoCodec') transcode_height = self.get_xml_attr(transcode_session, 'height') transcode_width = self.get_xml_attr(transcode_session, 'width') transcode_audio_dec = self.get_xml_attr(transcode_session, 'audioDecision') transcode_audio_codec = self.get_xml_attr(transcode_session, 'audioCodec') transcode_audio_channels = self.get_xml_attr(transcode_session, 'audioChannels') else: transcode_data = a.getElementsByTagName('Media') for transcode_session in transcode_data: transcode_video_dec = 'direct play' transcode_video_codec = self.get_xml_attr(transcode_session, 'videoCodec') transcode_height = self.get_xml_attr(transcode_session, 'height') transcode_width = self.get_xml_attr(transcode_session, 'width') transcode_audio_dec = 'direct play' transcode_audio_codec = self.get_xml_attr(transcode_session, 'audioCodec') transcode_audio_channels = self.get_xml_attr(transcode_session, 'audioChannels') if a.getElementsByTagName('Media'): stream_data = a.getElementsByTagName('Media') for stream_item in stream_data: stream_output = {'container': self.get_xml_attr(stream_item, 'container'), 'bitrate': self.get_xml_attr(stream_item, 'bitrate'), 'video_resolution': self.get_xml_attr(stream_item, 'videoResolution'), 'width': self.get_xml_attr(stream_item, 'width'), 'height': self.get_xml_attr(stream_item, 'height'), 'aspect_ratio': self.get_xml_attr(stream_item, 'aspectRatio'), 'video_framerate': self.get_xml_attr(stream_item, 'videoFrameRate'), 'video_codec': self.get_xml_attr(stream_item, 'videoCodec'), 'audio_codec': self.get_xml_attr(stream_item, 'audioCodec'), 'audio_channels': self.get_xml_attr(stream_item, 'audioChannels'), 'transcode_video_dec': transcode_video_dec, 'transcode_video_codec': transcode_video_codec, 'transcode_height': transcode_height, 'transcode_width': transcode_width, 'transcode_audio_dec': transcode_audio_dec, 'transcode_audio_codec': transcode_audio_codec, 'transcode_audio_channels': transcode_audio_channels, 'media_type': media_type, 'title': title, 'grandparent_title': grandparent_title } return stream_output
def get_stream_details(self, row_id=None): myDB = db.DBConnection() if row_id: query = 'SELECT xml from %s where id = ?' % ( self.get_history_table_name()) xml = myDB.select_single(query, args=[row_id]) xml_data = helpers.latinToAscii(xml) else: return None try: xml_parse = minidom.parseString(xml_data) except: logger.warn("Error parsing XML for Plex stream data.") return None xml_head = xml_parse.getElementsByTagName('opt') if not xml_head: logger.warn("Error parsing XML for Plex stream data.") return None stream_output = {} for a in xml_head: media_type = self.get_xml_attr(a, 'type') title = self.get_xml_attr(a, 'title') grandparent_title = self.get_xml_attr(a, 'grandparentTitle') if a.getElementsByTagName('TranscodeSession'): transcode_data = a.getElementsByTagName('TranscodeSession') for transcode_session in transcode_data: transcode_video_dec = self.get_xml_attr( transcode_session, 'videoDecision') transcode_video_codec = self.get_xml_attr( transcode_session, 'videoCodec') transcode_height = self.get_xml_attr( transcode_session, 'height') transcode_width = self.get_xml_attr( transcode_session, 'width') transcode_audio_dec = self.get_xml_attr( transcode_session, 'audioDecision') transcode_audio_codec = self.get_xml_attr( transcode_session, 'audioCodec') transcode_audio_channels = self.get_xml_attr( transcode_session, 'audioChannels') else: transcode_data = a.getElementsByTagName('Media') for transcode_session in transcode_data: transcode_video_dec = 'direct play' transcode_video_codec = self.get_xml_attr( transcode_session, 'videoCodec') transcode_height = self.get_xml_attr( transcode_session, 'height') transcode_width = self.get_xml_attr( transcode_session, 'width') transcode_audio_dec = 'direct play' transcode_audio_codec = self.get_xml_attr( transcode_session, 'audioCodec') transcode_audio_channels = self.get_xml_attr( transcode_session, 'audioChannels') if a.getElementsByTagName('Media'): stream_data = a.getElementsByTagName('Media') for stream_item in stream_data: stream_output = { 'container': self.get_xml_attr(stream_item, 'container'), 'bitrate': self.get_xml_attr(stream_item, 'bitrate'), 'video_resolution': self.get_xml_attr(stream_item, 'videoResolution'), 'width': self.get_xml_attr(stream_item, 'width'), 'height': self.get_xml_attr(stream_item, 'height'), 'aspect_ratio': self.get_xml_attr(stream_item, 'aspectRatio'), 'video_framerate': self.get_xml_attr(stream_item, 'videoFrameRate'), 'video_codec': self.get_xml_attr(stream_item, 'videoCodec'), 'audio_codec': self.get_xml_attr(stream_item, 'audioCodec'), 'audio_channels': self.get_xml_attr(stream_item, 'audioChannels'), 'transcode_video_dec': transcode_video_dec, 'transcode_video_codec': transcode_video_codec, 'transcode_height': transcode_height, 'transcode_width': transcode_width, 'transcode_audio_dec': transcode_audio_dec, 'transcode_audio_codec': transcode_audio_codec, 'transcode_audio_channels': transcode_audio_channels, 'media_type': media_type, 'title': title, 'grandparent_title': grandparent_title } return stream_output
def extract_plexwatch_xml(xml=None): output = {} clean_xml = helpers.latinToAscii(xml) try: xml_parse = minidom.parseString(clean_xml) except: logger.warn( u"PlexPy Importer :: Error parsing XML for Plexwatch database.") return None xml_head = xml_parse.getElementsByTagName('opt') if not xml_head: logger.warn( u"PlexPy Importer :: Error parsing XML for Plexwatch database.") return None for a in xml_head: added_at = helpers.get_xml_attr(a, 'addedAt') art = helpers.get_xml_attr(a, 'art') duration = helpers.get_xml_attr(a, 'duration') grandparent_thumb = helpers.get_xml_attr(a, 'grandparentThumb') grandparent_title = helpers.get_xml_attr(a, 'grandparentTitle') guid = helpers.get_xml_attr(a, 'guid') section_id = helpers.get_xml_attr(a, 'librarySectionID') media_index = helpers.get_xml_attr(a, 'index') originally_available_at = helpers.get_xml_attr( a, 'originallyAvailableAt') last_viewed_at = helpers.get_xml_attr(a, 'lastViewedAt') parent_media_index = helpers.get_xml_attr(a, 'parentIndex') parent_thumb = helpers.get_xml_attr(a, 'parentThumb') rating = helpers.get_xml_attr(a, 'rating') thumb = helpers.get_xml_attr(a, 'thumb') media_type = helpers.get_xml_attr(a, 'type') updated_at = helpers.get_xml_attr(a, 'updatedAt') view_offset = helpers.get_xml_attr(a, 'viewOffset') year = helpers.get_xml_attr(a, 'year') parent_title = helpers.get_xml_attr(a, 'parentTitle') studio = helpers.get_xml_attr(a, 'studio') title = helpers.get_xml_attr(a, 'title') tagline = helpers.get_xml_attr(a, 'tagline') directors = [] if a.getElementsByTagName('Director'): director_elem = a.getElementsByTagName('Director') for b in director_elem: directors.append(helpers.get_xml_attr(b, 'tag')) aspect_ratio = '' audio_channels = None audio_codec = '' bitrate = None container = '' height = None video_codec = '' video_framerate = '' video_resolution = '' width = None if a.getElementsByTagName('Media'): media_elem = a.getElementsByTagName('Media') for c in media_elem: aspect_ratio = helpers.get_xml_attr(c, 'aspectRatio') audio_channels = helpers.get_xml_attr(c, 'audioChannels') audio_codec = helpers.get_xml_attr(c, 'audioCodec') bitrate = helpers.get_xml_attr(c, 'bitrate') container = helpers.get_xml_attr(c, 'container') height = helpers.get_xml_attr(c, 'height') video_codec = helpers.get_xml_attr(c, 'videoCodec') video_framerate = helpers.get_xml_attr(c, 'videoFrameRate') video_resolution = helpers.get_xml_attr(c, 'videoResolution') width = helpers.get_xml_attr(c, 'width') machine_id = '' platform = '' player = '' if a.getElementsByTagName('Player'): player_elem = a.getElementsByTagName('Player') for d in player_elem: machine_id = helpers.get_xml_attr(d, 'machineIdentifier') platform = helpers.get_xml_attr(d, 'platform') player = helpers.get_xml_attr(d, 'title') transcode_audio_channels = None transcode_audio_codec = '' audio_decision = 'direct play' transcode_container = '' transcode_height = None transcode_protocol = '' transcode_video_codec = '' video_decision = 'direct play' transcode_width = None if a.getElementsByTagName('TranscodeSession'): transcode_elem = a.getElementsByTagName('TranscodeSession') for e in transcode_elem: transcode_audio_channels = helpers.get_xml_attr( e, 'audioChannels') transcode_audio_codec = helpers.get_xml_attr(e, 'audioCodec') audio_decision = helpers.get_xml_attr(e, 'audioDecision') transcode_container = helpers.get_xml_attr(e, 'container') transcode_height = helpers.get_xml_attr(e, 'height') transcode_protocol = helpers.get_xml_attr(e, 'protocol') transcode_video_codec = helpers.get_xml_attr(e, 'videoCodec') video_decision = helpers.get_xml_attr(e, 'videoDecision') transcode_width = helpers.get_xml_attr(e, 'width') user_id = None if a.getElementsByTagName('User'): user_elem = a.getElementsByTagName('User') for f in user_elem: user_id = helpers.get_xml_attr(f, 'id') writers = [] if a.getElementsByTagName('Writer'): writer_elem = a.getElementsByTagName('Writer') for g in writer_elem: writers.append(helpers.get_xml_attr(g, 'tag')) actors = [] if a.getElementsByTagName('Role'): actor_elem = a.getElementsByTagName('Role') for h in actor_elem: actors.append(helpers.get_xml_attr(h, 'tag')) genres = [] if a.getElementsByTagName('Genre'): genre_elem = a.getElementsByTagName('Genre') for i in genre_elem: genres.append(helpers.get_xml_attr(i, 'tag')) output = { 'added_at': added_at, 'art': art, 'duration': duration, 'grandparent_thumb': grandparent_thumb, 'grandparent_title': grandparent_title, 'parent_title': parent_title, 'title': title, 'tagline': tagline, 'guid': guid, 'section_id': section_id, 'media_index': media_index, 'originally_available_at': originally_available_at, 'last_viewed_at': last_viewed_at, 'parent_media_index': parent_media_index, 'parent_thumb': parent_thumb, 'rating': rating, 'thumb': thumb, 'media_type': media_type, 'updated_at': updated_at, 'view_offset': view_offset, 'year': year, 'directors': directors, 'aspect_ratio': aspect_ratio, 'audio_channels': audio_channels, 'audio_codec': audio_codec, 'bitrate': bitrate, 'container': container, 'height': height, 'video_codec': video_codec, 'video_framerate': video_framerate, 'video_resolution': video_resolution, 'width': width, 'machine_id': machine_id, 'platform': platform, 'player': player, 'transcode_audio_channels': transcode_audio_channels, 'transcode_audio_codec': transcode_audio_codec, 'audio_decision': audio_decision, 'transcode_container': transcode_container, 'transcode_height': transcode_height, 'transcode_protocol': transcode_protocol, 'transcode_video_codec': transcode_video_codec, 'video_decision': video_decision, 'transcode_width': transcode_width, 'user_id': user_id, 'writers': writers, 'actors': actors, 'genres': genres, 'studio': studio } return output
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(u"PlexPy Importer :: Invalid filename.") return None except ValueError: logger.error(u"PlexPy Importer :: Invalid filename.") return None try: connection.execute('SELECT ratingKey from %s' % table_name) except sqlite3.OperationalError: logger.error(u"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(activity_pinger.check_active_sessions, 'Check for active sessions', hours=0, minutes=0, seconds=0) plexpy.schedule_job(activity_pinger.check_recently_added, 'Check for recently added items', hours=0, minutes=0, seconds=0) plexpy.schedule_job(activity_pinger.check_server_response, 'Check for Plex remote access', hours=0, minutes=0, seconds=0) ap = activity_processor.ActivityProcessor() user_data = users.Users() # 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 record with ratingKey %s due to malformed xml." % str(row['rating_key'])) continue # Skip line if we don't have a ratingKey to work with if not row['rating_key']: logger.error(u"PlexPy Importer :: Skipping record due to null ratingKey.") continue # If the user_id no longer exists in the friends list, pull it from the xml. if user_data.get_user_id(user=row['user']): user_id = user_data.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'], 'media_index': extracted_xml['media_index'], 'parent_media_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'], 'tagline': extracted_xml['tagline'], 'rating': extracted_xml['rating'], 'duration': extracted_xml['duration'], 'guid': extracted_xml['guid'], 'section_id': extracted_xml['section_id'], '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(): ap.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()
return [] try: logfile = open(log_file, "r") except IOError, e: logger.error('Unable to open Plex Log file. %s' % e) return [] log_lines = tail(logfile, window) if parsed: line_error = False clean_lines = [] for i in log_lines: try: i = helpers.latinToAscii(i) log_time = i.split(' [')[0] log_level = i.split('] ', 1)[1].split(' - ',1)[0] log_msg = i.split('] ', 1)[1].split(' - ',1)[1] full_line = [log_time, log_level, log_msg] clean_lines.append(full_line) except: line_error = True full_line = ['', '', 'Unable to parse log line.'] clean_lines.append(full_line) if line_error: logger.error('PlexPy was unable to parse some lines of the Plex Media Server log.') return clean_lines else:
def _getHistory(self, iDisplayStart=0, iDisplayLength=100, sSearch="", iSortCol_0='0', sSortDir_0='asc', **kwargs): iDisplayStart = int(iDisplayStart) iDisplayLength = int(iDisplayLength) filtered = [] totalcount = 0 myDB = db.DBConnection() db_table = db.DBConnection().get_history_table_name() sortcolumn = 'time' sortbyhavepercent = False if iSortCol_0 == '1': sortcolumn = 'user' if iSortCol_0 == '2': sortcolumn = 'platform' elif iSortCol_0 == '3': sortcolumn = 'ip_address' elif iSortCol_0 == '4': sortcolumn = 'title' elif iSortCol_0 == '5': sortcolumn = 'time' elif iSortCol_0 == '6': sortcolumn = 'paused_counter' elif iSortCol_0 == '7': sortcolumn = 'stopped' elif iSortCol_0 == '8': sortbyhavepercent = True if sSearch == "": query = 'SELECT * from %s order by %s COLLATE NOCASE %s' % (db_table, sortcolumn, sSortDir_0) filtered = myDB.select(query) totalcount = len(filtered) else: query = 'SELECT * from ' + db_table + ' WHERE user LIKE "%' + sSearch + \ '%" OR title LIKE "%' + sSearch + '%"' + 'ORDER BY %s COLLATE NOCASE %s' % (sortcolumn, sSortDir_0) filtered = myDB.select(query) totalcount = myDB.select('SELECT COUNT(*) from processed')[0][0] history = filtered[iDisplayStart:(iDisplayStart + iDisplayLength)] rows = [] for item in history: row = {"date": item['time'], "user": item["user"], "platform": item["platform"], "ip_address": item["ip_address"], "title": item["title"], "started": item["time"], "paused": item["paused_counter"], "stopped": item["stopped"], "duration": "", "percent_complete": 0, } if item['paused_counter'] > 0: row['paused'] = item['paused_counter'] else: row['paused'] = 0 if item['time']: if item['stopped'] > 0: stopped = item['stopped'] else: stopped = 0 if item['paused_counter'] > 0: paused_counter = item['paused_counter'] else: paused_counter = 0 row['duration'] = stopped - item['time'] + paused_counter try: xml_parse = minidom.parseString(helpers.latinToAscii(item['xml'])) except IOError, e: logger.warn("Error parsing XML in PlexWatch db: %s" % e) xml_head = xml_parse.getElementsByTagName('opt') if not xml_head: logger.warn("Error parsing XML in PlexWatch db: %s" % e) for s in xml_head: if s.getAttribute('duration') and s.getAttribute('viewOffset'): view_offset = helpers.cast_to_float(s.getAttribute('viewOffset')) duration = helpers.cast_to_float(s.getAttribute('duration')) if duration > 0: row['percent_complete'] = (view_offset / duration)*100 else: row['percent_complete'] = 0 rows.append(row)
def get_home_stats(self, time_range='30'): myDB = db.DBConnection() if not time_range.isdigit(): time_range = '30' stats_queries = ["top_tv", "popular_tv", "top_users", "top_platforms"] home_stats = [] for stat in stats_queries: if 'top_tv' in stat: top_tv = [] try: query = 'SELECT orig_title, COUNT(orig_title) as total_plays, ' \ 'grandparentRatingKey, MAX(time) as last_watch, xml ' \ 'FROM %s ' \ 'WHERE datetime(stopped, "unixepoch", "localtime") ' \ '>= datetime("now", "-%s days", "localtime") ' \ 'AND episode != "" ' \ 'GROUP BY orig_title ' \ 'ORDER BY total_plays DESC LIMIT 10' % (self.get_history_table_name(), time_range) result = myDB.select(query) except: logger.warn("Unable to open PlexWatch database.") return None for item in result: xml_data = helpers.latinToAscii(item[4]) try: xml_parse = minidom.parseString(xml_data) except: logger.warn( "Error parsing XML for Plexwatch database.") return None xml_head = xml_parse.getElementsByTagName('opt') if not xml_head: logger.warn( "Error parsing XML for Plexwatch database.") return None for a in xml_head: grandparent_thumb = self.get_xml_attr( a, 'grandparentThumb') row = { 'title': item[0], 'total_plays': item[1], 'users_watched': '', 'rating_key': item[2], 'last_play': item[3], 'grandparent_thumb': grandparent_thumb, 'thumb': '', 'user': '', 'friendly_name': '', 'platform_type': '', 'platform': '' } top_tv.append(row) home_stats.append({'stat_id': stat, 'rows': top_tv}) elif 'popular_tv' in stat: popular_tv = [] try: query = 'SELECT orig_title, COUNT(DISTINCT user) as users_watched, grandparentRatingKey, ' \ 'MAX(time) as last_watch, xml, COUNT(id) as total_plays ' \ 'FROM %s ' \ 'WHERE datetime(stopped, "unixepoch", "localtime") ' \ '>= datetime("now", "-%s days", "localtime") ' \ 'AND episode != "" ' \ 'GROUP BY orig_title ' \ 'ORDER BY users_watched DESC, total_plays DESC ' \ 'LIMIT 10' % (self.get_history_table_name(), time_range) result = myDB.select(query) except: logger.warn("Unable to open PlexWatch database.") return None for item in result: xml_data = helpers.latinToAscii(item[4]) try: xml_parse = minidom.parseString(xml_data) except: logger.warn( "Error parsing XML for Plexwatch database.") return None xml_head = xml_parse.getElementsByTagName('opt') if not xml_head: logger.warn( "Error parsing XML for Plexwatch database.") return None for a in xml_head: grandparent_thumb = self.get_xml_attr( a, 'grandparentThumb') row = { 'title': item[0], 'users_watched': item[1], 'rating_key': item[2], 'last_play': item[3], 'total_plays': item[5], 'grandparent_thumb': grandparent_thumb, 'thumb': '', 'user': '', 'friendly_name': '', 'platform_type': '', 'platform': '' } popular_tv.append(row) home_stats.append({'stat_id': stat, 'rows': popular_tv}) elif 'top_users' in stat: top_users = [] try: s = self.get_history_table_name() query = 'SELECT user, ' \ '(case when friendly_name is null then user else friendly_name end) as friendly_name,' \ 'COUNT(' + s + '.id) as total_plays, MAX(time) as last_watch, thumb ' \ 'FROM ' + s + ' ' \ 'LEFT OUTER JOIN plexpy_users ON ' + s + '.user = plexpy_users.username ' \ 'WHERE datetime(stopped, "unixepoch", "localtime") >= ' \ 'datetime("now", "-' + time_range + ' days", "localtime") '\ 'GROUP BY ' + s + '.user ' \ 'ORDER BY total_plays DESC LIMIT 10' result = myDB.select(query) except: logger.warn("Unable to open PlexWatch database.") return None for item in result: if not item['thumb'] or item['thumb'] == '': user_thumb = common.DEFAULT_USER_THUMB else: user_thumb = item[4] thumb = self.get_user_gravatar_image(item[0]) row = { 'user': item[0], 'friendly_name': item[1], 'total_plays': item[2], 'last_play': item[3], 'thumb': user_thumb, 'grandparent_thumb': '', 'users_watched': '', 'rating_key': '', 'title': '', 'platform_type': '', 'platform': '' } top_users.append(row) home_stats.append({'stat_id': stat, 'rows': top_users}) elif 'top_platforms' in stat: top_platform = [] try: query = 'SELECT platform, COUNT(id) as total_plays, MAX(time) as last_watch, xml ' \ 'FROM %s ' \ 'WHERE datetime(stopped, "unixepoch", "localtime") ' \ '>= datetime("now", "-%s days", "localtime") ' \ 'GROUP BY platform ' \ 'ORDER BY total_plays DESC' % (self.get_history_table_name(), time_range) result = myDB.select(query) except: logger.warn("Unable to open PlexWatch database.") return None for item in result: xml_data = helpers.latinToAscii(item[3]) try: xml_parse = minidom.parseString(xml_data) except: logger.warn( "Error parsing XML for Plexwatch database.") return None xml_head = xml_parse.getElementsByTagName('Player') if not xml_head: logger.warn( "Error parsing XML for Plexwatch database.") return None for a in xml_head: platform_type = self.get_xml_attr(a, 'platform') row = { 'platform': item[0], 'total_plays': item[1], 'last_play': item[2], 'platform_type': platform_type, 'title': '', 'thumb': '', 'grandparent_thumb': '', 'users_watched': '', 'rating_key': '', 'user': '', 'friendly_name': '' } top_platform.append(row) top_platform_aggr = self.group_and_sum_dataset( top_platform, 'platform_type', ['total_plays'], 'total_plays') home_stats.append({'stat_id': stat, 'rows': top_platform_aggr}) return home_stats
def get_home_stats(self, time_range='30'): myDB = db.DBConnection() if not time_range.isdigit(): time_range = '30' stats_queries = ["top_tv", "popular_tv", "top_users", "top_platforms"] home_stats = [] for stat in stats_queries: if 'top_tv' in stat: top_tv = [] try: query = 'SELECT orig_title, COUNT(orig_title) as total_plays, grandparentRatingKey, MAX(time) as last_watch, xml ' \ 'FROM %s ' \ 'WHERE datetime(stopped, "unixepoch", "localtime") >= datetime("now", "-%s days", "localtime") ' \ 'AND episode != "" ' \ 'GROUP BY orig_title ' \ 'ORDER BY total_plays DESC LIMIT 10' % (self.get_history_table_name(), time_range) result = myDB.select(query) except: logger.warn("Unable to open PlexWatch database.") return None for item in result: xml_data = helpers.latinToAscii(item[4]) try: xml_parse = minidom.parseString(xml_data) except: logger.warn("Error parsing XML for Plexwatch database.") return None xml_head = xml_parse.getElementsByTagName('opt') if not xml_head: logger.warn("Error parsing XML for Plexwatch database.") return None for a in xml_head: grandparent_thumb = self.get_xml_attr(a, 'grandparentThumb') row = {'orig_title': item[0], 'total_plays': item[1], 'rating_key': item[2], 'last_play': item[3], 'grandparent_thumb': grandparent_thumb } top_tv.append(row) home_stats.append({'stat_id': stat, 'rows': top_tv}) elif 'popular_tv' in stat: popular_tv = [] try: query = 'SELECT orig_title, COUNT(DISTINCT user) as users_watched, grandparentRatingKey, ' \ 'MAX(time) as last_watch, xml, COUNT(id) as total_plays ' \ 'FROM %s ' \ 'WHERE datetime(stopped, "unixepoch", "localtime") >= datetime("now", "-%s days", "localtime") ' \ 'AND episode != "" ' \ 'GROUP BY orig_title ' \ 'ORDER BY users_watched DESC, total_plays DESC LIMIT 10' % (self.get_history_table_name(), time_range) result = myDB.select(query) except: logger.warn("Unable to open PlexWatch database.") return None for item in result: xml_data = helpers.latinToAscii(item[4]) try: xml_parse = minidom.parseString(xml_data) except: logger.warn("Error parsing XML for Plexwatch database.") return None xml_head = xml_parse.getElementsByTagName('opt') if not xml_head: logger.warn("Error parsing XML for Plexwatch database.") return None for a in xml_head: grandparent_thumb = self.get_xml_attr(a, 'grandparentThumb') row = {'orig_title': item[0], 'users_watched': item[1], 'rating_key': item[2], 'last_play': item[3], 'total_plays': item[5], 'grandparent_thumb': grandparent_thumb } popular_tv.append(row) home_stats.append({'stat_id': stat, 'rows': popular_tv}) elif 'top_users' in stat: top_users = [] try: query = 'SELECT user, COUNT(id) as total_plays, MAX(time) as last_watch ' \ 'FROM %s ' \ 'WHERE datetime(stopped, "unixepoch", "localtime") >= datetime("now", "-%s days", "localtime") ' \ 'GROUP BY user ' \ 'ORDER BY total_plays DESC LIMIT 10' % (self.get_history_table_name(), time_range) result = myDB.select(query) except: logger.warn("Unable to open PlexWatch database.") return None for item in result: thumb = self.get_user_gravatar_image(item[0]) row = {'user': item[0], 'total_plays': item[1], 'last_play': item[2], 'thumb': thumb['user_thumb'] } top_users.append(row) home_stats.append({'stat_id': stat, 'rows': top_users}) elif 'top_platforms' in stat: top_platform = [] try: query = 'SELECT platform, COUNT(id) as total_plays, MAX(time) as last_watch, xml ' \ 'FROM %s ' \ 'WHERE datetime(stopped, "unixepoch", "localtime") >= datetime("now", "-%s days", "localtime") ' \ 'GROUP BY platform ' \ 'ORDER BY total_plays DESC' % (self.get_history_table_name(), time_range) result = myDB.select(query) except: logger.warn("Unable to open PlexWatch database.") return None for item in result: xml_data = helpers.latinToAscii(item[3]) try: xml_parse = minidom.parseString(xml_data) except: logger.warn("Error parsing XML for Plexwatch database.") return None xml_head = xml_parse.getElementsByTagName('Player') if not xml_head: logger.warn("Error parsing XML for Plexwatch database.") return None for a in xml_head: platform_type = self.get_xml_attr(a, 'platform') row = {'platform': item[0], 'total_plays': item[1], 'last_play': item[2], 'platform_type': platform_type } top_platform.append(row) top_platform_aggr = self.group_and_sum_dataset( top_platform, 'platform_type', ['total_plays'], 'total_plays') home_stats.append({'stat_id': stat, 'rows': top_platform_aggr}) return home_stats
def extract_plexwatch_xml(xml=None): output = {} clean_xml = helpers.latinToAscii(xml) try: xml_parse = minidom.parseString(clean_xml) except: logger.warn("Error parsing XML for Plexwatch database.") return None xml_head = xml_parse.getElementsByTagName("opt") if not xml_head: logger.warn("Error parsing XML for Plexwatch database.") return None for a in xml_head: added_at = helpers.get_xml_attr(a, "addedAt") art = helpers.get_xml_attr(a, "art") duration = helpers.get_xml_attr(a, "duration") grandparent_thumb = helpers.get_xml_attr(a, "grandparentThumb") grandparent_title = helpers.get_xml_attr(a, "grandparentTitle") guid = helpers.get_xml_attr(a, "guid") media_index = helpers.get_xml_attr(a, "index") originally_available_at = helpers.get_xml_attr(a, "originallyAvailableAt") last_viewed_at = helpers.get_xml_attr(a, "lastViewedAt") parent_media_index = helpers.get_xml_attr(a, "parentIndex") parent_thumb = helpers.get_xml_attr(a, "parentThumb") rating = helpers.get_xml_attr(a, "rating") thumb = helpers.get_xml_attr(a, "thumb") media_type = helpers.get_xml_attr(a, "type") updated_at = helpers.get_xml_attr(a, "updatedAt") view_offset = helpers.get_xml_attr(a, "viewOffset") year = helpers.get_xml_attr(a, "year") parent_title = helpers.get_xml_attr(a, "parentTitle") studio = helpers.get_xml_attr(a, "studio") title = helpers.get_xml_attr(a, "title") tagline = helpers.get_xml_attr(a, "tagline") directors = [] if a.getElementsByTagName("Director"): director_elem = a.getElementsByTagName("Director") for b in director_elem: directors.append(helpers.get_xml_attr(b, "tag")) aspect_ratio = "" audio_channels = None audio_codec = "" bitrate = None container = "" height = None video_codec = "" video_framerate = "" video_resolution = "" width = None if a.getElementsByTagName("Media"): media_elem = a.getElementsByTagName("Media") for c in media_elem: aspect_ratio = helpers.get_xml_attr(c, "aspectRatio") audio_channels = helpers.get_xml_attr(c, "audioChannels") audio_codec = helpers.get_xml_attr(c, "audioCodec") bitrate = helpers.get_xml_attr(c, "bitrate") container = helpers.get_xml_attr(c, "container") height = helpers.get_xml_attr(c, "height") video_codec = helpers.get_xml_attr(c, "videoCodec") video_framerate = helpers.get_xml_attr(c, "videoFrameRate") video_resolution = helpers.get_xml_attr(c, "videoResolution") width = helpers.get_xml_attr(c, "width") machine_id = "" platform = "" player = "" if a.getElementsByTagName("Player"): player_elem = a.getElementsByTagName("Player") for d in player_elem: machine_id = helpers.get_xml_attr(d, "machineIdentifier") platform = helpers.get_xml_attr(d, "platform") player = helpers.get_xml_attr(d, "title") transcode_audio_channels = None transcode_audio_codec = "" audio_decision = "direct play" transcode_container = "" transcode_height = None transcode_protocol = "" transcode_video_codec = "" video_decision = "direct play" transcode_width = None if a.getElementsByTagName("TranscodeSession"): transcode_elem = a.getElementsByTagName("TranscodeSession") for e in transcode_elem: transcode_audio_channels = helpers.get_xml_attr(e, "audioChannels") transcode_audio_codec = helpers.get_xml_attr(e, "audioCodec") audio_decision = helpers.get_xml_attr(e, "audioDecision") transcode_container = helpers.get_xml_attr(e, "container") transcode_height = helpers.get_xml_attr(e, "height") transcode_protocol = helpers.get_xml_attr(e, "protocol") transcode_video_codec = helpers.get_xml_attr(e, "videoCodec") video_decision = helpers.get_xml_attr(e, "videoDecision") transcode_width = helpers.get_xml_attr(e, "width") user_id = None if a.getElementsByTagName("User"): user_elem = a.getElementsByTagName("User") for f in user_elem: user_id = helpers.get_xml_attr(f, "id") writers = [] if a.getElementsByTagName("Writer"): writer_elem = a.getElementsByTagName("Writer") for g in writer_elem: writers.append(helpers.get_xml_attr(g, "tag")) actors = [] if a.getElementsByTagName("Role"): actor_elem = a.getElementsByTagName("Role") for h in actor_elem: actors.append(helpers.get_xml_attr(h, "tag")) genres = [] if a.getElementsByTagName("Genre"): genre_elem = a.getElementsByTagName("Genre") for i in genre_elem: genres.append(helpers.get_xml_attr(i, "tag")) output = { "added_at": added_at, "art": art, "duration": duration, "grandparent_thumb": grandparent_thumb, "grandparent_title": grandparent_title, "parent_title": parent_title, "title": title, "tagline": tagline, "guid": guid, "media_index": media_index, "originally_available_at": originally_available_at, "last_viewed_at": last_viewed_at, "parent_media_index": parent_media_index, "parent_thumb": parent_thumb, "rating": rating, "thumb": thumb, "media_type": media_type, "updated_at": updated_at, "view_offset": view_offset, "year": year, "directors": directors, "aspect_ratio": aspect_ratio, "audio_channels": audio_channels, "audio_codec": audio_codec, "bitrate": bitrate, "container": container, "height": height, "video_codec": video_codec, "video_framerate": video_framerate, "video_resolution": video_resolution, "width": width, "machine_id": machine_id, "platform": platform, "player": player, "transcode_audio_channels": transcode_audio_channels, "transcode_audio_codec": transcode_audio_codec, "audio_decision": audio_decision, "transcode_container": transcode_container, "transcode_height": transcode_height, "transcode_protocol": transcode_protocol, "transcode_video_codec": transcode_video_codec, "video_decision": video_decision, "transcode_width": transcode_width, "user_id": user_id, "writers": writers, "actors": actors, "genres": genres, "studio": studio, } return output
def extract_plexwatch_xml(xml=None): output = {} clean_xml = helpers.latinToAscii(xml) try: xml_parse = minidom.parseString(clean_xml) except: logger.warn(u"PlexPy Importer :: Error parsing XML for Plexwatch database.") return None xml_head = xml_parse.getElementsByTagName('opt') if not xml_head: logger.warn(u"PlexPy Importer :: Error parsing XML for Plexwatch database.") return None for a in xml_head: added_at = helpers.get_xml_attr(a, 'addedAt') art = helpers.get_xml_attr(a, 'art') duration = helpers.get_xml_attr(a, 'duration') grandparent_thumb = helpers.get_xml_attr(a, 'grandparentThumb') grandparent_title = helpers.get_xml_attr(a, 'grandparentTitle') guid = helpers.get_xml_attr(a, 'guid') section_id = helpers.get_xml_attr(a, 'librarySectionID') media_index = helpers.get_xml_attr(a, 'index') originally_available_at = helpers.get_xml_attr(a, 'originallyAvailableAt') last_viewed_at = helpers.get_xml_attr(a, 'lastViewedAt') parent_media_index = helpers.get_xml_attr(a, 'parentIndex') parent_thumb = helpers.get_xml_attr(a, 'parentThumb') rating = helpers.get_xml_attr(a, 'rating') thumb = helpers.get_xml_attr(a, 'thumb') media_type = helpers.get_xml_attr(a, 'type') updated_at = helpers.get_xml_attr(a, 'updatedAt') view_offset = helpers.get_xml_attr(a, 'viewOffset') year = helpers.get_xml_attr(a, 'year') parent_title = helpers.get_xml_attr(a, 'parentTitle') studio = helpers.get_xml_attr(a, 'studio') title = helpers.get_xml_attr(a, 'title') tagline = helpers.get_xml_attr(a, 'tagline') directors = [] if a.getElementsByTagName('Director'): director_elem = a.getElementsByTagName('Director') for b in director_elem: directors.append(helpers.get_xml_attr(b, 'tag')) aspect_ratio = '' audio_channels = None audio_codec = '' bitrate = None container = '' height = None video_codec = '' video_framerate = '' video_resolution = '' width = None if a.getElementsByTagName('Media'): media_elem = a.getElementsByTagName('Media') for c in media_elem: aspect_ratio = helpers.get_xml_attr(c, 'aspectRatio') audio_channels = helpers.get_xml_attr(c, 'audioChannels') audio_codec = helpers.get_xml_attr(c, 'audioCodec') bitrate = helpers.get_xml_attr(c, 'bitrate') container = helpers.get_xml_attr(c, 'container') height = helpers.get_xml_attr(c, 'height') video_codec = helpers.get_xml_attr(c, 'videoCodec') video_framerate = helpers.get_xml_attr(c, 'videoFrameRate') video_resolution = helpers.get_xml_attr(c, 'videoResolution') width = helpers.get_xml_attr(c, 'width') machine_id = '' platform = '' player = '' if a.getElementsByTagName('Player'): player_elem = a.getElementsByTagName('Player') for d in player_elem: machine_id = helpers.get_xml_attr(d, 'machineIdentifier') platform = helpers.get_xml_attr(d, 'platform') player = helpers.get_xml_attr(d, 'title') transcode_audio_channels = None transcode_audio_codec = '' audio_decision = 'direct play' transcode_container = '' transcode_height = None transcode_protocol = '' transcode_video_codec = '' video_decision = 'direct play' transcode_width = None if a.getElementsByTagName('TranscodeSession'): transcode_elem = a.getElementsByTagName('TranscodeSession') for e in transcode_elem: transcode_audio_channels = helpers.get_xml_attr(e, 'audioChannels') transcode_audio_codec = helpers.get_xml_attr(e, 'audioCodec') audio_decision = helpers.get_xml_attr(e, 'audioDecision') transcode_container = helpers.get_xml_attr(e, 'container') transcode_height = helpers.get_xml_attr(e, 'height') transcode_protocol = helpers.get_xml_attr(e, 'protocol') transcode_video_codec = helpers.get_xml_attr(e, 'videoCodec') video_decision = helpers.get_xml_attr(e, 'videoDecision') transcode_width = helpers.get_xml_attr(e, 'width') user_id = None if a.getElementsByTagName('User'): user_elem = a.getElementsByTagName('User') for f in user_elem: user_id = helpers.get_xml_attr(f, 'id') writers = [] if a.getElementsByTagName('Writer'): writer_elem = a.getElementsByTagName('Writer') for g in writer_elem: writers.append(helpers.get_xml_attr(g, 'tag')) actors = [] if a.getElementsByTagName('Role'): actor_elem = a.getElementsByTagName('Role') for h in actor_elem: actors.append(helpers.get_xml_attr(h, 'tag')) genres = [] if a.getElementsByTagName('Genre'): genre_elem = a.getElementsByTagName('Genre') for i in genre_elem: genres.append(helpers.get_xml_attr(i, 'tag')) output = {'added_at': added_at, 'art': art, 'duration': duration, 'grandparent_thumb': grandparent_thumb, 'grandparent_title': grandparent_title, 'parent_title': parent_title, 'title': title, 'tagline': tagline, 'guid': guid, 'section_id': section_id, 'media_index': media_index, 'originally_available_at': originally_available_at, 'last_viewed_at': last_viewed_at, 'parent_media_index': parent_media_index, 'parent_thumb': parent_thumb, 'rating': rating, 'thumb': thumb, 'media_type': media_type, 'updated_at': updated_at, 'view_offset': view_offset, 'year': year, 'directors': directors, 'aspect_ratio': aspect_ratio, 'audio_channels': audio_channels, 'audio_codec': audio_codec, 'bitrate': bitrate, 'container': container, 'height': height, 'video_codec': video_codec, 'video_framerate': video_framerate, 'video_resolution': video_resolution, 'width': width, 'machine_id': machine_id, 'platform': platform, 'player': player, 'transcode_audio_channels': transcode_audio_channels, 'transcode_audio_codec': transcode_audio_codec, 'audio_decision': audio_decision, 'transcode_container': transcode_container, 'transcode_height': transcode_height, 'transcode_protocol': transcode_protocol, 'transcode_video_codec': transcode_video_codec, 'video_decision': video_decision, 'transcode_width': transcode_width, 'user_id': user_id, 'writers': writers, 'actors': actors, 'genres': genres, 'studio': studio } return output
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( activity_pinger.check_active_sessions, "Check for active sessions", hours=0, minutes=0, seconds=0 ) ap = activity_processor.ActivityProcessor() user_data = users.Users() # 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 user_data.get_user_id(user=row["user"]): user_id = user_data.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"], "tagline": extracted_xml["tagline"], "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(): ap.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()
def _getHistory(self, iDisplayStart=0, iDisplayLength=100, sSearch="", iSortCol_0='0', sSortDir_0='asc', **kwargs): iDisplayStart = int(iDisplayStart) iDisplayLength = int(iDisplayLength) filtered = [] totalcount = 0 myDB = db.DBConnection() db_table = db.DBConnection().get_history_table_name() sortcolumn = 'time' sortbyhavepercent = False if iSortCol_0 == '1': sortcolumn = 'user' if iSortCol_0 == '2': sortcolumn = 'platform' elif iSortCol_0 == '3': sortcolumn = 'ip_address' elif iSortCol_0 == '4': sortcolumn = 'title' elif iSortCol_0 == '5': sortcolumn = 'time' elif iSortCol_0 == '6': sortcolumn = 'paused_counter' elif iSortCol_0 == '7': sortcolumn = 'stopped' elif iSortCol_0 == '8': sortbyhavepercent = True if sSearch == "": query = 'SELECT * from %s order by %s COLLATE NOCASE %s' % ( db_table, sortcolumn, sSortDir_0) filtered = myDB.select(query) totalcount = len(filtered) else: query = 'SELECT * from ' + db_table + ' WHERE user LIKE "%' + sSearch + \ '%" OR title LIKE "%' + sSearch + '%"' + 'ORDER BY %s COLLATE NOCASE %s' % (sortcolumn, sSortDir_0) filtered = myDB.select(query) totalcount = myDB.select('SELECT COUNT(*) from processed')[0][0] history = filtered[iDisplayStart:(iDisplayStart + iDisplayLength)] rows = [] for item in history: row = { "date": item['time'], "user": item["user"], "platform": item["platform"], "ip_address": item["ip_address"], "title": item["title"], "started": item["time"], "paused": item["paused_counter"], "stopped": item["stopped"], "duration": "", "percent_complete": 0, } if item['paused_counter'] > 0: row['paused'] = item['paused_counter'] else: row['paused'] = 0 if item['time']: if item['stopped'] > 0: stopped = item['stopped'] else: stopped = 0 if item['paused_counter'] > 0: paused_counter = item['paused_counter'] else: paused_counter = 0 row['duration'] = stopped - item['time'] + paused_counter try: xml_parse = minidom.parseString( helpers.latinToAscii(item['xml'])) except IOError, e: logger.warn("Error parsing XML in PlexWatch db: %s" % e) xml_head = xml_parse.getElementsByTagName('opt') if not xml_head: logger.warn("Error parsing XML in PlexWatch db: %s" % e) for s in xml_head: if s.getAttribute('duration') and s.getAttribute('viewOffset'): view_offset = helpers.cast_to_float( s.getAttribute('viewOffset')) duration = helpers.cast_to_float( s.getAttribute('duration')) if duration > 0: row['percent_complete'] = (view_offset / duration) * 100 else: row['percent_complete'] = 0 rows.append(row)
def get_history(self, start='', length='', kwargs=None, custom_where=''): data_tables = datatables.DataTables() start = int(start) length = int(length) filtered = [] totalcount = 0 search_value = "" search_regex = "" order_column = 1 order_dir = "desc" if 'order[0][dir]' in kwargs: order_dir = kwargs.get('order[0][dir]', "desc") if 'order[0][column]' in kwargs: order_column = kwargs.get('order[0][column]', "1") if 'search[value]' in kwargs: search_value = kwargs.get('search[value]', "") if 'search[regex]' in kwargs: search_regex = kwargs.get('search[regex]', "") columns = ['id', 'time as date', 'user', 'platform', 'ip_address', 'title', 'time as started', 'paused_counter', 'stopped', 'ratingKey as rating_key', 'xml', 'round((julianday(datetime(stopped, "unixepoch", "localtime")) - \ julianday(datetime(time, "unixepoch", "localtime"))) * 86400) - \ (case when paused_counter is null then 0 else paused_counter end) as duration', 'grandparentRatingKey as grandparent_rating_key' ] try: query = data_tables.ssp_query(table_name=self.get_history_table_name(), columns=columns, start=start, length=length, order_column=int(order_column), order_dir=order_dir, search_value=search_value, search_regex=search_regex, custom_where=custom_where, group_by='', kwargs=kwargs) except: logger.warn("Unable to open PlexWatch database.") return {'recordsFiltered': 0, 'recordsTotal': 0, 'data': 'null'}, history = query['result'] rows = [] # NOTE: We are adding in a blank xml field in order enable the Datatables "searchable" parameter for item in history: row = {"id": item['id'], "date": item['date'], "user": item["user"], "platform": item["platform"], "ip_address": item["ip_address"], "title": item["title"], "started": item["started"], "paused_counter": item["paused_counter"], "stopped": item["stopped"], "rating_key": item["rating_key"], "duration": item["duration"], "percent_complete": 0, "xml": ""} if item['paused_counter'] > 0: row['paused_counter'] = item['paused_counter'] else: row['paused_counter'] = 0 if item['started']: if item['stopped'] > 0: stopped = item['stopped'] else: stopped = 0 if item['paused_counter'] > 0: paused_counter = item['paused_counter'] else: paused_counter = 0 try: xml_parse = minidom.parseString(helpers.latinToAscii(item['xml'])) except IOError, e: logger.warn("Error parsing XML in PlexWatch db: %s" % e) xml_head = xml_parse.getElementsByTagName('opt') if not xml_head: logger.warn("Error parsing XML in PlexWatch db: %s" % e) for s in xml_head: if s.getAttribute('duration') and s.getAttribute('viewOffset'): view_offset = helpers.cast_to_float(s.getAttribute('viewOffset')) duration = helpers.cast_to_float(s.getAttribute('duration')) if duration > 0: row['percent_complete'] = (view_offset / duration) * 100 else: row['percent_complete'] = 0 rows.append(row)
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(u"PlexPy Importer :: Invalid filename.") return None except ValueError: logger.error(u"PlexPy Importer :: Invalid filename.") return None try: connection.execute('SELECT ratingKey from %s' % table_name) except sqlite3.OperationalError: logger.error( u"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(activity_pinger.check_active_sessions, 'Check for active sessions', hours=0, minutes=0, seconds=0) plexpy.schedule_job(activity_pinger.check_recently_added, 'Check for recently added items', hours=0, minutes=0, seconds=0) plexpy.schedule_job(activity_pinger.check_server_response, 'Check for server response', hours=0, minutes=0, seconds=0) ap = activity_processor.ActivityProcessor() user_data = users.Users() # 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 record with ratingKey %s due to malformed xml." % str(row['rating_key'])) continue # Skip line if we don't have a ratingKey to work with if not row['rating_key']: logger.error( u"PlexPy Importer :: Skipping record due to null ratingRey.") continue # If the user_id no longer exists in the friends list, pull it from the xml. if user_data.get_user_id(user=row['user']): user_id = user_data.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'], 'media_index': extracted_xml['media_index'], 'parent_media_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'], 'tagline': extracted_xml['tagline'], 'rating': extracted_xml['rating'], 'duration': extracted_xml['duration'], 'guid': extracted_xml['guid'], 'section_id': extracted_xml['section_id'], '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(): ap.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()
def get_history(self, start='', length='', kwargs=None, custom_where=''): data_tables = datatables.DataTables() start = int(start) length = int(length) filtered = [] totalcount = 0 search_value = "" search_regex = "" order_column = 1 order_dir = "desc" t = self.get_history_table_name() if 'order[0][dir]' in kwargs: order_dir = kwargs.get('order[0][dir]', "desc") if 'order[0][column]' in kwargs: order_column = kwargs.get('order[0][column]', "1") if 'search[value]' in kwargs: search_value = kwargs.get('search[value]', "") if 'search[regex]' in kwargs: search_regex = kwargs.get('search[regex]', "") columns = [ t + '.id', t + '.time as date', '(case when plexpy_users.friendly_name is null then ' + t + '.user else plexpy_users.friendly_name end) as friendly_name', t + '.platform', t + '.ip_address', t + '.title', t + '.time as started', t + '.paused_counter', t + '.stopped', 'round((julianday(datetime(' + t + '.stopped, "unixepoch", "localtime")) - \ julianday(datetime(' + t + '.time, "unixepoch", "localtime"))) * 86400) - \ (case when ' + t + '.paused_counter is null then 0 else ' + t + '.paused_counter end) as duration', t + '.ratingKey as rating_key', t + '.xml', t + '.user', t + '.grandparentRatingKey as grandparent_rating_key' ] try: query = data_tables.ssp_query( table_name=t, columns=columns, start=start, length=length, order_column=int(order_column), order_dir=order_dir, search_value=search_value, search_regex=search_regex, custom_where=custom_where, group_by='', join_type='LEFT OUTER JOIN', join_table='plexpy_users', join_evals=[t + '.user', 'plexpy_users.username'], kwargs=kwargs) except: logger.warn("Unable to open PlexWatch database.") return {'recordsFiltered': 0, 'recordsTotal': 0, 'data': 'null'}, history = query['result'] rows = [] # NOTE: We are adding in a blank xml field in order enable the Datatables "searchable" parameter for item in history: row = { "id": item['id'], "date": item['date'], "friendly_name": item['friendly_name'], "platform": item["platform"], "ip_address": item["ip_address"], "title": item["title"], "started": item["started"], "paused_counter": item["paused_counter"], "stopped": item["stopped"], "rating_key": item["rating_key"], "duration": item["duration"], "percent_complete": 0, "xml": "", "user": item["user"] } if item['paused_counter'] > 0: row['paused_counter'] = item['paused_counter'] else: row['paused_counter'] = 0 if item['started']: if item['stopped'] > 0: stopped = item['stopped'] else: stopped = 0 if item['paused_counter'] > 0: paused_counter = item['paused_counter'] else: paused_counter = 0 try: xml_parse = minidom.parseString( helpers.latinToAscii(item['xml'])) except: logger.warn("Error parsing XML in PlexWatch db") xml_head = xml_parse.getElementsByTagName('opt') if not xml_head: logger.warn("Error parsing XML in PlexWatch db.") for s in xml_head: if s.getAttribute('duration') and s.getAttribute('viewOffset'): view_offset = helpers.cast_to_float( s.getAttribute('viewOffset')) duration = helpers.cast_to_float( s.getAttribute('duration')) if duration > 0: row['percent_complete'] = (view_offset / duration) * 100 else: row['percent_complete'] = 0 rows.append(row) dict = { 'recordsFiltered': query['filteredCount'], 'recordsTotal': query['totalCount'], 'data': rows, } return dict