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.
This commit is contained in:
Tim 2015-07-25 12:40:38 +02:00
parent 187f9d7cd4
commit 7d9934e4b6
11 changed files with 137 additions and 64 deletions

View file

@ -107,9 +107,9 @@ DOCUMENTATION :: END
</div> </div>
<div class="dashboard-activity-metadata-title"> <div class="dashboard-activity-metadata-title">
% if a['type'] == 'episode': % if a['type'] == 'episode':
<a href="info?rating_key=${a['rating_key']}">${a['grandparent_title']} - ${a['title']}</a> <a href="info?item_id=${a['rating_key']}">${a['grandparent_title']} - ${a['title']}</a>
% elif a['type'] == 'movie': % elif a['type'] == 'movie':
<a href="info?rating_key=${a['rating_key']}">${a['title']}</a> <a href="info?item_id=${a['rating_key']}">${a['title']}</a>
% elif a['type'] == 'clip': % elif a['type'] == 'clip':
${a['title']} ${a['title']}
% elif a['type'] == 'track': % elif a['type'] == 'track':

View file

@ -14,6 +14,8 @@ data['rows'] Returns an array containing stat data
data[array_index]['rows'] :: Usable parameters 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' == == Only if 'stat_id' is 'top_tv' or 'popular_tv' ==
grandparent_thumb Returns location of the item's thumbnail. Use with pms_image_proxy. grandparent_thumb Returns location of the item's thumbnail. Use with pms_image_proxy.
rating_key Returns the unique identifier for the media item. rating_key Returns the unique identifier for the media item.
@ -46,7 +48,7 @@ DOCUMENTATION :: END
<div class="home-platforms-instance"> <div class="home-platforms-instance">
<li> <li>
<span> <span>
<a href="info?rating_key=${a['rows'][0]['rating_key']}"> <a href="info?item_id=${a['rows'][0]['rating_key']}">
% if a['rows'][0]['grandparent_thumb']: % if a['rows'][0]['grandparent_thumb']:
<img class="home-platforms-instance-poster" <img class="home-platforms-instance-poster"
src="pms_image_proxy?img=${a['rows'][0]['grandparent_thumb']}&width=162&height=240&fallback=poster"> src="pms_image_proxy?img=${a['rows'][0]['grandparent_thumb']}&width=162&height=240&fallback=poster">
@ -58,7 +60,7 @@ DOCUMENTATION :: END
<div class="home-platforms-instance-name"> <div class="home-platforms-instance-name">
<h4>Most Watched TV</h4> <h4>Most Watched TV</h4>
<a href="info?rating_key=${a['rows'][0]['rating_key']}"> <a href="info?item_id=${a['rows'][0]['rating_key']}">
<h5>${a['rows'][0]['title']}</h5> <h5>${a['rows'][0]['title']}</h5>
</a> </a>
</div> </div>
@ -73,7 +75,7 @@ DOCUMENTATION :: END
<div class="home-platforms-instance"> <div class="home-platforms-instance">
<li> <li>
<span> <span>
<a href="info?rating_key=${a['rows'][0]['rating_key']}"> <a href="info?item_id=${a['rows'][0]['rating_key']}">
% if a['rows'][0]['grandparent_thumb'] != '': % if a['rows'][0]['grandparent_thumb'] != '':
<img class="home-platforms-instance-poster" <img class="home-platforms-instance-poster"
src="pms_image_proxy?img=${a['rows'][0]['grandparent_thumb']}&width=162&height=240&fallback=poster"> src="pms_image_proxy?img=${a['rows'][0]['grandparent_thumb']}&width=162&height=240&fallback=poster">
@ -85,7 +87,7 @@ DOCUMENTATION :: END
<div class="home-platforms-instance-name"> <div class="home-platforms-instance-name">
<h4>Most Popular TV</h4> <h4>Most Popular TV</h4>
<a href="info?rating_key=${a['rows'][0]['rating_key']}"> <a href="info?item_id=${a['rows'][0]['rating_key']}">
<h5>${a['rows'][0]['title']}</h5> <h5>${a['rows'][0]['title']}</h5>
</a> </a>
</div> </div>
@ -100,7 +102,11 @@ DOCUMENTATION :: END
<div class="home-platforms-instance"> <div class="home-platforms-instance">
<li> <li>
<span> <span>
% if a['rows'][0]['user_id']:
<a href="user?user_id=${a['rows'][0]['user_id']}"> <a href="user?user_id=${a['rows'][0]['user_id']}">
% else:
<a href="user?user=${a['rows'][0]['user']}">
% endif
% if a['rows'][0]['thumb'] != '': % if a['rows'][0]['thumb'] != '':
<img class="home-platforms-instance-oval" src="${a['rows'][0]['thumb']}" <img class="home-platforms-instance-oval" src="${a['rows'][0]['thumb']}"
class="poster-face"> class="poster-face">
@ -113,7 +119,11 @@ DOCUMENTATION :: END
<div class="home-platforms-instance-name"> <div class="home-platforms-instance-name">
<h4>Most Active User</h4> <h4>Most Active User</h4>
% if a['rows'][0]['user_id']:
<a href="user?user_id=${a['rows'][0]['user_id']}"> <a href="user?user_id=${a['rows'][0]['user_id']}">
% else:
<a href="user?user=${a['rows'][0]['user']}">
% endif
<h5>${a['rows'][0]['friendly_name']}</h5> <h5>${a['rows'][0]['friendly_name']}</h5>
</a> </a>
</div> </div>

