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>
|
||||
</span>
|
||||
<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']}">
|
||||
<h5>${a['rows'][0]['orig_title']}</h5>
|
||||
</a>
|
||||
|
|
|
@ -56,25 +56,19 @@
|
|||
% else:
|
||||
Directed by <strong> unknown</strong>
|
||||
% endif
|
||||
% elif metadata['type'] == 'show':
|
||||
% elif metadata['type'] == 'show' or metadata['type'] == 'season':
|
||||
Studio <strong> ${metadata['studio']}</strong>
|
||||
% endif
|
||||
</div>
|
||||
<div class="summary-content-duration">
|
||||
% if metadata['type'] == 'episode' or metadata['type'] == 'movie' or metadata['type'] == 'show':
|
||||
Runtime <strong> ${metadata['duration']} mins</strong>
|
||||
% endif
|
||||
</div>
|
||||
<div class="summary-content-content-rating">
|
||||
% if metadata['type'] == 'episode' or metadata['type'] == 'movie' or metadata['type'] == 'show':
|
||||
Rated <strong> ${metadata['contentRating']} </strong>
|
||||
% endif
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-content-summary">
|
||||
% if metadata['type'] == 'episode' or metadata['type'] == 'movie' or metadata['type'] == 'show':
|
||||
<p> ${metadata['summary']} </p>
|
||||
% endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -171,6 +165,14 @@
|
|||
</table>
|
||||
<div id="info-modal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="info-modal" aria-hidden="true">
|
||||
</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
|
||||
</div>
|
||||
</div>
|
||||
|
@ -220,5 +222,18 @@
|
|||
});
|
||||
</script>
|
||||
%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
|
||||
</%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 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.
|
||||
|
||||
|
@ -350,6 +384,9 @@ class PmsConnect(object):
|
|||
}
|
||||
metadata_list = {'metadata': metadata}
|
||||
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,
|
||||
'ratingKey': self.get_xml_attr(metadata_main, 'ratingKey'),
|
||||
'parentTitle': self.get_xml_attr(metadata_main, 'parentTitle'),
|
||||
|
@ -357,6 +394,10 @@ class PmsConnect(object):
|
|||
'title': self.get_xml_attr(metadata_main, 'title'),
|
||||
'thumb': self.get_xml_attr(metadata_main, 'thumb'),
|
||||
'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}
|
||||
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
|
||||
"""
|
||||
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 return_bool:
|
||||
return True
|
||||
|
@ -548,6 +590,55 @@ class PmsConnect(object):
|
|||
|
||||
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.
|
||||
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")
|
||||
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
|
||||
def get_metadata_json(self, rating_key='', **kwargs):
|
||||
|
||||
|
@ -611,6 +623,18 @@ class WebInterface(object):
|
|||
else:
|
||||
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
|
||||
def get_stream(self, row_id='', **kwargs):
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue