From 7d9934e4b62bd8a4855c2175c20f4c99484e1ec6 Mon Sep 17 00:00:00 2001 From: Tim Date: Sat, 25 Jul 2015 12:40:38 +0200 Subject: [PATCH] Allow info pages to be pulled from the db instead of the Plex Server, useful for media that has been deleted. Fix home stats user link if user has no id. Fix bug in PlexWatch import script which switched around the episode and show titles. --- data/interfaces/default/current_activity.html | 4 +- data/interfaces/default/home_stats.html | 18 +++- data/interfaces/default/info.html | 4 +- .../interfaces/default/info_episode_list.html | 4 +- .../default/js/tables/history_table.js | 4 +- .../default/js/tables/sync_table.js | 2 +- data/interfaces/default/recently_added.html | 2 +- .../default/user_recently_watched.html | 2 +- plexpy/datafactory.py | 93 +++++++++++++++---- plexpy/plexwatch_import.py | 54 +++++------ plexpy/webserve.py | 14 ++- 11 files changed, 137 insertions(+), 64 deletions(-) diff --git a/data/interfaces/default/current_activity.html b/data/interfaces/default/current_activity.html index a0541c4c..64b0e9a5 100644 --- a/data/interfaces/default/current_activity.html +++ b/data/interfaces/default/current_activity.html @@ -107,9 +107,9 @@ DOCUMENTATION :: END
% if a['type'] == 'episode': - ${a['grandparent_title']} - ${a['title']} + ${a['grandparent_title']} - ${a['title']} % elif a['type'] == 'movie': - ${a['title']} + ${a['title']} % elif a['type'] == 'clip': ${a['title']} % elif a['type'] == 'track': diff --git a/data/interfaces/default/home_stats.html b/data/interfaces/default/home_stats.html index 71c0e232..c5b48d36 100644 --- a/data/interfaces/default/home_stats.html +++ b/data/interfaces/default/home_stats.html @@ -14,6 +14,8 @@ data['rows'] Returns an array containing stat data data[array_index]['rows'] :: Usable parameters +row_id Return the db row id for a metadata item if one exists + == Only if 'stat_id' is 'top_tv' or 'popular_tv' == grandparent_thumb Returns location of the item's thumbnail. Use with pms_image_proxy. rating_key Returns the unique identifier for the media item. @@ -46,7 +48,7 @@ DOCUMENTATION :: END
  • - + % if a['rows'][0]['grandparent_thumb']: @@ -58,7 +60,7 @@ DOCUMENTATION :: END @@ -73,7 +75,7 @@ DOCUMENTATION :: END
  • - + % if a['rows'][0]['grandparent_thumb'] != '': @@ -85,7 +87,7 @@ DOCUMENTATION :: END @@ -100,7 +102,11 @@ DOCUMENTATION :: END
  • + % if a['rows'][0]['user_id']: + % else: + + % endif % if a['rows'][0]['thumb'] != '': @@ -113,7 +119,11 @@ DOCUMENTATION :: END diff --git a/data/interfaces/default/info.html b/data/interfaces/default/info.html index ea4c28df..4f662a3a 100644 --- a/data/interfaces/default/info.html +++ b/data/interfaces/default/info.html @@ -58,9 +58,9 @@ from plexpy import helpers
    % if data['type'] == 'episode': - + % else: - + % endif
    diff --git a/data/interfaces/default/info_episode_list.html b/data/interfaces/default/info_episode_list.html index 06363043..ea490243 100644 --- a/data/interfaces/default/info_episode_list.html +++ b/data/interfaces/default/info_episode_list.html @@ -32,7 +32,7 @@ DOCUMENTATION :: END
  • - + @@ -45,7 +45,7 @@ DOCUMENTATION :: END
    diff --git a/data/interfaces/default/js/tables/history_table.js b/data/interfaces/default/js/tables/history_table.js index 41602602..a310ec81 100644 --- a/data/interfaces/default/js/tables/history_table.js +++ b/data/interfaces/default/js/tables/history_table.js @@ -87,11 +87,11 @@ history_table_options = { if (rowData['video_decision'] === 'transcode') { transcode_dec = ' '; } - $(td).html('
    ' + transcode_dec + '
    '); + $(td).html('
    ' + transcode_dec + '
    '); } else if (rowData['media_type'] === 'track') { $(td).html('
    ' + cellData + '
    '); } else { - $(td).html('' + cellData + ''); + $(td).html('' + cellData + ''); } } } diff --git a/data/interfaces/default/js/tables/sync_table.js b/data/interfaces/default/js/tables/sync_table.js index d4311232..7261e641 100644 --- a/data/interfaces/default/js/tables/sync_table.js +++ b/data/interfaces/default/js/tables/sync_table.js @@ -44,7 +44,7 @@ sync_table_options = { "createdCell": function (td, cellData, rowData, row, col) { if (cellData !== '') { if (rowData['metadata_type'] !== 'track') { - $(td).html('' + cellData + ''); + $(td).html('' + cellData + ''); } else { $(td).html(cellData); } diff --git a/data/interfaces/default/recently_added.html b/data/interfaces/default/recently_added.html index 4f6cd0e9..63d991a1 100644 --- a/data/interfaces/default/recently_added.html +++ b/data/interfaces/default/recently_added.html @@ -31,7 +31,7 @@ DOCUMENTATION :: END
    % if item['type'] == 'season' or item['type'] == 'movie': diff --git a/data/interfaces/default/user_recently_watched.html b/data/interfaces/default/user_recently_watched.html index 371662a5..76ed681f 100644 --- a/data/interfaces/default/user_recently_watched.html +++ b/data/interfaces/default/user_recently_watched.html @@ -34,7 +34,7 @@ DOCUMENTATION :: END
  • diff --git a/plexpy/datafactory.py b/plexpy/datafactory.py index ae84f12e..8cd090e1 100644 --- a/plexpy/datafactory.py +++ b/plexpy/datafactory.py @@ -35,7 +35,7 @@ class DataFactory(object): users.friendly_name end) as friendly_name', 'session_history.started', 'session_history.ip_address', - 'COUNT(session_history.rating_key) as plays', + 'COUNT(session_history.id) as plays', 'session_history.user', 'session_history.user_id' ] @@ -377,7 +377,8 @@ class DataFactory(object): if 'top_tv' in stat: top_tv = [] try: - query = 'SELECT session_history_metadata.grandparent_title, ' \ + query = 'SELECT session_history_metadata.id, ' \ + 'session_history_metadata.grandparent_title, ' \ 'COUNT(session_history_metadata.grandparent_title) as total_plays, ' \ 'session_history_metadata.grandparent_rating_key, ' \ 'MAX(session_history.started) as last_watch,' \ @@ -395,17 +396,18 @@ class DataFactory(object): return None for item in result: - row = {'title': item[0], - 'total_plays': item[1], + row = {'title': item[1], + 'total_plays': item[2], 'users_watched': '', - 'rating_key': item[2], - 'last_play': item[3], - 'grandparent_thumb': item[4], + 'rating_key': item[3], + 'last_play': item[4], + 'grandparent_thumb': item[5], 'thumb': '', 'user': '', 'friendly_name': '', 'platform_type': '', - 'platform': '' + 'platform': '', + 'row_id': item[0] } top_tv.append(row) @@ -415,7 +417,8 @@ class DataFactory(object): elif 'popular_tv' in stat: popular_tv = [] try: - query = 'SELECT session_history_metadata.grandparent_title, ' \ + query = 'SELECT session_history_metadata.id, ' \ + 'session_history_metadata.grandparent_title, ' \ 'COUNT(DISTINCT session_history.user_id) as users_watched, ' \ 'session_history_metadata.grandparent_rating_key, ' \ 'MAX(session_history.started) as last_watch, ' \ @@ -435,17 +438,18 @@ class DataFactory(object): return None for item in result: - row = {'title': item[0], - 'users_watched': item[1], - 'rating_key': item[2], - 'last_play': item[3], - 'total_plays': item[4], - 'grandparent_thumb': item[5], + row = {'title': item[1], + 'users_watched': item[2], + 'rating_key': item[3], + 'last_play': item[4], + 'total_plays': item[5], + 'grandparent_thumb': item[6], 'thumb': '', 'user': '', 'friendly_name': '', 'platform_type': '', - 'platform': '' + 'platform': '', + 'row_id': item[0] } popular_tv.append(row) @@ -491,7 +495,8 @@ class DataFactory(object): 'rating_key': '', 'title': '', 'platform_type': '', - 'platform': '' + 'platform': '', + 'row_id': '' } top_users.append(row) @@ -526,7 +531,8 @@ class DataFactory(object): 'users_watched': '', 'rating_key': '', 'user': '', - 'friendly_name': '' + 'friendly_name': '', + 'row_id': '' } top_platform.append(row) @@ -862,3 +868,54 @@ class DataFactory(object): output = {'categories': categories, 'series': [series_1_output]} return output + + def get_metadata_details(self, row_id): + monitor_db = database.MonitorDatabase() + + if row_id: + query = 'SELECT 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 ' \ + 'FROM session_history_metadata ' \ + 'WHERE id = ?' + result = monitor_db.select(query=query, args=[row_id]) + else: + result = [] + + metadata = {} + for item in result: + directors = item['directors'].split(';') + writers = item['writers'].split(';') + actors = item['actors'].split(';') + genres = item['genres'].split(';') + + metadata = {'type': item['media_type'], + 'rating_key': item['rating_key'], + 'grandparent_title': item['grandparent_title'], + 'parent_index': item['parent_media_index'], + 'parent_title': item['parent_title'], + 'index': item['media_index'], + 'studio': item['studio'], + 'title': item['title'], + 'content_rating': item['content_rating'], + 'summary': item['summary'], + 'rating': item['rating'], + 'duration': item['duration'], + 'year': item['year'], + 'thumb': item['thumb'], + 'parent_thumb': item['parent_thumb'], + 'grandparent_thumb': item['grandparent_thumb'], + 'art': item['art'], + 'originally_available_at': item['originally_available_at'], + 'added_at': item['added_at'], + 'updated_at': item['updated_at'], + 'last_viewed_at': item['last_viewed_at'], + 'guid': item['guid'], + 'writers': writers, + 'directors': directors, + 'genres': genres, + 'actors': actors + } + + return metadata \ No newline at end of file diff --git a/plexpy/plexwatch_import.py b/plexpy/plexwatch_import.py index 2b3f5ef0..236b8b85 100644 --- a/plexpy/plexwatch_import.py +++ b/plexpy/plexwatch_import.py @@ -226,7 +226,7 @@ def import_from_plexwatch(database=None, table_name=None, import_ignore_interval try: connection = sqlite3.connect(database, timeout=20) - cur = connection.cursor() + connection.row_factory = sqlite3.Row except sqlite3.OperationalError: logger.error('PlexPy Importer :: Invalid filename.') return None @@ -273,37 +273,39 @@ def import_from_plexwatch(database=None, table_name=None, import_ignore_interval 'rating as content_rating,' \ 'summary,' \ 'title AS full_title,' \ - 'orig_title AS title, ' \ - 'orig_title_ep AS grandparent_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 = cur.execute(query) + result = connection.execute(query) for row in result: # Extract the xml from the Plexwatch db xml field. - extracted_xml = extract_plexwatch_xml(row[14]) + extracted_xml = extract_plexwatch_xml(row['xml']) # If the user_id no longer exists in the friends list, pull it from the xml. - if data_factory.get_user_id(user=row[4]): - user_id = data_factory.get_user_id(user=row[4]) + 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[0], - 'stopped': row[1], - 'rating_key': row[2], - 'title': row[18], + 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[19], + 'grandparent_title': row['grandparent_title'], 'user_id': user_id, - 'user': row[4], - 'ip_address': row[5], - 'paused_counter': row[6], - 'player': row[7], + '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[10], - 'grandparent_rating_key': row[11], + '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'], @@ -328,12 +330,12 @@ def import_from_plexwatch(database=None, table_name=None, import_ignore_interval 'transcode_height': extracted_xml['transcode_height'] } - session_history_metadata = {'rating_key': helpers.latinToAscii(row[2]), - 'parent_rating_key': row[10], - 'grandparent_rating_key': row[11], - 'title': row[18], + 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[19], + 'grandparent_title': row['grandparent_title'], 'index': extracted_xml['media_index'], 'parent_index': extracted_xml['parent_media_index'], 'thumb': extracted_xml['thumb'], @@ -346,8 +348,8 @@ def import_from_plexwatch(database=None, table_name=None, import_ignore_interval 'added_at': extracted_xml['added_at'], 'updated_at': extracted_xml['updated_at'], 'last_viewed_at': extracted_xml['last_viewed_at'], - 'content_rating': row[15], - 'summary': row[16], + 'content_rating': row['content_rating'], + 'summary': row['summary'], 'rating': extracted_xml['rating'], 'duration': extracted_xml['duration'], 'guid': extracted_xml['guid'], @@ -356,7 +358,7 @@ def import_from_plexwatch(database=None, table_name=None, import_ignore_interval 'actors': extracted_xml['actors'], 'genres': extracted_xml['genres'], 'studio': extracted_xml['studio'], - 'full_title': row[17] + 'full_title': row['full_title'] } # On older versions of PMS, "clip" items were still classified as "movie" and had bad ratingKey values diff --git a/plexpy/webserve.py b/plexpy/webserve.py index 32ef3941..53472fab 100644 --- a/plexpy/webserve.py +++ b/plexpy/webserve.py @@ -671,16 +671,20 @@ class WebInterface(object): return None @cherrypy.expose - def info(self, rating_key='', **kwargs): + def info(self, item_id=None, source=None, **kwargs): - pms_connect = pmsconnect.PmsConnect() - result = pms_connect.get_metadata_details(rating_key) + if source == 'history': + data_factory = datafactory.DataFactory() + result = data_factory.get_metadata_details(row_id=item_id) + else: + pms_connect = pmsconnect.PmsConnect() + result = pms_connect.get_metadata_details(rating_key=item_id)['metadata'] if result: - return serve_template(templatename="info.html", data=result['metadata'], title="Info") + return serve_template(templatename="info.html", data=result, title="Info") else: - return serve_template(templatename="info.html", data=None, title="Info") logger.warn('Unable to retrieve data.') + return serve_template(templatename="info.html", data=None, title="Info") @cherrypy.expose def get_user_recently_watched(self, user=None, user_id=None, limit='10', **kwargs):