View file

@ -58,9 +58,9 @@ from plexpy import helpers
<div class="span9"> <div class="span9">
<div class="summary-content-poster hidden-phone hidden-tablet"> <div class="summary-content-poster hidden-phone hidden-tablet">
% if data['type'] == 'episode': % if data['type'] == 'episode':
<img src="pms_image_proxy?img=${data['parent_thumb']}&width=256&height=352"> <img src="pms_image_proxy?img=${data['parent_thumb']}&width=256&height=352&fallback=poster">
% else: % else:
<img src="pms_image_proxy?img=${data['thumb']}&width=256&height=352"> <img src="pms_image_proxy?img=${data['thumb']}&width=256&height=352&fallback=poster">
% endif % endif
</div> </div>
<div class="summary-content"> <div class="summary-content">

View file

@ -32,7 +32,7 @@ DOCUMENTATION :: END
<li> <li>
<div class="season-episodes-poster"> <div class="season-episodes-poster">
<div class="season-episodes-poster-face"> <div class="season-episodes-poster-face">
<a href="info?rating_key=${a['rating_key']}"> <a href="info?item_id=${a['rating_key']}">
<img src="pms_image_proxy?img=${a['thumb']}&width=205&height=115" <img src="pms_image_proxy?img=${a['thumb']}&width=205&height=115"
class="season-episodes-poster-face"> class="season-episodes-poster-face">
</a> </a>
@ -45,7 +45,7 @@ DOCUMENTATION :: END
</div> </div>
<div class="season-episodes-instance-text-wrapper"> <div class="season-episodes-instance-text-wrapper">
<div class="season-episodes-title"> <div class="season-episodes-title">
<a href="info?rating_key=${a['rating_key']}"> <a href="info?item_id=${a['rating_key']}">
"${a['title']}" "${a['title']}"
</a> </a>
</div> </div>

View file

@ -87,11 +87,11 @@ history_table_options = {
if (rowData['video_decision'] === 'transcode') { if (rowData['video_decision'] === 'transcode') {
transcode_dec = '<i class="fa fa-server"></i>&nbsp'; transcode_dec = '<i class="fa fa-server"></i>&nbsp';
} }
$(td).html('<div><div style="float: left;"><a href="info?rating_key=' + rowData['rating_key'] + '">' + cellData + '</a></div><div style="float: right; text-align: right; padding-right: 5px;">' + transcode_dec + '<i class="fa fa-video-camera"></i></div></div>'); $(td).html('<div><div style="float: left;"><a href="info?source=history&item_id=' + rowData['id'] + '">' + cellData + '</a></div><div style="float: right; text-align: right; padding-right: 5px;">' + transcode_dec + '<i class="fa fa-video-camera"></i></div></div>');
} else if (rowData['media_type'] === 'track') { } else if (rowData['media_type'] === 'track') {
$(td).html('<div><div style="float: left;">' + cellData + '</div><div style="float: right; text-align: right; padding-right: 5px;"><i class="fa fa-music"></i></div></div>'); $(td).html('<div><div style="float: left;">' + cellData + '</div><div style="float: right; text-align: right; padding-right: 5px;"><i class="fa fa-music"></i></div></div>');
} else { } else {
$(td).html('<a href="info?rating_key=' + rowData['rating_key'] + '">' + cellData + '</a>'); $(td).html('<a href="info?item_id=' + rowData['id'] + '">' + cellData + '</a>');
} }
} }
} }

View file

@ -44,7 +44,7 @@ sync_table_options = {
"createdCell": function (td, cellData, rowData, row, col) { "createdCell": function (td, cellData, rowData, row, col) {
if (cellData !== '') { if (cellData !== '') {
if (rowData['metadata_type'] !== 'track') { if (rowData['metadata_type'] !== 'track') {
$(td).html('<a href="info?rating_key=' + rowData['rating_key'] + '">' + cellData + '</a>'); $(td).html('<a href="info?item_id=' + rowData['rating_key'] + '">' + cellData + '</a>');
} else { } else {
$(td).html(cellData); $(td).html(cellData);
} }

View file

@ -31,7 +31,7 @@ DOCUMENTATION :: END
<div class="poster"> <div class="poster">
% if item['type'] == 'season' or item['type'] == 'movie': % if item['type'] == 'season' or item['type'] == 'movie':
<div class="poster-face"> <div class="poster-face">
<a href="info?rating_key=${item['rating_key']}"> <a href="info?item_id=${item['rating_key']}">
<img src="pms_image_proxy?img=${item['thumb']}&width=153&height=225&fallback=poster" class="poster-face"> <img src="pms_image_proxy?img=${item['thumb']}&width=153&height=225&fallback=poster" class="poster-face">
</a> </a>
</div> </div>

View file

@ -34,7 +34,7 @@ DOCUMENTATION :: END
<li> <li>
<div class="poster"> <div class="poster">
<div class="poster-face"> <div class="poster-face">
<a href="info?rating_key=${item['rating_key']}"> <a href="info?item_id=${item['rating_key']}">
<img src="pms_image_proxy?img=${item['thumb']}&width=153&height=225&fallback=poster" class="poster-face"> <img src="pms_image_proxy?img=${item['thumb']}&width=153&height=225&fallback=poster" class="poster-face">
</a> </a>
</div> </div>

View file

@ -35,7 +35,7 @@ class DataFactory(object):
users.friendly_name end) as friendly_name', users.friendly_name end) as friendly_name',
'session_history.started', 'session_history.started',
'session_history.ip_address', 'session_history.ip_address',
'COUNT(session_history.rating_key) as plays', 'COUNT(session_history.id) as plays',
'session_history.user', 'session_history.user',
'session_history.user_id' 'session_history.user_id'
] ]
@ -377,7 +377,8 @@ class DataFactory(object):
if 'top_tv' in stat: if 'top_tv' in stat:
top_tv = [] top_tv = []
try: 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, ' \ 'COUNT(session_history_metadata.grandparent_title) as total_plays, ' \
'session_history_metadata.grandparent_rating_key, ' \ 'session_history_metadata.grandparent_rating_key, ' \
'MAX(session_history.started) as last_watch,' \ 'MAX(session_history.started) as last_watch,' \
@ -395,17 +396,18 @@ class DataFactory(object):
return None return None
for item in result: for item in result:
row = {'title': item[0], row = {'title': item[1],
'total_plays': item[1], 'total_plays': item[2],
'users_watched': '', 'users_watched': '',
'rating_key': item[2], 'rating_key': item[3],
'last_play': item[3], 'last_play': item[4],
'grandparent_thumb': item[4], 'grandparent_thumb': item[5],
'thumb': '', 'thumb': '',
'user': '', 'user': '',
'friendly_name': '', 'friendly_name': '',
'platform_type': '', 'platform_type': '',
'platform': '' 'platform': '',
'row_id': item[0]
} }
top_tv.append(row) top_tv.append(row)
@ -415,7 +417,8 @@ class DataFactory(object):
elif 'popular_tv' in stat: elif 'popular_tv' in stat:
popular_tv = [] popular_tv = []
try: 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, ' \ 'COUNT(DISTINCT session_history.user_id) as users_watched, ' \
'session_history_metadata.grandparent_rating_key, ' \ 'session_history_metadata.grandparent_rating_key, ' \
'MAX(session_history.started) as last_watch, ' \ 'MAX(session_history.started) as last_watch, ' \
@ -435,17 +438,18 @@ class DataFactory(object):
return None return None
for item in result: for item in result:
row = {'title': item[0], row = {'title': item[1],
'users_watched': item[1], 'users_watched': item[2],
'rating_key': item[2], 'rating_key': item[3],
'last_play': item[3], 'last_play': item[4],
'total_plays': item[4], 'total_plays': item[5],
'grandparent_thumb': item[5], 'grandparent_thumb': item[6],
'thumb': '', 'thumb': '',
'user': '', 'user': '',
'friendly_name': '', 'friendly_name': '',
'platform_type': '', 'platform_type': '',
'platform': '' 'platform': '',
'row_id': item[0]
} }
popular_tv.append(row) popular_tv.append(row)
@ -491,7 +495,8 @@ class DataFactory(object):
'rating_key': '', 'rating_key': '',
'title': '', 'title': '',
'platform_type': '', 'platform_type': '',
'platform': '' 'platform': '',
'row_id': ''
} }
top_users.append(row) top_users.append(row)
@ -526,7 +531,8 @@ class DataFactory(object):
'users_watched': '', 'users_watched': '',
'rating_key': '', 'rating_key': '',
'user': '', 'user': '',
'friendly_name': '' 'friendly_name': '',
'row_id': ''
} }
top_platform.append(row) top_platform.append(row)
@ -862,3 +868,54 @@ class DataFactory(object):
output = {'categories': categories, output = {'categories': categories,
'series': [series_1_output]} 'series': [series_1_output]}
return 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

