mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-07-06 13:11:15 -07:00
Change wording on home stats
Add TV info to season info page Add episode list to season info page
This commit is contained in:
parent
c99e3c5e4a
commit
01601605e1
5 changed files with 175 additions and 12 deletions
|
@ -16,7 +16,7 @@
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</span>
|
||||||
<div class="home-platforms-instance-name">
|
<div class="home-platforms-instance-name">
|
||||||
<h4>Most Popular TV</h4>
|
<h4>Most Watched TV</h4>
|
||||||
<a href="info?rating_key=${a['rows'][0]['rating_key']}">
|
<a href="info?rating_key=${a['rows'][0]['rating_key']}">
|
||||||
<h5>${a['rows'][0]['orig_title']}</h5>
|
<h5>${a['rows'][0]['orig_title']}</h5>
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -56,25 +56,19 @@
|
||||||
% else:
|
% else:
|
||||||
Directed by <strong> unknown</strong>
|
Directed by <strong> unknown</strong>
|
||||||
% endif
|
% endif
|
||||||
% elif metadata['type'] == 'show':
|
% elif metadata['type'] == 'show' or metadata['type'] == 'season':
|
||||||
Studio <strong> ${metadata['studio']}</strong>
|
Studio <strong> ${metadata['studio']}</strong>
|
||||||
% endif
|
% endif
|
||||||
</div>
|
</div>
|
||||||
<div class="summary-content-duration">
|
<div class="summary-content-duration">
|
||||||
% if metadata['type'] == 'episode' or metadata['type'] == 'movie' or metadata['type'] == 'show':
|
|
||||||
Runtime <strong> ${metadata['duration']} mins</strong>
|
Runtime <strong> ${metadata['duration']} mins</strong>
|
||||||
% endif
|
|
||||||
</div>
|
</div>
|
||||||
<div class="summary-content-content-rating">
|
<div class="summary-content-content-rating">
|
||||||
% if metadata['type'] == 'episode' or metadata['type'] == 'movie' or metadata['type'] == 'show':
|
|
||||||
Rated <strong> ${metadata['contentRating']} </strong>
|
Rated <strong> ${metadata['contentRating']} </strong>
|
||||||
% endif
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="summary-content-summary">
|
<div class="summary-content-summary">
|
||||||
% if metadata['type'] == 'episode' or metadata['type'] == 'movie' or metadata['type'] == 'show':
|
|
||||||
<p> ${metadata['summary']} </p>
|
<p> ${metadata['summary']} </p>
|
||||||
% endif
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -171,6 +165,14 @@
|
||||||
</table>
|
</table>
|
||||||
<div id="info-modal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="info-modal" aria-hidden="true">
|
<div id="info-modal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="info-modal" aria-hidden="true">
|
||||||
</div>
|
</div>
|
||||||
|
% elif metadata['type'] == 'season':
|
||||||
|
<div class="wellheader">
|
||||||
|
<div class="dashboard-wellheader">
|
||||||
|
<h3>Episode list for <strong>${metadata['title']}</strong></h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="episode-list">
|
||||||
|
</div>
|
||||||
% endif
|
% endif
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -220,5 +222,18 @@
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
%endif
|
%endif
|
||||||
|
% if metadata['type'] == 'season':
|
||||||
|
<script>
|
||||||
|
$.ajax({
|
||||||
|
url: 'get_children',
|
||||||
|
type: "GET",
|
||||||
|
async: true,
|
||||||
|
data: { rating_key : ${metadata['ratingKey']} },
|
||||||
|
complete: function(xhr, status) {
|
||||||
|
$("#episode-list").html(xhr.responseText);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
% endif
|
||||||
% endif
|
% endif
|
||||||
</%def>
|
</%def>
|
||||||
|
|
33
data/interfaces/default/info_episode_list.html
Normal file
33
data/interfaces/default/info_episode_list.html
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
% if episode_list != None:
|
||||||
|
% if episode_list['episode_count'] > 0:
|
||||||
|
<div class="season-episodes-wrapper">
|
||||||
|
<ul class="season-episodes-instance">
|
||||||
|
% for a in episode_list['episode_list']:
|
||||||
|
<li>
|
||||||
|
<div class="season-episodes-poster">
|
||||||
|
<div class="season-episodes-poster-face">
|
||||||
|
<a href="info?rating_key=${a['ratingKey']}">
|
||||||
|
<img src="pms_image_proxy?img=${a['thumb']}&width=205&height=115"
|
||||||
|
class="season-episodes-poster-face">
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="season-episodes-card-overlay">
|
||||||
|
<div class="season-episodes-season">
|
||||||
|
Episode ${a['index']}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="season-episodes-instance-text-wrapper">
|
||||||
|
<div class="season-episodes-title">
|
||||||
|
<a href="info?rating_key=${a['ratingKey']}">
|
||||||
|
"${a['title']}"
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
% endfor
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
% endif
|
||||||
|
% endif
|
||||||
|
|
|
@ -155,6 +155,40 @@ class PmsConnect(object):
|
||||||
|
|
||||||
return output
|
return output
|
||||||
|
|
||||||
|
"""
|
||||||
|
Return list of episodes in requested season.
|
||||||
|
|
||||||
|
Parameters required: rating_key { ratingKey of parent }
|
||||||
|
Optional parameters: output_format { dict, json }
|
||||||
|
|
||||||
|
Output: array
|
||||||
|
"""
|
||||||
|
def get_episode_list(self, rating_key='', output_format=''):
|
||||||
|
url_command = '/library/metadata/' + rating_key + '/children'
|
||||||
|
http_handler = HTTPConnection(self.host, self.port, timeout=10)
|
||||||
|
|
||||||
|
try:
|
||||||
|
http_handler.request("GET", url_command + '?X-Plex-Token=' + self.token)
|
||||||
|
response = http_handler.getresponse()
|
||||||
|
request_status = response.status
|
||||||
|
request_content = response.read()
|
||||||
|
except IOError, e:
|
||||||
|
logger.warn(u"Failed to access metadata. %s" % e)
|
||||||
|
return None
|
||||||
|
|
||||||
|
if request_status == 200:
|
||||||
|
if output_format == 'dict':
|
||||||
|
output = helpers.convert_xml_to_dict(request_content)
|
||||||
|
elif output_format == 'json':
|
||||||
|
output = helpers.convert_xml_to_json(request_content)
|
||||||
|
else:
|
||||||
|
output = request_content
|
||||||
|
else:
|
||||||
|
logger.warn(u"Failed to access metadata. Status code %r" % request_status)
|
||||||
|
return None
|
||||||
|
|
||||||
|
return output
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Return processed and validated list of recently added items.
|
Return processed and validated list of recently added items.
|
||||||
|
|
||||||
|
@ -350,6 +384,9 @@ class PmsConnect(object):
|
||||||
}
|
}
|
||||||
metadata_list = {'metadata': metadata}
|
metadata_list = {'metadata': metadata}
|
||||||
elif metadata_type == 'season':
|
elif metadata_type == 'season':
|
||||||
|
parent_rating_key = self.get_xml_attr(metadata_main, 'parentRatingKey')
|
||||||
|
show_details = self.get_metadata_details(parent_rating_key)
|
||||||
|
logger.debug(u"show_details = %r" % show_details)
|
||||||
metadata = {'type': metadata_type,
|
metadata = {'type': metadata_type,
|
||||||
'ratingKey': self.get_xml_attr(metadata_main, 'ratingKey'),
|
'ratingKey': self.get_xml_attr(metadata_main, 'ratingKey'),
|
||||||
'parentTitle': self.get_xml_attr(metadata_main, 'parentTitle'),
|
'parentTitle': self.get_xml_attr(metadata_main, 'parentTitle'),
|
||||||
|
@ -357,6 +394,10 @@ class PmsConnect(object):
|
||||||
'title': self.get_xml_attr(metadata_main, 'title'),
|
'title': self.get_xml_attr(metadata_main, 'title'),
|
||||||
'thumb': self.get_xml_attr(metadata_main, 'thumb'),
|
'thumb': self.get_xml_attr(metadata_main, 'thumb'),
|
||||||
'art': self.get_xml_attr(metadata_main, 'art'),
|
'art': self.get_xml_attr(metadata_main, 'art'),
|
||||||
|
'summary': show_details['metadata']['summary'],
|
||||||
|
'studio': show_details['metadata']['studio'],
|
||||||
|
'duration': show_details['metadata']['duration'],
|
||||||
|
'contentRating': show_details['metadata']['contentRating']
|
||||||
}
|
}
|
||||||
metadata_list = {'metadata': metadata}
|
metadata_list = {'metadata': metadata}
|
||||||
else:
|
else:
|
||||||
|
@ -367,7 +408,8 @@ class PmsConnect(object):
|
||||||
"""
|
"""
|
||||||
Validate xml keys to make sure they exist and return their attribute value, return blank value is none found
|
Validate xml keys to make sure they exist and return their attribute value, return blank value is none found
|
||||||
"""
|
"""
|
||||||
def get_xml_attr(self, xml_key, attribute, return_bool=False, default_return=''):
|
@staticmethod
|
||||||
|
def get_xml_attr(xml_key, attribute, return_bool=False, default_return=''):
|
||||||
if xml_key.getAttribute(attribute):
|
if xml_key.getAttribute(attribute):
|
||||||
if return_bool:
|
if return_bool:
|
||||||
return True
|
return True
|
||||||
|
@ -548,6 +590,55 @@ class PmsConnect(object):
|
||||||
|
|
||||||
return session_output
|
return session_output
|
||||||
|
|
||||||
|
"""
|
||||||
|
Return processed and validated episode list.
|
||||||
|
|
||||||
|
Output: array
|
||||||
|
"""
|
||||||
|
def get_season_children(self, rating_key=''):
|
||||||
|
episode_data = self.get_episode_list(rating_key)
|
||||||
|
episode_list = []
|
||||||
|
|
||||||
|
try:
|
||||||
|
xml_parse = minidom.parseString(episode_data)
|
||||||
|
except Exception, e:
|
||||||
|
logger.warn("Error parsing XML for Plex session data: %s" % e)
|
||||||
|
return None
|
||||||
|
except:
|
||||||
|
logger.warn("Error parsing XML for Plex session data.")
|
||||||
|
return None
|
||||||
|
|
||||||
|
xml_head = xml_parse.getElementsByTagName('MediaContainer')
|
||||||
|
if not xml_head:
|
||||||
|
logger.warn("Error parsing XML for Plex session data.")
|
||||||
|
return None
|
||||||
|
|
||||||
|
for a in xml_head:
|
||||||
|
if a.getAttribute('size'):
|
||||||
|
if a.getAttribute('size') == '0':
|
||||||
|
logger.debug(u"No episode data.")
|
||||||
|
episode_list = {'episode_count': '0',
|
||||||
|
'episode_list': []
|
||||||
|
}
|
||||||
|
return episode_list
|
||||||
|
|
||||||
|
if a.getElementsByTagName('Video'):
|
||||||
|
result_data = a.getElementsByTagName('Video')
|
||||||
|
for result in result_data:
|
||||||
|
episode_output = {'ratingKey': self.get_xml_attr(result, 'ratingKey'),
|
||||||
|
'index': self.get_xml_attr(result, 'index'),
|
||||||
|
'title': self.get_xml_attr(result, 'title'),
|
||||||
|
'thumb': self.get_xml_attr(result, 'thumb')
|
||||||
|
}
|
||||||
|
episode_list.append(episode_output)
|
||||||
|
|
||||||
|
output = {'episode_count': self.get_xml_attr(xml_head[0], 'size'),
|
||||||
|
'title': self.get_xml_attr(xml_head[0], 'title2'),
|
||||||
|
'episode_list': episode_list
|
||||||
|
}
|
||||||
|
|
||||||
|
return output
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Return image data as array.
|
Return image data as array.
|
||||||
Array contains the image content type and image binary
|
Array contains the image content type and image binary
|
||||||
|
|
|
@ -575,6 +575,18 @@ class WebInterface(object):
|
||||||
return serve_template(templatename="user_platform_stats.html", platform_stats=None, title="Platform Stats")
|
return serve_template(templatename="user_platform_stats.html", platform_stats=None, title="Platform Stats")
|
||||||
logger.warn('Unable to retrieve data.')
|
logger.warn('Unable to retrieve data.')
|
||||||
|
|
||||||
|
@cherrypy.expose
|
||||||
|
def get_children(self, rating_key='', **kwargs):
|
||||||
|
|
||||||
|
pms_connect = pmsconnect.PmsConnect()
|
||||||
|
result = pms_connect.get_season_children(rating_key)
|
||||||
|
|
||||||
|
if result:
|
||||||
|
return serve_template(templatename="info_episode_list.html", episode_list=result, title="Episode List")
|
||||||
|
else:
|
||||||
|
return serve_template(templatename="info_episode_list.html", episode_list=None, title="Episode List")
|
||||||
|
logger.warn('Unable to retrieve data.')
|
||||||
|
|
||||||
@cherrypy.expose
|
@cherrypy.expose
|
||||||
def get_metadata_json(self, rating_key='', **kwargs):
|
def get_metadata_json(self, rating_key='', **kwargs):
|
||||||
|
|
||||||
|
@ -611,6 +623,18 @@ class WebInterface(object):
|
||||||
else:
|
else:
|
||||||
logger.warn('Unable to retrieve data.')
|
logger.warn('Unable to retrieve data.')
|
||||||
|
|
||||||
|
@cherrypy.expose
|
||||||
|
def get_episode_list_json(self, rating_key='', **kwargs):
|
||||||
|
|
||||||
|
pms_connect = pmsconnect.PmsConnect()
|
||||||
|
result = pms_connect.get_episode_list(rating_key, 'json')
|
||||||
|
|
||||||
|
if result:
|
||||||
|
cherrypy.response.headers['Content-type'] = 'application/json'
|
||||||
|
return result
|
||||||
|
else:
|
||||||
|
logger.warn('Unable to retrieve data.')
|
||||||
|
|
||||||
@cherrypy.expose
|
@cherrypy.expose
|
||||||
def get_stream(self, row_id='', **kwargs):
|
def get_stream(self, row_id='', **kwargs):
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue