diff --git a/data/interfaces/default/css/plexpy.css b/data/interfaces/default/css/plexpy.css
index a4bbd743..79d37e1a 100644
--- a/data/interfaces/default/css/plexpy.css
+++ b/data/interfaces/default/css/plexpy.css
@@ -1008,17 +1008,102 @@ a .summary-poster-face-episode:hover {
background-size: contain;
height: 16px;
}
+.show-seasons-wrapper {
+}
+.show-seasons-instance {
+ list-style: none;
+ margin: 0;
+}
+.show-seasons-instance li {
+ float: left;
+ position: relative;
+ left: 0px;
+ margin-right: 25px;
+ margin-bottom: 25px;
+}
+a .show-seasons-card-overlay:hover {
+ webkit-box-shadow: inset 0 0 0 2px #e9a049;
+ -moz-box-shadow: inset 0 0 0 2px #e9a049;
+ box-shadow: inset 0 0 0 2px #e9a049;
+}
+.show-seasons-poster {
+ float: left;
+ position: relative;
+ left: 0px;
+}
+.show-seasons-card-overlay {
+ position: absolute;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ text-align: left;
+ background: -moz-linear-gradient(top, rgba(0,0,0,0) 30%, rgba(0,0,0,1) 100%);
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(30%,rgba(0,0,0,0)), color-stop(100%,rgba(0,0,0,1)));
+ background: -webkit-linear-gradient(top, rgba(0,0,0,0) 30%,rgba(0,0,0,1) 100%);
+ background: -o-linear-gradient(top, rgba(0,0,0,0) 30%,rgba(0,0,0,1) 100%);
+ background: -ms-linear-gradient(top, rgba(0,0,0,0) 30%,rgba(0,0,0,1) 100%);
+ background: linear-gradient(to bottom, rgba(0,0,0,0) 30%,rgba(0,0,0,1) 100%);
+ height: 225px;
+}
+.show-seasons-overlay-text {
+ color: #aaa;
+ font-size: 12px;
+ float: left;
+ position: absolute;
+ left: 8px;
+ bottom: 5px;
+}
+.show-seasons-instance-text-wrapper {
+ width: 150px;
+ font-size: 13px;
+ margin-bottom: 20px;
+ clear: both;
+}
+.show-seasons-instance-text-wrapper h3 {
+ padding: 5px 3px 0 3px;
+ color: #fff;
+ text-overflow: ellipsis;
+ overflow: hidden;
+ position: relative;
+ font-size: 13px;
+ margin: 0;
+ line-height: 15px;
+ font-weight: normal;
+ width: 250px;
+ white-space: nowrap;
+ text-align: left;
+ clear: both;
+}
+.show-seasons-title a {
+ text-decoration: none;
+ font-size: 14px;
+ font-weight: normal;
+ color: #fff;
+ float: left;
+ text-overflow: ellipsis;
+ overflow: hidden;
+ position: relative;
+ white-space: nowrap;
+ width: 205px;
+ margin-top: 2px;
+ margin-left: 0px;
+ margin-bottom: 20px;
+}
+.show-seasons a:hover {
+ color: #F9AA03;
+}
.season-episodes-wrapper {
}
.season-episodes-instance {
list-style: none;
- margin: 0 0 0px 0px;
+ margin: 0;
}
.season-episodes-instance li {
float: left;
position: relative;
left: 0px;
margin-right: 25px;
+ margin-bottom: 25px;
}
a .season-episodes-card-overlay:hover {
webkit-box-shadow: inset 0 0 0 2px #e9a049;
@@ -1059,11 +1144,13 @@ a .season-episodes-card-overlay:hover {
font-size: 11px;
text-shadow: 0 1px 5px rgba(0,0,0,0.2);
}
-.season-episodes-instance-text-wrapper {
- width: 250px;
- font-size: 13px;
- margin-bottom: 20px;
- clear: both;
+.season-episodes-overlay-text {
+ color: #aaa;
+ font-size: 12px;
+ float: left;
+ position: absolute;
+ left: 8px;
+ bottom: 5px;
}
.season-episodes-instance-text-wrapper h3 {
padding: 5px 3px 0 3px;
@@ -1098,14 +1185,6 @@ a .season-episodes-card-overlay:hover {
.season-episodes a:hover {
color: #F9AA03;
}
-.season-episodes-season {
- color: #aaa;
- font-size: 12px;
- float: left;
- position: absolute;
- left: 8px;
- bottom: 5px;
-}
.user-info-wrapper {
height: 113px;
}
diff --git a/data/interfaces/default/info.html b/data/interfaces/default/info.html
index 078d1670..c2cacf2a 100644
--- a/data/interfaces/default/info.html
+++ b/data/interfaces/default/info.html
@@ -197,7 +197,30 @@ DOCUMENTATION :: END
% endif
- % if data['type'] == 'movie' or data['type'] == 'episode' or data['type'] == 'show':
+ % if data['type'] == 'show':
+
+ % elif data['type'] == 'season':
+
+ % endif
+ % if data['type'] == 'movie' or data['type'] == 'episode' or data['type'] == 'show' or data['type'] == 'season':
@@ -288,28 +300,27 @@ DOCUMENTATION :: END
type: 'post',
data: function ( d ) {
return { 'json_data': JSON.stringify( d ),
- 'rating_key': ${data['rating_key']}
- };
- }
- }
+ 'rating_key': ${data['rating_key']} };
+ }
+ }
history_table = $('#history_table').DataTable(history_table_options);
- var colvis = new $.fn.dataTable.ColVis(history_table, { buttonText: ' Select columns', buttonClass: 'btn btn-dark', exclude: [0, 10] });
- $(colvis.button()).appendTo('div.colvis-button-bar');
+ var colvis = new $.fn.dataTable.ColVis(history_table, { buttonText: ' Select columns', buttonClass: 'btn btn-dark', exclude: [0, 10] });
+ $(colvis.button()).appendTo('div.colvis-button-bar');
- clearSearchButton('history_table', history_table);
+ clearSearchButton('history_table', history_table);
- $('#row-edit-mode').click(function() {
- if ($(this).hasClass('active')) {
- $('.delete-control').each(function() {
- $(this).addClass('hidden');
- });
- } else {
- $('.delete-control').each(function() {
- $(this).removeClass('hidden');
- });
- }
- });
+ $('#row-edit-mode').click(function() {
+ if ($(this).hasClass('active')) {
+ $('.delete-control').each(function() {
+ $(this).addClass('hidden');
+ });
+ } else {
+ $('.delete-control').each(function() {
+ $(this).removeClass('hidden');
+ });
+ }
+ });
});
% elif data['type'] == 'show':
@@ -321,40 +332,75 @@ DOCUMENTATION :: END
type: 'post',
data: function ( d ) {
return { 'json_data': JSON.stringify( d ),
- 'grandparent_rating_key': ${data['rating_key']}
- };
- }
- }
- history_table = $('#history_table').DataTable(history_table_options);
- var colvis = new $.fn.dataTable.ColVis(history_table, { buttonText: ' Select columns', buttonClass: 'btn btn-dark', exclude: [0, 10] });
- $(colvis.button()).appendTo('div.colvis-button-bar');
-
- clearSearchButton('history_table', history_table);
-
- $('#row-edit-mode').click(function() {
- if ($(this).hasClass('active')) {
- $('.delete-control').each(function() {
- $(this).addClass('hidden');
- });
- } else {
- $('.delete-control').each(function() {
- $(this).removeClass('hidden');
- });
+ 'grandparent_rating_key': ${data['rating_key']} };
+ }
}
+ history_table = $('#history_table').DataTable(history_table_options);
+ var colvis = new $.fn.dataTable.ColVis(history_table, { buttonText: ' Select columns', buttonClass: 'btn btn-dark', exclude: [0, 10] });
+ $(colvis.button()).appendTo('div.colvis-button-bar');
+
+ clearSearchButton('history_table', history_table);
+
+ $('#row-edit-mode').click(function() {
+ if ($(this).hasClass('active')) {
+ $('.delete-control').each(function() {
+ $(this).addClass('hidden');
+ });
+ } else {
+ $('.delete-control').each(function() {
+ $(this).removeClass('hidden');
+ });
+ }
+ });
});
+ $.ajax({
+ url: 'get_show_children',
+ type: "GET",
+ async: true,
+ data: { rating_key : ${data['rating_key']} },
+ complete: function(xhr, status) {
+ $("#season-list").html(xhr.responseText); }
});
% endif
% if data['type'] == 'season':
+
% endif
diff --git a/data/interfaces/default/info_episode_list.html b/data/interfaces/default/info_episode_list.html
index ef02c42c..11651969 100644
--- a/data/interfaces/default/info_episode_list.html
+++ b/data/interfaces/default/info_episode_list.html
@@ -34,7 +34,7 @@ DOCUMENTATION :: END
-
diff --git a/data/interfaces/default/info_season_list.html b/data/interfaces/default/info_season_list.html
new file mode 100644
index 00000000..6da68e0e
--- /dev/null
+++ b/data/interfaces/default/info_season_list.html
@@ -0,0 +1,55 @@
+<%doc>
+USAGE DOCUMENTATION :: PLEASE LEAVE THIS AT THE TOP OF THIS FILE
+
+For Mako templating syntax documentation please visit: http://docs.makotemplates.org/en/latest/
+
+Filename: info_season_list.html
+Version: 0.1
+Variable names: data [list]
+
+data :: Usable parameters
+
+== Global keys ==
+season_count Returns the number of seasons in the array.
+season_list Returns an array of seasons.
+
+data['season_list'] :: Usable paramaters
+
+== Global keys ==
+rating_key Returns the unique identifier for the media item.
+thumb Returns the location of the item's thumbnail. Use with pms_image_proxy.
+title Returns the name of the season.
+index Returns the season number.
+
+DOCUMENTATION :: END
+%doc>
+
+% if data != None:
+% if data['season_count'] > 0:
+
+
+ % for a in data['season_list']:
+ % if a['rating_key']:
+ -
+
+
+ % if a['thumb']:
+
+ % else:
+
+ % endif
+
+
+ Season ${a['index']}
+
+
+
+
+
+
+ % endif
+ % endfor
+
+
+% endif
+% endif
\ No newline at end of file
diff --git a/plexpy/datafactory.py b/plexpy/datafactory.py
index b60c654b..e052a1f7 100644
--- a/plexpy/datafactory.py
+++ b/plexpy/datafactory.py
@@ -55,6 +55,7 @@ class DataFactory(object):
(CASE WHEN session_history_metadata.duration IS NULL THEN 1.0 ELSE \
session_history_metadata.duration * 1.0 END) * 100) as percent_complete',
'session_history.grandparent_rating_key as grandparent_rating_key',
+ 'session_history.parent_rating_key as parent_rating_key',
'session_history.rating_key as rating_key',
'session_history.user',
'session_history_metadata.media_type',
@@ -112,6 +113,7 @@ class DataFactory(object):
"duration": item["duration"],
"percent_complete": item["percent_complete"],
"grandparent_rating_key": item["grandparent_rating_key"],
+ "parent_rating_key": item["parent_rating_key"],
"rating_key": item["rating_key"],
"user": item["user"],
"media_type": item["media_type"],
diff --git a/plexpy/pmsconnect.py b/plexpy/pmsconnect.py
index 7fb15618..dba5b0b8 100644
--- a/plexpy/pmsconnect.py
+++ b/plexpy/pmsconnect.py
@@ -89,6 +89,23 @@ class PmsConnect(object):
return request
+ """
+ Return list of seasons in requested show.
+
+ Parameters required: rating_key { ratingKey of parent }
+ Optional parameters: output_format { dict, json }
+
+ Output: array
+ """
+ def get_season_list(self, rating_key='', output_format=''):
+ uri = '/library/metadata/' + rating_key + '/children'
+ request = self.request_handler.make_request(uri=uri,
+ proto=self.protocol,
+ request_type='GET',
+ output_format=output_format)
+
+ return request
+
"""
Return list of episodes in requested season.
@@ -103,7 +120,7 @@ class PmsConnect(object):
proto=self.protocol,
request_type='GET',
output_format=output_format)
-
+
return request
"""
@@ -798,6 +815,49 @@ class PmsConnect(object):
return session_output
+ """
+ Return processed and validated season list.
+
+ Output: array
+ """
+ def get_show_children(self, rating_key=''):
+ season_data = self.get_season_list(rating_key, output_format='xml')
+
+ try:
+ xml_head = season_data.getElementsByTagName('MediaContainer')
+ except:
+ logger.warn("Unable to parse XML for get_season_list.")
+ return []
+
+ season_list = []
+
+ for a in xml_head:
+ if a.getAttribute('size'):
+ if a.getAttribute('size') == '0':
+ logger.debug(u"No season data.")
+ episode_list = {'season_count': '0',
+ 'season_list': []
+ }
+ return season_list
+
+ if a.getElementsByTagName('Directory'):
+ result_data = a.getElementsByTagName('Directory')
+ for result in result_data:
+ season_output = {'rating_key': helpers.get_xml_attr(result, 'ratingKey'),
+ 'index': helpers.get_xml_attr(result, 'index'),
+ 'title': helpers.get_xml_attr(result, 'title'),
+ 'thumb': helpers.get_xml_attr(result, 'thumb'),
+ 'parent_thumb': helpers.get_xml_attr(a, 'thumb')
+ }
+ season_list.append(season_output)
+
+ output = {'season_count': helpers.get_xml_attr(xml_head[0], 'size'),
+ 'title': helpers.get_xml_attr(xml_head[0], 'title2'),
+ 'season_list': season_list
+ }
+
+ return output
+
"""
Return processed and validated episode list.
diff --git a/plexpy/webserve.py b/plexpy/webserve.py
index 54fc8d9f..92c378d0 100644
--- a/plexpy/webserve.py
+++ b/plexpy/webserve.py
@@ -1,4 +1,4 @@
-# This file is part of PlexPy.
+# This file is part of PlexPy.
#
# PlexPy is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -567,6 +567,9 @@ class WebInterface(object):
if 'rating_key' in kwargs:
rating_key = kwargs.get('rating_key', "")
custom_where = [['rating_key', rating_key]]
+ if 'parent_rating_key' in kwargs:
+ rating_key = kwargs.get('parent_rating_key', "")
+ custom_where = [['parent_rating_key', rating_key]]
if 'grandparent_rating_key' in kwargs:
rating_key = kwargs.get('grandparent_rating_key', "")
custom_where = [['grandparent_rating_key', rating_key]]
@@ -804,7 +807,19 @@ class WebInterface(object):
return serve_template(templatename="user_platform_stats.html", data=None, title="Platform Stats")
@cherrypy.expose
- def get_children(self, rating_key='', **kwargs):
+ def get_show_children(self, rating_key='', **kwargs):
+
+ pms_connect = pmsconnect.PmsConnect()
+ result = pms_connect.get_show_children(rating_key)
+
+ if result:
+ return serve_template(templatename="info_season_list.html", data=result, title="Season List")
+ else:
+ logger.warn('Unable to retrieve data.')
+ return serve_template(templatename="info_season_list.html", data=None, title="Season List")
+
+ @cherrypy.expose
+ def get_season_children(self, rating_key='', **kwargs):
pms_connect = pmsconnect.PmsConnect()
result = pms_connect.get_season_children(rating_key)