View file

@ -226,7 +226,7 @@ def import_from_plexwatch(database=None, table_name=None, import_ignore_interval
try: try:
connection = sqlite3.connect(database, timeout=20) connection = sqlite3.connect(database, timeout=20)
cur = connection.cursor() connection.row_factory = sqlite3.Row
except sqlite3.OperationalError: except sqlite3.OperationalError:
logger.error('PlexPy Importer :: Invalid filename.') logger.error('PlexPy Importer :: Invalid filename.')
return None return None
@ -273,37 +273,39 @@ def import_from_plexwatch(database=None, table_name=None, import_ignore_interval
'rating as content_rating,' \ 'rating as content_rating,' \
'summary,' \ 'summary,' \
'title AS full_title,' \ 'title AS full_title,' \
'orig_title AS title, ' \ '(case when orig_title_ep = "" then orig_title else ' \
'orig_title_ep AS grandparent_title ' \ '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' 'FROM ' + table_name + ' ORDER BY id'
result = cur.execute(query) result = connection.execute(query)
for row in result: for row in result:
# Extract the xml from the Plexwatch db xml field. # 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 the user_id no longer exists in the friends list, pull it from the xml.
if 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[4]) user_id = data_factory.get_user_id(user=row['user'])
else: else:
user_id = extracted_xml['user_id'] user_id = extracted_xml['user_id']
session_history = {'started': row[0], session_history = {'started': row['started'],
'stopped': row[1], 'stopped': row['stopped'],
'rating_key': row[2], 'rating_key': row['rating_key'],
'title': row[18], 'title': row['title'],
'parent_title': extracted_xml['parent_title'], 'parent_title': extracted_xml['parent_title'],
'grandparent_title': row[19], 'grandparent_title': row['grandparent_title'],
'user_id': user_id, 'user_id': user_id,
'user': row[4], 'user': row['user'],
'ip_address': row[5], 'ip_address': row['ip_address'],
'paused_counter': row[6], 'paused_counter': row['paused_counter'],
'player': row[7], 'player': row['player'],
'platform': extracted_xml['platform'], 'platform': extracted_xml['platform'],
'machine_id': extracted_xml['machine_id'], 'machine_id': extracted_xml['machine_id'],
'parent_rating_key': row[10], 'parent_rating_key': row['parent_rating_key'],
'grandparent_rating_key': row[11], 'grandparent_rating_key': row['grandparent_rating_key'],
'media_type': extracted_xml['media_type'], 'media_type': extracted_xml['media_type'],
'view_offset': extracted_xml['view_offset'], 'view_offset': extracted_xml['view_offset'],
'video_decision': extracted_xml['video_decision'], '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'] 'transcode_height': extracted_xml['transcode_height']
} }
session_history_metadata = {'rating_key': helpers.latinToAscii(row[2]), session_history_metadata = {'rating_key': helpers.latinToAscii(row['rating_key']),
'parent_rating_key': row[10], 'parent_rating_key': row['parent_rating_key'],
'grandparent_rating_key': row[11], 'grandparent_rating_key': row['grandparent_rating_key'],
'title': row[18], 'title': row['title'],
'parent_title': extracted_xml['parent_title'], 'parent_title': extracted_xml['parent_title'],
'grandparent_title': row[19], 'grandparent_title': row['grandparent_title'],
'index': extracted_xml['media_index'], 'index': extracted_xml['media_index'],
'parent_index': extracted_xml['parent_media_index'], 'parent_index': extracted_xml['parent_media_index'],
'thumb': extracted_xml['thumb'], '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'], 'added_at': extracted_xml['added_at'],
'updated_at': extracted_xml['updated_at'], 'updated_at': extracted_xml['updated_at'],
'last_viewed_at': extracted_xml['last_viewed_at'], 'last_viewed_at': extracted_xml['last_viewed_at'],
'content_rating': row[15], 'content_rating': row['content_rating'],
'summary': row[16], 'summary': row['summary'],
'rating': extracted_xml['rating'], 'rating': extracted_xml['rating'],
'duration': extracted_xml['duration'], 'duration': extracted_xml['duration'],
'guid': extracted_xml['guid'], 'guid': extracted_xml['guid'],
@ -356,7 +358,7 @@ def import_from_plexwatch(database=None, table_name=None, import_ignore_interval
'actors': extracted_xml['actors'], 'actors': extracted_xml['actors'],
'genres': extracted_xml['genres'], 'genres': extracted_xml['genres'],
'studio': extracted_xml['studio'], '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 # On older versions of PMS, "clip" items were still classified as "movie" and had bad ratingKey values

View file

@ -671,16 +671,20 @@ class WebInterface(object):
return None return None
@cherrypy.expose @cherrypy.expose
def info(self, rating_key='', **kwargs): def info(self, item_id=None, source=None, **kwargs):
if source == 'history':
data_factory = datafactory.DataFactory()
result = data_factory.get_metadata_details(row_id=item_id)
else:
pms_connect = pmsconnect.PmsConnect() pms_connect = pmsconnect.PmsConnect()
result = pms_connect.get_metadata_details(rating_key) result = pms_connect.get_metadata_details(rating_key=item_id)['metadata']
if result: if result:
return serve_template(templatename="info.html", data=result['metadata'], title="Info") return serve_template(templatename="info.html", data=result, title="Info")
else: else:
return serve_template(templatename="info.html", data=None, title="Info")
logger.warn('Unable to retrieve data.') logger.warn('Unable to retrieve data.')
return serve_template(templatename="info.html", data=None, title="Info")
@cherrypy.expose @cherrypy.expose
def get_user_recently_watched(self, user=None, user_id=None, limit='10', **kwargs): def get_user_recently_watched(self, user=None, user_id=None, limit='10', **kwargs):