Compare commits

...

79 Commits

Author SHA1 Message Date
Tim
1761b14fe9 Merge branch 'dev' 2015-09-20 14:16:10 +02:00
Tim
8792aa6c70 v1.1.10 2015-09-20 14:15:15 +02:00
Tim
34e548cc15 Don't log some Twitter auth stuff. 2015-09-20 14:03:47 +02:00
Tim
9c955771c0 Do not include the paused time in our ignore interval logic. 2015-09-19 13:57:54 +02:00
Tim
0c6ccc5d52 Fix bug on stats type where it would always show home stats by duration. 2015-09-19 13:10:03 +02:00
Tim
7c6619ebc5 Fix Email TLS checkbox bug.
Clean up some notifier code.
2015-09-19 12:37:51 +02:00
drzoidberg33
22ed8a3a95 Merge pull request #195 from JonnyWong16/home-stats
Selective hiding home homepage statistics
2015-09-19 12:29:08 +02:00
Jonathan Wong
924ed70458 Move cards settings help text 2015-09-19 00:53:18 -07:00
Jonathan Wong
de4d8fb277 Default to show all cards until the user disables them. 2015-09-19 00:42:00 -07:00
Jonathan Wong
d61e699dc9 Remove test code 2015-09-18 23:49:34 -07:00
Jonathan Wong
ad183ff9fe Update message to prompt the user to enable cards for homepage statistics 2015-09-18 23:43:01 -07:00
Jonathan Wong
078f4babf5 Add setting to selectively hide library statistics cards on the homepage 2015-09-18 23:42:16 -07:00
Jonathan Wong
8a989d71ca Add top music and popular music cards to watch statistics 2015-09-18 18:58:59 -07:00
Jonathan Wong
78f959d39a Clean up passing unnecessary configs to homepage 2015-09-18 18:54:48 -07:00
Jonathan Wong
20056718db Add setting to selectively hide watch statistic cards on homepage 2015-09-18 18:52:46 -07:00
Tim
6eec4d1ca6 Some Twitter love. Resolves Issue #47. 2015-09-19 00:57:24 +02:00
Tim
483f5825db Add check for webbrowser import which may not be available in all Python builds (like certain NAS devices). 2015-09-17 21:04:10 +02:00
drzoidberg33
d23aaf91f7 Merge pull request #189 from JonnyWong16/miscellaneous-fixes
Fix for music on graphs, and fixes on homepage
2015-09-17 20:26:48 +02:00
Jonathan Wong
1f3a238ab2 Fix logic to add "Direct Stream" state to current activity 2015-09-16 15:42:45 -07:00
Jonathan Wong
7170dbd800 Fix home stats Last Watched to use watched percent specified in settings 2015-09-16 01:13:08 -07:00
Jonathan Wong
048b31c87a Fix music visible on graph only if "Log music" is enabled 2015-09-14 20:59:04 -07:00
Tim
e386d3ee21 Merge branch 'dev' 2015-09-14 20:53:09 +02:00
Tim
285946bf94 v1.1.9
Close href tag on activity pane.
Update program description.
2015-09-14 20:45:49 +02:00
drzoidberg33
578ba52215 Merge pull request #185 from JonnyWong16/miscellaneous-fixes
Add tracks to user recently watched
2015-09-14 20:23:05 +02:00
Jonathan Wong
5126c39c26 Group recently watched tracks together by album
* Also group identical movie or episode
2015-09-14 00:02:31 -07:00
Jonathan Wong
5ec9e41244 Add tracks to user recently watched
* Clean up poster styles to match info pages
2015-09-13 23:28:42 -07:00
Tim
5eebf6592a Make music items clickable in activity pane now that we have info pages. 2015-09-14 01:09:12 +02:00
Tim
7994351644 Fix broken history logging. 2015-09-14 00:58:28 +02:00
drzoidberg33
e445228b8a Merge pull request #182 from JonnyWong16/music-info-pages
Music info pages
2015-09-13 23:42:54 +02:00
drzoidberg33
46e6250329 Merge pull request #183 from JonnyWong16/miscellaneous-fixes
Fix typo for location of PMS logs path
2015-09-13 23:28:23 +02:00
Jonathan Wong
2edfc1e3da Add link to music info from recently added 2015-09-13 14:09:22 -07:00
Jonathan Wong
f2024b0854 Fix typo for location of PMS logs path 2015-09-13 14:04:20 -07:00
Jonathan Wong
5f2cf6cb7a Add links for track items on tables 2015-09-13 13:33:09 -07:00
Jonathan Wong
73664b6a03 Update info page to show music info 2015-09-13 13:32:44 -07:00
Jonathan Wong
af131ce16d Change code to get generic library children items
* Merge the separate season list and episode list
2015-09-13 13:31:51 -07:00
Jonathan Wong
414c4c2ffa Add artist, album, and track metadata 2015-09-13 13:29:04 -07:00
drzoidberg33
d2cdc2cea2 Merge pull request #180 from JonnyWong16/miscellaneous-fixes
Add photos to current activity
2015-09-13 20:09:26 +02:00
Jonathan Wong
b860f9a5e8 Add photos to current activity
* Also fix BIF fade in
2015-09-12 23:09:01 -07:00
drzoidberg33
e5535b6167 Merge pull request #177 from JonnyWong16/miscellaneous-fixes
Fix paused time on graphs and other miscellaneous items
2015-09-13 01:44:46 +02:00
Jonathan Wong
6359c02c80 Fix PMS Token input error message on settings page 2015-09-11 21:17:11 -07:00
Jonathan Wong
1c589fbefa Change season and episode number in history table item title
* For seasons/episodes of any number of digits
2015-09-11 21:09:48 -07:00
Jonathan Wong
b768ad8a19 Fix Mystery platform names in graphs 2015-09-11 17:41:25 -07:00
Jonathan Wong
60878ed12e Add table name session_history to paused_counter in watch stats query 2015-09-11 15:40:24 -07:00
Jonathan Wong
328d744efd Swap order of History and Users in the navbar 2015-09-11 15:19:30 -07:00
Jonathan Wong
92a868c3c6 Clean up watch statistics duration database queries 2015-09-11 13:35:50 -07:00
Jonathan Wong
7b9210a5fc Add music to graphs
* Separate out TV, movies, and music on bar graphs
* Separate out direct play, direct stream, and transcode on bar graphs
2015-09-11 13:12:33 -07:00
Jonathan Wong
fb872596d6 Fix paused time from graphs 2015-09-11 11:11:32 -07:00
Jonathan Wong
a43efef28a Fix write session to history only if library item
Some channel items, specifically Apple movie trailers, are counted as
movie items. Make sure the rating_key is a number to filter these out.
2015-09-10 21:30:34 -07:00
Jonathan Wong
e30e6dfe35 Fix Plex Web click through logo 2015-09-10 15:03:38 -07:00
Tim
eaadd5e2d6 Merge branch 'dev' 2015-09-09 22:20:45 +02:00
Tim
c608c7c9fc v1.1.8 2015-09-09 22:19:59 +02:00
drzoidberg33
451485d706 Merge pull request #173 from JonnyWong16/miscellaneous-fixes
Change Plex click through to app.plex.tv instead of local IP
2015-09-09 22:16:05 +02:00
Jonathan Wong
849675185d Change Plex click through to app.plex.tv instead of local IP 2015-09-09 13:13:17 -07:00
drzoidberg33
b060a23733 Merge pull request #170 from JonnyWong16/miscellaneous-fixes
Miscellaneous
2015-09-09 21:51:11 +02:00
drzoidberg33
bee9091182 Add Gitter Button to README 2015-09-09 16:49:28 +02:00
Jonathan Wong
f8e1ba6798 Add link to poster on info pages to view item in Plex/Web 2015-09-09 02:13:52 -07:00
Tim
e5ce57fead Fix bug with missing tagline field in PlexWatch db import. 2015-09-08 21:30:09 +02:00
Jonathan Wong
c9e2d1d200 Fix delete mode on info pages 2015-09-08 10:35:33 -07:00
Jonathan Wong
88b6eae3bf Add platform icons for windows and windows phone 2015-09-08 09:09:16 -07:00
drzoidberg33
c7d6ee8021 Merge pull request #166 from JonnyWong16/miscellaneous-fixes
Fix home stats title overflow
2015-09-08 00:44:26 +02:00
Jonathan Wong
7480508af2 Fix home stats title overflow 2015-09-07 15:38:34 -07:00
Tim
3fcc44aacf Merge branch 'dev' 2015-09-07 21:16:30 +02:00
Tim
fcc4575a86 v1.1.7 2015-09-07 21:15:52 +02:00
Tim
ebd0276eae Fix bug when parsing custom notification strings with unicode characters. 2015-09-07 20:43:15 +02:00
drzoidberg33
35521e127f Merge pull request #163 from JonnyWong16/miscellaneous-fixes
Fix for 5 digit library stats
2015-09-07 19:22:04 +02:00
Jonathan Wong
2c83554631 Update documentation 2015-09-06 21:13:56 -07:00
Jonathan Wong
56b717b1a1 Add transcode progress and speed to dashboard activity 2015-09-06 21:10:47 -07:00
Jonathan Wong
56f601e2a5 Add icon for play/pause/buffer state in dashboard activity 2015-09-06 15:52:47 -07:00
Jonathan Wong
3867dd7bdd Add throttled indicator to dashboard activity 2015-09-06 15:51:46 -07:00
Jonathan Wong
b7dc28c3fb Remove unnecessary console.log 2015-09-06 13:33:35 -07:00
Jonathan Wong
e6383d52ad Fix adding tagline to session_history_metadata table 2015-09-06 13:21:08 -07:00
Jonathan Wong
0a2ebb8815 Add tagline for newly watched items 2015-09-06 12:57:51 -07:00
Jonathan Wong
e44a0fed22 Fix tagline only if type is movie 2015-09-06 12:46:46 -07:00
Jonathan Wong
2d7585d64b Add tagline to movie info metadata 2015-09-06 12:31:50 -07:00
Jonathan Wong
df290d995b Make video preview thumbnails wording clearer. 2015-09-06 12:17:55 -07:00
Jonathan Wong
36ee5234b1 Revert overflow: hidden
* Accidentally hid top stats slider.
2015-09-06 11:54:31 -07:00
Jonathan Wong
48e601d5ff Restore edit username in users table
* Editing usernames was accidentally removed in e7b1e17
2015-09-06 11:20:49 -07:00
Jonathan Wong
84aa727387 Fix for 5 digit library stats 2015-09-06 11:03:47 -07:00
Tim
29204cb6ba Fix weird issue with bad merge. 2015-09-06 15:33:17 +02:00
45 changed files with 2272 additions and 1128 deletions

View File

@@ -1,5 +1,49 @@
# Changelog
## v1.1.10 (2015-09-20)
* Added dedicated settings section for home stats configuration with ability to show/hide selected stats and sections.
* Added support for Twitter notifications.
* Only show music in graphs if music logging is enabled.
* The monitoring ignore interval now excludes paused time.
* Fix display bug on activity panel which incorrectly reported transcoding sometimes.
* Fix bug with Email notification TLS checkbox when it would be disabled by changing any other settings afterwards.
* Fix issue on some Python releases where the webbrowser library isn't included.
## v1.1.9 (2015-09-14)
* Another JonnyWong release. I'm going to stop thanking you now ;)
* Add music plays to graphs.
* Add info pages for music items.
* Add music to user recently watched items.
* Add photo views to Activity pane (photos are not logged).
* Fix token validation message on Settings page.
* Fix some "Mystery" platform names.
* Fix paused time be counted for graph data.
* Other small bug fixes.
## v1.1.8 (2015-09-09)
* Add platform images for Windows devices. Thanks @JonnyWong.
* Add click-through to PlexWeb preplay page from info page. Thanks @JonnyWong.
* Fix broken delete option on info pages. Thanks @JonnyWong.
* Fix tagline bug in PlexWatch db import tool.
* Fix home stats text overflow bug. Thanks @JonnyWong.
## v1.1.7 (2015-09-07)
* Show tagline in info screens for movies. Thanks @JonnyWong.
* Add play/pause/buffer icon to activity pane. Thanks @JonnyWong.
* Add transcoder info in activity pane info. Thanks @JonnyWong.
* Show transcoder progress on activity progress bar. Thanks @JonnyWong.
* Fix bug where custom notification strings would be ignored if unicode characters were present.
* Fix text overflow issue on home stats cards. Thanks @JonnyWong.
* Fix regression with user friendly name change input in edit screen. Thanks @JonnyWong.
## v1.1.6 (2015-09-06)
* Home stats cards are now expandable to show multiple items. Configurable in settings. Thanks @JonnyWong.

View File

@@ -64,7 +64,7 @@ def main():
# Set up and gather command line arguments
parser = argparse.ArgumentParser(
description='Python frontend for PlexWatch.')
description='A Python based monitoring and tracking tool for Plex Media Server.')
parser.add_argument(
'-v', '--verbose', action='store_true', help='Increase console logging verbosity')

View File

@@ -1,5 +1,7 @@
#PlexPy
[![Join the chat at https://gitter.im/drzoidberg33/plexpy](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/drzoidberg33/plexpy?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
A python based web application for monitoring, analytics and notifications for Plex Media Server (www.plex.tv).
This project is based on code from Headphones (https://github.com/rembo10/headphones) and PlexWatchWeb (https://github.com/ecleese/plexWatchWeb).
@@ -120,4 +122,4 @@ If you **comply with these rules** you can [post your request/issue](http://gith
## License
This is free software under the GPL v3 open source license. Feel free to do with it what you wish, but any modification must be open sourced. A copy of the license is included.
This software includes Highsoft software libraries which you may freely distribute for non-commercial use. Commerical users must licence this software, for more information visit https://shop.highsoft.com/faq/non-commercial#non-commercial-redistribution.
This software includes Highsoft software libraries which you may freely distribute for non-commercial use. Commerical users must licence this software, for more information visit https://shop.highsoft.com/faq/non-commercial#non-commercial-redistribution.

View File

@@ -62,16 +62,16 @@ from plexpy import version
% else:
<li><a href="home"><i class="fa fa-lg fa-home"></i></a></li>
% endif
% if title=="History":
<li class="active"><a href="history">History</a></li>
% else:
<li><a href="history">History</a></li>
% endif
% if title=="Users" or title=="User":
<li class="active"><a href="users">Users</a></li>
% else:
<li><a href="users">Users</a></li>
% endif
% if title=="History":
<li class="active"><a href="history">History</a></li>
% else:
<li><a href="history">History</a></li>
% endif
% if title=="Graphs":
<li class="active"><a href="graphs">Graphs</a></li>
% else:

View File

@@ -33,6 +33,33 @@ select.input-sm {
color: #999;
outline: none;
}
select[multiple] {
height: 125px;
margin: 5px 0 5px 0;
color: #fff;
border: 0px solid #444;
background: #555;
padding: 2px 2px;
background-color: #555;
border-radius: 3px;
transition: background-color .3s;
}
select[multiple]:focus {
outline: 0;
outline: thin dotted \9;
color: #555;
background-color: #fff;
transition: background-color .3s;
}
select[multiple]:focus::-webkit-scrollbar-thumb {
background-color: rgba(0,0,0,.15);
}
select[multiple] option {
padding: 6px 10px;
-webkit-border-radius: 2px;
-moz-border-radius: 2px;
border-radius: 2px;
}
img {
-webkit-box-sizing: content-box;
-moz-box-sizing: content-box;
@@ -683,6 +710,13 @@ a:hover .dashboard-activity-poster {
-webkit-transition: all 0s;
transition: all 0s;
}
.dashboard-activity-progress .bufferbar {
padding-top: 6px;
background-color: #444;
position: absolute;
height: 6px;
overflow: hidden;
}
.dashboard-activity-progress .bar {
padding-top: 6px;
background-color: #faa732;
@@ -693,6 +727,9 @@ a:hover .dashboard-activity-poster {
background-image: linear-gradient(to bottom, #fbb450, #f89406);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0);
position: absolute;
height: 6px;
overflow: hidden;
}
.dashboard-activity-metadata-wrapper {
position: relative;
@@ -768,36 +805,88 @@ a .dashboard-activity-metadata-user-thumb:hover {
font-weight: bold;
color: #F9AA03;
}
/*.dashboard-activity-instance-overlay {
position: relative;
top: -12px;
text-align: left;
height: 53px;
width: 250px;
border-radius: 0 0 3px 3px;
}*/
.dashboard-recent-media-row {
width: 100%;
margin:0 auto;
text-align: center;
position: relative;
z-index: 0;
}
.dashboard-recent-media {
width: 100%;
margin: auto;
list-style: none;
}
.dashboard-recent-media-instance {
}
.dashboard-recent-media li {
margin-right: 27px;
float: left;
position: relative;
left: 0px;
margin-right: 25px;
margin-bottom: 25px;
}
.dashboard-recent-media-poster {
position: relative;
float: left;
min-height: 340px;
}
.dashboard-recent-media-cover {
position: relative;
margin-top: 75px;
float: left;
}
a:hover .dashboard-recent-media-poster,
a:hover .dashboard-recent-media-cover {
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;
}
.dashboard-recent-media-poster-face {
background-position: center;
background-size: cover;
height: 225px;
width: 150px;
position: relative;
-webkit-box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1);
-moz-box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1);
box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1);
z-index: -2;
}
.dashboard-recent-media-cover-face {
background-position: center;
background-size: cover;
height: 150px;
width: 150px;
position: relative;
-webkit-box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1);
-moz-box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1);
box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1);
z-index: -2;
}
.dashboard-recent-media-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: 100%;
z-index: -1;
}
.dashboard-recent-media-overlay-text {
color: #aaa;
font-size: 12px;
float: left;
position: absolute;
left: 8px;
bottom: 5px;
}
.dashboard-recent-media-metacontainer {
width: 150px;
font-size: 13px;
margin-bottom: 20px;
clear: both;
}
.dashboard-recent-media-metacontainer h3 {
@@ -815,6 +904,9 @@ a .dashboard-activity-metadata-user-thumb:hover {
text-align: left;
clear: both;
}
.dashboard-recent-media-metacontainer h3.text-muted {
color: #777;
}
.dashboard-recent-media-metacontainer .text-muted {
padding: 5px 3px 0 3px;
text-overflow: ellipsis;
@@ -866,10 +958,12 @@ a .dashboard-activity-metadata-user-thumb:hover {
.summary-navbar-list {
padding: 0 25px;
color: #999;
white-space: nowrap;
overflow: hidden;
}
.summary-navbar-list span {
float: left;
margin-right: 20px;
display: inline-block;
margin-right: 15px;
}
.summary-navbar-list span a {
color: #999;
@@ -894,6 +988,10 @@ a .dashboard-activity-metadata-user-thumb:hover {
line-height: 40px;
float: left;
clear: left;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
width: 100%;
}
.summary-content-title h1 a {
color: #F9AA03;
@@ -910,6 +1008,10 @@ a .dashboard-activity-metadata-user-thumb:hover {
line-height: 40px;
float: left;
clear: left;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
width: 100%;
}
.summary-content-title h3 {
margin-top: 0;
@@ -917,7 +1019,9 @@ a .dashboard-activity-metadata-user-thumb:hover {
color: #999;
font-size: 28px;
line-height: 40px;
float: right;
position: absolute;
bottom: 0;
right: 0;
}
.summary-content-title h3 a:hover {
text-decoration: underline;
@@ -963,11 +1067,54 @@ a .dashboard-activity-metadata-user-thumb:hover {
overflow: hidden;
z-index: 1;
}
a .summary-poster-face:hover,
a .summary-poster-face-episode:hover {
.summary-poster-face-track {
background-position: center;
background-size: cover;
height: 250px;
width: 250px;
position: relative;
webkit-box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1);
-moz-box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1);
box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1);
overflow: hidden;
z-index: 1;
}
.summary-poster-face-overlay {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
background-image: -webkit-gradient(linear,left 0,left 100%,from(rgba(0,0,0,.7)),to(rgba(0,0,0,.9)));
background-image: -webkit-linear-gradient(top,rgba(0,0,0,.7),0,rgba(0,0,0,.9),100%);
background-image: -moz-linear-gradient(top,rgba(0,0,0,.7) 0,rgba(0,0,0,.9) 100%);
background-image: linear-gradient(to bottom,rgba(0,0,0,.7) 0,rgba(0,0,0,.9) 100%);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#b3000000', endColorstr='#e6000000', GradientType=0);
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;
opacity: 0;
transition: opacity .2s;
}
.summary-poster-face-overlay span {
display: block;
width: 100%;
height: 100%;
background-image: url(../images/plex-logo-light.svg);
background-size: 100px;
background-repeat: no-repeat;
background-position: center;
opacity: 0;
transition: opacity .3s;
}
a:hover .summary-poster-face .summary-poster-face-overlay,
a:hover .summary-poster-face-episode .summary-poster-face-overlay,
a:hover .summary-poster-face-track .summary-poster-face-overlay,
a:hover .summary-poster-face .summary-poster-face-overlay span,
a:hover .summary-poster-face-episode .summary-poster-face-overlay span,
a:hover .summary-poster-face-track .summary-poster-face-overlay span {
opacity: 1;
}
.summary-content-padding {
float: left;
@@ -988,47 +1135,11 @@ a .summary-poster-face-episode:hover {
position: relative;
float: left;
}
.summary-content-director {
.summary-content-details-tag {
float: left;
line-height: 24px;
}
.summary-content-director strong {
color: #fff;
margin-left: 2px;
margin-right: 10px;
}
.summary-content-studio {
float: left;
line-height: 24px;
}
.summary-content-studio strong {
color: #fff;
margin-left: 2px;
margin-right: 10px;
}
.summary-content-airdate {
float: left;
line-height: 24px;
}
.summary-content-airdate strong {
color: #fff;
margin-left: 2px;
margin-right: 10px;
}
.summary-content-duration {
float: left;
line-height: 24px;
}
.summary-content-duration strong {
color: #fff;
margin-left: 2px;
margin-right: 10px;
}
.summary-content-content-rating {
float: left;
line-height: 24px;
}
.summary-content-content-rating strong {
.summary-content-details-tag strong {
color: #fff;
margin-left: 2px;
margin-right: 10px;
@@ -1135,135 +1246,57 @@ a .summary-poster-face-episode:hover {
background-size: contain;
height: 16px;
}
.show-seasons-wrapper {
.item-children-wrapper {
}
.show-seasons-instance {
.item-children-instance {
list-style: none;
margin: 0;
}
.show-seasons-instance li {
.item-children-instance li {
float: left;
position: relative;
left: 0px;
margin-right: 25px;
margin-bottom: 25px;
}
a .show-seasons-card-overlay:hover {
.item-children-instance li.item-children-list-item {
width: 100%;
height: 35px;
margin-right: 0;
margin-bottom: 0;
}
.item-children-poster {
float: left;
position: relative;
left: 0px;
}
a:hover .item-children-poster {
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;
}
.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;
-moz-box-shadow: inset 0 0 0 2px #e9a049;
box-shadow: inset 0 0 0 2px #e9a049;
}
.season-episodes-poster {
float: left;
position: relative;
left: 0px;
}
.season-episodes-poster-face {
.item-children-poster-face {
background-position: center;
background-size: cover;
height: 140px;
width: 250px;
position: relative;
-webkit-box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1);
-moz-box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1);
box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1);
z-index: -2;
}
.season-episodes-poster-face img {
bottom: 0;
overflow: hidden;
.item-children-poster-face.season-poster {
width: 150px;
height: 225px;
}
.item-children-poster-face.episode-poster {
width: 250px;
height: 140px;
}
.season-episodes-poster-face img:hover {
-webkit-box-shadow: 0 0 0 2px #F9AA03;
-moz-box-shadow: 0 0 0 2px #F9AA03;
box-shadow: 0 0 0 2px #F9AA03;
.item-children-poster-face.album-poster {
width: 150px;
height: 150px;
}
.season-episodes-card-overlay {
.item-children-card-overlay {
position: absolute;
left: 0;
right: 0;
@@ -1275,14 +1308,10 @@ a .season-episodes-card-overlay:hover {
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: 140px;
height: 100%;
z-index: -1;
}
.season-episodes-card-overlay-index {
color: #fff;
font-size: 11px;
text-shadow: 0 1px 5px rgba(0,0,0,0.2);
}
.season-episodes-overlay-text {
.item-children-overlay-text {
color: #aaa;
font-size: 12px;
float: left;
@@ -1290,7 +1319,22 @@ a .season-episodes-card-overlay:hover {
left: 8px;
bottom: 5px;
}
.season-episodes-instance-text-wrapper h3 {
.item-children-instance-text-wrapper {
font-size: 13px;
margin-bottom: 20px;
clear: both;
}
.item-children-instance-text-wrapper.season-item {
width: 150px;
}
.item-children-instance-text-wrapper.episode-item {
width: 250px;
}
.item-children-instance-text-wrapper.album-item {
width: 150px;
}
.item-children-instance-text-wrapper h3 {
width: 100%;
padding: 5px 3px 0 3px;
color: #fff;
text-overflow: ellipsis;
@@ -1300,36 +1344,52 @@ a .season-episodes-card-overlay:hover {
margin: 0;
line-height: 15px;
font-weight: normal;
width: 250px;
white-space: nowrap;
text-align: left;
clear: both;
}
.season-episodes-title a {
text-decoration: none;
font-size: 14px;
font-weight: normal;
color: #fff;
.item-children-list-item-odd {
border-top: 0px solid #343434;
border-bottom: 0px solid #343434;
background-color: rgba(255,255,255,0.010);
height: 100%;
font-size: 13px;
padding-top: 10px;
}
.item-children-list-item-even {
border-top: 0px solid #343434;
border-bottom: 0px solid #343434;
background-color: rgba(255,255,255,0.035);
height: 100%;
font-size: 13px;
padding-top: 10px;
}
.item-children-list-item-odd:hover,
.item-children-list-item-even:hover {
background-color: rgba(255,255,255,0.075);
}
.item-children-list-item-index {
float: left;
color: #777;
text-align: right;
display: inline-block;
width: 35px;
margin-right: 10px;
}
.item-children-list-item-title {
display: inline-block;
width: calc(100% - 110px);
text-overflow: ellipsis;
overflow: hidden;
position: relative;
white-space: nowrap;
width: 205px;
margin-top: 2px;
margin-left: 0px;
margin-bottom: 20px;
}
.season-episodes a:hover {
color: #F9AA03;
}
.season-episodes-season {
color: #aaa;
font-size: 12px;
float: left;
position: absolute;
left: 8px;
bottom: 5px;
.item-children-list-item-duration {
float: right;
color: #777;
text-align: right;
display: inline-block;
width: 40px;
margin-right: 20px;
}
.settings-alert {
float: left;
@@ -1541,6 +1601,7 @@ a .season-episodes-card-overlay:hover {
-webkit-box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1);
-moz-box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1);
box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1);
white-space: nowrap;
}
.home-platforms-instance li {
position: relative;
@@ -1553,7 +1614,6 @@ a .season-episodes-card-overlay:hover {
height: 120px;
}
.home-platforms-instance-name {
float: left;
color: #fff;
text-overflow: ellipsis;
overflow: hidden;
@@ -1565,53 +1625,21 @@ a .season-episodes-card-overlay:hover {
padding: 0 0 0 20px;
}
.home-platforms-instance-name h4 {
margin: 10px 0 20px 0;
}
.home-platforms-instance-name h5 {
font-size: 14px;
line-height: 16px;
margin: 15px 0 2px 0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.home-platforms-instance-name2 {
position: absolute;
top: 34px;
left: 215px;
}
.home-platforms-instance-name2 h5 {
font-size: 14px;
line-height: 16px;
margin: 15px 0 2px 0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.home-platforms-instance-name2 h3 {
font-size: 30px;
font-weight: bold;
color: #F9AA03;
line-height: 22px;
position: relative;
top: 5px;
margin: 0 5px 0 0;
padding-top: 6px;
float: left;
}
.home-platforms-instance-name2 p {
color: #aaa;
font-size: 12px;
float: left;
position: relative;
top: 21px;
left: 0px;
margin: 10px 0 4px 0;
}
.home-platforms-instance-playcount {
float: left;
display: inline-block;
position: relative;
padding: 6px 0 0 20px;
width: 100%;
max-width: 100%;
}
.home-platforms-instance-playcount h4 {
font-size: 14px;
line-height: 16px;
margin: 10px 0 10px 0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.home-platforms-instance-playcount h3 {
font-size: 30px;
@@ -1638,6 +1666,14 @@ a .season-episodes-card-overlay:hover {
padding: 6px 0 0 20px;
width: 100%;
}
.home-platforms-instance-last-user h4 {
font-size: 14px;
line-height: 16px;
margin: 10px 0 10px 0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.home-platforms-instance-last-user h5 {
font-size: 12px;
position: relative;
@@ -2220,6 +2256,9 @@ a .home-platforms-instance-list-oval:hover,
color: #fff;
cursor: pointer;
}
.edit-user-name > input[type='text'] {
margin: 0;
}
.popover {
z-index: 2;
}

View File

@@ -34,6 +34,9 @@ title Returns the name of the episode, movie or music trac
year Returns the year of the episode, movie, or clip.
player Returns the name of the platform used to play the stream.
platform Returns the type of platform used to play the stream.
throttled Returns true if the transcode session is throttled.
transcode_progress Returns the current transcode progress of the item. 0 to 100.
transcode_speed Returns the current transcode speed of the item.
audio_decision Returns the audio transcode decision. Either 'transcode', 'copy' or 'direct play'.
audio_codec Returns the name of the audio codec.
audio_channels Returns the number of audio channels.
@@ -64,11 +67,10 @@ DOCUMENTATION :: END
% if data['stream_count'] != '0':
% for a in data['sessions']:
<div class="dashboard-instance" id="instance-${a['session_key']}">
% if a['type'] == 'movie' or a['type'] == 'episode':
% if a['type'] == 'movie' or a['type'] == 'episode' or a['type'] == 'track':
<a href="info?item_id=${a['rating_key']}">
% endif
<div class="dashboard-activity-poster">
<script>console.log('${a['indexes']}');</script>
% if a['type'] == 'movie' and not a['indexes']:
<div class="dashboard-activity-poster-face" style="background-image: url(pms_image_proxy?img=${a['art']}&width=500&height=280);"></div>
% elif a['type'] == 'episode' and not a['indexes']:
@@ -91,6 +93,8 @@ DOCUMENTATION :: END
<div class="dashboard-activity-poster-face" style="background-image: url(pms_image_proxy?img=${a['thumb']}&width=500&height=280);"></div>
% endif
% endif
% elif a['type'] == 'photo':
<div class="dashboard-activity-poster-face bif" style="background-image: url(pms_image_proxy?img=${a['thumb']}&width=500&height=500);"></div>
% else:
<div class="dashboard-activity-cover-face" style="background-image: url(pms_image_proxy?img=${a['thumb']}&width=300&height=300&fallback=cover);"></div>
% endif
@@ -115,8 +119,15 @@ DOCUMENTATION :: END
% if a['type'] == 'track':
% if a['audio_decision'] == 'direct play':
Stream &nbsp;<strong>Direct Play</strong>
% elif a['audio_decision'] == 'copy':
Stream &nbsp;<strong>Direct Stream</strong>
% else:
Stream &nbsp;<strong>Transcoding</strong>
Stream &nbsp;<strong>Transcoding
(Speed: ${a['transcode_speed']})
% if a['throttled'] == '1':
(Throttled)
% endif
</strong>
% endif
<br />
% if a['audio_decision'] == 'direct play':
@@ -127,10 +138,17 @@ DOCUMENTATION :: END
Audio &nbsp;<strong>Transcode (${a['transcode_audio_codec']}) (${a['transcode_audio_channels']}ch)</strong>
% endif
% elif a['type'] == 'episode' or a['type'] == 'movie' or a['type'] == 'clip':
% if a['video_decision'] == 'direct play':
% if a['video_decision'] == 'direct play' and a['audio_decision'] == 'direct play':
Stream &nbsp;<strong>Direct Play</strong>
% elif a['video_decision'] == 'copy' and a['audio_decision'] == 'copy':
Stream &nbsp;<strong>Direct Stream</strong>
% else:
Stream &nbsp;<strong>Transcoding</strong>
Stream &nbsp;<strong>Transcoding
(Speed: ${a['transcode_speed']})
% if a['throttled'] == '1':
(Throttled)
% endif
</strong>
% endif
<br />
% if a['video_decision'] == 'direct play':
@@ -148,21 +166,38 @@ DOCUMENTATION :: END
% elif a['audio_decision'] == 'transcode':
Audio &nbsp;<strong>Transcode (${a['transcode_audio_codec']}) (${a['transcode_audio_channels']}ch)</strong>
% endif
% elif a['type'] == 'photo':
% if a['video_decision'] == 'direct play':
Stream &nbsp;<strong>Direct Play</strong>
% elif a['video_decision'] == 'copy':
Stream &nbsp;<strong>Direct Stream</strong>
% else:
Stream &nbsp;<strong>
Transcoding
(Speed: ${a['transcode_speed']})
% if a['throttled'] == '1':
(Throttled)
% endif
</strong>
% endif
% endif
<br>
</div>
</div>
% if a['type'] != 'photo':
<div class="dashboard-activity-poster-info-bar">
<div class="dashboard-activity-poster-info-time">
<span class="progress_time">${a['progress']}</span>/<span class="progress_time">${a['duration']}</span>
</div>
</div>
% endif
</div>
% if a['type'] == 'movie' or a['type'] == 'episode':
% if a['type'] == 'movie' or a['type'] == 'episode' or a['type'] == 'track':
</a>
% endif
<div class="dashboard-activity-progress">
<div class="dashboard-activity-progress-bar">
<div class="bufferbar" style="width: ${a['transcode_progress']}%">${a['transcode_progress']}%</div>
<div class="bar" style="width: ${a['progress_percent']}%">${a['progress_percent']}%</div>
</div>
</div>
@@ -171,6 +206,13 @@ DOCUMENTATION :: END
<div class="dashboard-activity-metadata-user-thumb" style="background-image: url(${a['user_thumb']});"></div>
</a>
<div class="dashboard-activity-metadata-title">
% if a['state'] == 'playing':
<i class="fa fa-play"></i>&nbsp;
% elif a['state'] == 'paused':
<i class="fa fa-pause"></i>&nbsp;
% elif a['state'] == 'buffering':
<i class="fa fa-spinner"></i>&nbsp;
% endif
% if a['type'] == 'episode':
<a href="info?item_id=${a['rating_key']}">${a['grandparent_title']} - ${a['title']}</a>
% elif a['type'] == 'movie':
@@ -178,9 +220,11 @@ DOCUMENTATION :: END
% elif a['type'] == 'clip':
${a['title']}
% elif a['type'] == 'track':
${a['grandparent_title']} - ${a['title']}
<a href="info?item_id=${a['rating_key']}">${a['grandparent_title']} - ${a['title']}</a>
% elif a['type'] == 'photo':
${a['parent_title']}
% else:
${a['grandparent_title']} - ${a['title']}
${a['title']}
% endif
</div>
<div class="dashboard-activity-metadata-subtitle">
@@ -189,7 +233,9 @@ DOCUMENTATION :: END
% elif a['type'] == 'movie':
${a['year']}
% elif a['type'] == 'track':
${a['parent_title']}
<a href="info?item_id=${a['parent_rating_key']}">${a['parent_title']}</a>
% elif a['type'] == 'photo':
${a['title']}
% else:
${a['year']}
% endif
@@ -211,7 +257,7 @@ DOCUMENTATION :: END
<script>
// When using bif indexes make the image transition a little smoother.
$('.bif').each(function() {
$(this).fadeIn(1000);
$(this).hide().fadeIn(1000);
});
// Convert timestamps to readable times

View File

@@ -48,7 +48,7 @@
<div class="col-md-12">
<h4><i class="fa fa-history"></i> Daily <span class="yaxis-text">Play count</span> <small>Last <span class="days">30</span> days</small></h4>
<p class="help-block">
The total play count or duration of movies and tv played per day. Click a graph point to open up a list of items played for that specific date.
The total play count or duration of tv, movies, and music played per day. Click a graph point to open up a list of items played for that specific date.
</p>
<div class="graphs-instance">
<div class="watch-chart" id="chart_div_plays_by_day">
@@ -62,7 +62,7 @@
<div class="col-md-6">
<h4><i class="fa fa-calendar"></i> <span class="yaxis-text">Play count</span> by day of week <small>Last <span class="days">30</span> days</small></h4>
<p class="help-block">
The combined total of movies and tv played per day of the week.
The combined total of tv, movies, and music played per day of the week.
</p>
<div class="graphs-instance">
<div class="watch-chart" id="chart_div_plays_by_dayofweek" style="float: left;">
@@ -75,7 +75,7 @@
<div class="col-md-6">
<h4><i class="fa fa-clock-o"></i> <span class="yaxis-text">Play count</span> by hour of day <small>Last <span class="days">30</span> days</small></h4>
<p class="help-block">
The combined total of movies and tv played per hour of the day.
The combined total of tv, movies, and music played per hour of the day.
</p>
<div class="graphs-instance">
<div class="watch-chart" id="chart_div_plays_by_hourofday">
@@ -90,7 +90,7 @@
<div class="col-md-6">
<h4><i class="fa fa-television"></i> <span class="yaxis-text">Play count</span> by top 10 platforms <small>Last <span class="days">30</span> days</small></h4>
<p class="help-block">
The combined total of movies and tv played by top 10 most active platforms.
The combined total of tv, movies, and music played by top 10 most active platforms.
</p>
<div class="graphs-instance">
<div class="watch-chart" id="chart_div_plays_by_platform" style="float: left;">
@@ -103,7 +103,7 @@
<div class="col-md-6">
<h4><i class="fa fa-user"></i> <span class="yaxis-text">Play count</span> by top 10 users <small>Last <span class="days">30</span> days</small></h4>
<p class="help-block">
The combined total of movies and tv played by top 10 most active users.
The combined total of tv, movies, and music played by top 10 most active users.
</p>
<div class="graphs-instance">
<div class="watch-chart" id="chart_div_plays_by_user">
@@ -121,7 +121,7 @@
<div class="col-md-12">
<h4><i class="fa fa-video-camera"></i> Daily Stream type breakdown <small>Last <span class="days">30</span> days</small></h4>
<p class="help-block">
The total play count or duration of movies and tv by the transcode decision. Click a graph point to open up a list of items played for that specific date.
The total play count or duration of tv, movies, and music by the transcode decision. Click a graph point to open up a list of items played for that specific date.
</p>
<div class="graphs-instance">
<div class="watch-chart" id="chart_div_plays_by_stream_type">
@@ -135,7 +135,7 @@
<div class="col-md-6">
<h4><i class="fa fa-expand"></i> <span class="yaxis-text">Play count</span> by source resolution <small>Last <span class="days">30</span> days</small></h4>
<p class="help-block">
The combined total of movies and tv by their original resolution (pre-transcoding).
The combined total of tv and movies by their original resolution (pre-transcoding).
</p>
<div class="graphs-instance">
<div class="watch-chart" id="chart_div_plays_by_source_resolution" style="float: left;">
@@ -148,7 +148,7 @@
<div class="col-md-6">
<h4><i class="fa fa-expand"></i> <span class="yaxis-text">Play count</span> by stream resolution <small>Last <span class="days">30</span> days</small></h4>
<p class="help-block">
The combined total of movies and tv by their streamed resolution (post-transcoding).
The combined total of tv and movies by their streamed resolution (post-transcoding).
</p>
<div class="graphs-instance">
<div class="watch-chart" id="chart_div_plays_by_stream_resolution">
@@ -163,7 +163,7 @@
<div class="col-md-6">
<h4><i class="fa fa-television"></i> <span class="yaxis-text">Play count</span> by platform and stream type <small>Last <span class="days">30</span> days</small></h4>
<p class="help-block">
The combined total of movies and tv by platform and stream type.
The combined total of tv, movies, and music by platform and stream type.
</p>
<div class="graphs-instance">
<div class="watch-chart" id="chart_div_plays_by_platform_by_stream_type" style="float: left;">
@@ -176,7 +176,7 @@
<div class="col-md-6">
<h4><i class="fa fa-user"></i> <span class="yaxis-text">Play count</span> by user and stream type <small>Last <span class="days">30</span> days</small></h4>
<p class="help-block">
The combined total of movies and tv by user and stream type.
The combined total of tv, movies, and music by user and stream type.
</p>
<div class="graphs-instance">
<div class="watch-chart" id="chart_div_plays_by_user_by_stream_type" style="float: left;">
@@ -194,7 +194,7 @@
<div class="col-md-12">
<h4><i class="fa fa-calendar"></i> Plays by Month <small>Last 12 months</small></h4>
<p class="help-block">
The combined total of movies and tv by month.
The combined total of tv, movies, and music by month.
</p>
<div class="graphs-instance">
<div class="watch-chart" id="chart_div_plays_by_month">
@@ -294,6 +294,8 @@
$('a[data-toggle=tab][href=' + current_tab + ']').trigger('click');
}
var music_visible = (${config['music_logging_enable']} == 1 ? true : false);
function loadGraphsTab1(time_range, yaxis) {
setGraphFormat(yaxis);
@@ -319,6 +321,7 @@
hc_plays_by_day_options.yAxis.min = 0;
hc_plays_by_day_options.xAxis.categories = dateArray;
hc_plays_by_day_options.series = data.series;
hc_plays_by_day_options.series[2].visible = music_visible;
var hc_plays_by_day = new Highcharts.Chart(hc_plays_by_day_options);
}
});
@@ -331,6 +334,7 @@
success: function(data) {
hc_plays_by_dayofweek_options.xAxis.categories = data.categories;
hc_plays_by_dayofweek_options.series = data.series;
hc_plays_by_dayofweek_options.series[2].visible = music_visible;
var hc_plays_by_dayofweek = new Highcharts.Chart(hc_plays_by_dayofweek_options);
}
});
@@ -343,6 +347,7 @@
success: function(data) {
hc_plays_by_hourofday_options.xAxis.categories = data.categories;
hc_plays_by_hourofday_options.series = data.series;
hc_plays_by_hourofday_options.series[2].visible = music_visible;
var hc_plays_by_hourofday = new Highcharts.Chart(hc_plays_by_hourofday_options);
}
});
@@ -355,6 +360,7 @@
success: function(data) {
hc_plays_by_platform_options.xAxis.categories = data.categories;
hc_plays_by_platform_options.series = data.series;
hc_plays_by_platform_options.series[2].visible = music_visible;
var hc_plays_by_platform = new Highcharts.Chart(hc_plays_by_platform_options);
}
});
@@ -367,6 +373,7 @@
success: function(data) {
hc_plays_by_user_options.xAxis.categories = data.categories;
hc_plays_by_user_options.series = data.series;
hc_plays_by_user_options.series[2].visible = music_visible;
var hc_plays_by_user = new Highcharts.Chart(hc_plays_by_user_options);
}
});
@@ -462,6 +469,7 @@
hc_plays_by_month_options.yAxis.min = 0;
hc_plays_by_month_options.xAxis.categories = data.categories;
hc_plays_by_month_options.series = data.series;
hc_plays_by_month_options.series[2].visible = music_visible;
var hc_plays_by_month = new Highcharts.Chart(hc_plays_by_month_options);
}
});

View File

@@ -17,19 +17,19 @@ 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' or 'top_movies' or 'popular_movies' or 'last_watched' ==
== Only if 'stat_id' is 'top_tv' or 'popular_tv' or 'top_movies' or 'popular_movies' or 'top_music' or 'popular_music' or 'last_watched' ==
thumb Return the thumb for the media item.
== Only if 'stat_id' is 'top_tv' or 'popular_tv' ==
== Only if 'stat_id' is 'top_tv' or 'popular_tv' or 'top_music' or 'popular_music' ==
grandparent_thumb Returns location of the item's thumbnail. Use with pms_image_proxy.
rating_key Returns the unique identifier for the media item.
title Returns the title for the associated stat.
== Only if 'stat_id' is 'top_tv' or 'top_movies' or 'top_user' or 'top_platform' ==
== Only if 'stat_id' is 'top_tv' or 'top_movies' or 'top_music' or 'top_user' or 'top_platform' ==
total_plays Returns the count for the associated stat.
total_duration Returns the total duration for the associated stat.
== Only of 'stat_id' is 'popular_tv' or 'popular_movies' ==
== Only of 'stat_id' is 'popular_tv' or 'popular_movies' or 'popular_music' ==
users_watched Returns the count for the associated stat.
== Only if 'stat_id' is 'top_user' or 'last_watched' ==
@@ -51,16 +51,17 @@ DOCUMENTATION :: END
from plexpy import helpers
# Human readable duration
def hd(minutes):
if int(minutes) > 60:
hours = int(helpers.cast_to_float(minutes) / 60)
minutes = int(helpers.cast_to_float(minutes) % 60 )
def hd(seconds):
minutes = helpers.cast_to_float(seconds) / 60
if minutes > 60:
hours = int(minutes / 60)
minutes = int(minutes % 60)
if minutes > 0:
return "<h3>" + str(hours) + "</h3><p>hrs</p><h3>" + str(minutes) + "</h3><p>mins</p>"
else:
return "<h3>" + str(hours) + "</h3><p>hrs</p>"
else:
return "<h3>" + minutes + "</h3><p>mins</p>"
return "<h3>" + str(int(minutes)) + "</h3><p>mins</p>"
%>
% if data:
@@ -73,13 +74,13 @@ DOCUMENTATION :: END
<div class="home-platforms-instance-info">
<div class="home-platforms-instance-name">
<h4>Most Watched TV</h4>
<h5>
</div>
<div class="home-platforms-instance-playcount">
<h4>
<a href="info?item_id=${top_stat['rows'][0]['rating_key']}">
${top_stat['rows'][0]['title']}
</a>
</h5>
</div>
<div class="home-platforms-instance-playcount">
</h4>
% if top_stat['stat_type'] == 'total_plays':
<h3>${top_stat['rows'][0]['total_plays']}</h3>
<p> plays</p>
@@ -153,13 +154,13 @@ DOCUMENTATION :: END
<div class="home-platforms-instance-info">
<div class="home-platforms-instance-name">
<h4>Most Popular TV</h4>
<h5>
</div>
<div class="home-platforms-instance-playcount">
<h4>
<a href="info?item_id=${top_stat['rows'][0]['rating_key']}">
${top_stat['rows'][0]['title']}
</a>
</h5>
</div>
<div class="home-platforms-instance-playcount">
</h4>
<h3>${top_stat['rows'][0]['users_watched']}</h3>
<p> users</p>
</div>
@@ -225,13 +226,13 @@ DOCUMENTATION :: END
<div class="home-platforms-instance-info">
<div class="home-platforms-instance-name">
<h4>Most Watched Movie</h4>
<h5>
</div>
<div class="home-platforms-instance-playcount">
<h4>
<a href="info?item_id=${top_stat['rows'][0]['rating_key']}">
${top_stat['rows'][0]['title']}
</a>
</h5>
</div>
<div class="home-platforms-instance-playcount">
</h4>
% if top_stat['stat_type'] == 'total_plays':
<h3>${top_stat['rows'][0]['total_plays']}</h3>
<p> plays</p>
@@ -305,13 +306,13 @@ DOCUMENTATION :: END
<div class="home-platforms-instance-info">
<div class="home-platforms-instance-name">
<h4>Most Popular Movie</h4>
<h5>
</div>
<div class="home-platforms-instance-playcount">
<h4>
<a href="info?item_id=${top_stat['rows'][0]['rating_key']}">
${top_stat['rows'][0]['title']}
</a>
</h5>
</div>
<div class="home-platforms-instance-playcount">
</h4>
<h3>${top_stat['rows'][0]['users_watched']}</h3>
<p> users</p>
</div>
@@ -371,23 +372,175 @@ DOCUMENTATION :: END
% endif
</li>
</div>
% elif top_stat['stat_id'] == 'top_music' and top_stat['rows']:
<div class="home-platforms-instance">
<li>
<div class="home-platforms-instance-info">
<div class="home-platforms-instance-name">
<h4>Most Listened to Artist</h4>
</div>
<div class="home-platforms-instance-playcount">
<h4>
<a href="info?item_id=${top_stat['rows'][0]['rating_key']}">
${top_stat['rows'][0]['title']}
</a>
</h4>
% if top_stat['stat_type'] == 'total_plays':
<h3>${top_stat['rows'][0]['total_plays']}</h3>
<p> plays</p>
% else:
${top_stat['rows'][0]['total_duration'] | hd}
% endif
</div>
</div>
<a href="info?item_id=${top_stat['rows'][0]['rating_key']}">
% if top_stat['rows'][0]['grandparent_thumb']:
<div class="home-platforms-instance-poster">
<div class="home-platforms-poster-face" style="background-image: url(pms_image_proxy?img=${top_stat['rows'][0]['grandparent_thumb']}&width=300&height=300&fallback=poster);"></div>
</div>
% else:
<div class="home-platforms-instance-poster">
<div class="home-platforms-poster-face" style="background-image: url(interfaces/default/images/poster.png);"></div>
</div>
% endif
</a>
%if len(top_stat['rows']) > 1:
<div class="home-platforms-instance-list-chevron"><i class="fa fa-chevron-down"></i></div>
<ul class="list-unstyled">
<div class="slider">
<div class="home-platforms-instance-list">
% for row in top_stat['rows']:
%if loop.index > 0:
<li>
<div class="home-platforms-instance-list-info">
<div class="home-platforms-instance-list-name">
<h5>
<a href="info?item_id=${top_stat['rows'][loop.index]['rating_key']}">
${top_stat['rows'][loop.index]['title']}
</a>
</h5>
</div>
<div class="home-platforms-instance-list-playcount">
% if top_stat['stat_type'] == 'total_plays':
<h3>${top_stat['rows'][loop.index]['total_plays']}</h3>
<p> plays</p>
% else:
${top_stat['rows'][loop.index]['total_duration'] | hd}
% endif
</div>
</div>
<a href="info?item_id=${top_stat['rows'][loop.index]['rating_key']}">
% if top_stat['rows'][loop.index]['grandparent_thumb']:
<div class="home-platforms-instance-list-poster">
<div class="home-platforms-list-poster-face" style="background-image: url(pms_image_proxy?img=${top_stat['rows'][loop.index]['grandparent_thumb']}&width=300&height=300&fallback=poster);"></div>
</div>
% else:
<div class="home-platforms-instance-poster2">
<div class="home-platforms-list-poster-face" style="background-image: url(interfaces/default/images/poster.png);"></div>
</div>
% endif
</a>
<div class="home-platforms-instance-list-number">
<h4>${loop.index + 1}</h4>
</div>
</li>
% endif
% endfor
</div>
</div>
</ul>
% endif
</li>
</div>
% elif top_stat['stat_id'] == 'popular_music' and top_stat['rows']:
<div class="home-platforms-instance">
<li>
<div class="home-platforms-instance-info">
<div class="home-platforms-instance-name">
<h4>Most Popular Artist</h4>
</div>
<div class="home-platforms-instance-playcount">
<h4>
<a href="info?item_id=${top_stat['rows'][0]['rating_key']}">
${top_stat['rows'][0]['title']}
</a>
</h4>
<h3>${top_stat['rows'][0]['users_watched']}</h3>
<p> users</p>
</div>
</div>
<a href="info?item_id=${top_stat['rows'][0]['rating_key']}">
% if top_stat['rows'][0]['grandparent_thumb'] != '':
<div class="home-platforms-instance-poster">
<div class="home-platforms-poster-face" style="background-image: url(pms_image_proxy?img=${top_stat['rows'][0]['grandparent_thumb']}&width=300&height=300&fallback=poster);"></div>
</div>
% else:
<div class="home-platforms-instance-poster">
<div class="home-platforms-poster-face" style="background-image: url(interfaces/default/images/poster.png);"></div>
</div>
% endif
</a>
%if len(top_stat['rows']) > 1:
<div class="home-platforms-instance-list-chevron"><i class="fa fa-chevron-down"></i></div>
<ul class="list-unstyled">
<div class="slider">
<div class="home-platforms-instance-list">
% for row in top_stat['rows']:
%if loop.index > 0:
<li>
<div class="home-platforms-instance-list-info">
<div class="home-platforms-instance-list-name">
<h5>
<a href="info?item_id=${top_stat['rows'][loop.index]['rating_key']}">
${top_stat['rows'][loop.index]['title']}
</a>
</h5>
</div>
<div class="home-platforms-instance-list-playcount">
<h3>${top_stat['rows'][loop.index]['users_watched']}</h3>
<p> users</p>
</div>
</div>
<a href="info?item_id=${top_stat['rows'][loop.index]['rating_key']}">
% if top_stat['rows'][loop.index]['grandparent_thumb']:
<div class="home-platforms-instance-list-poster">
<div class="home-platforms-list-poster-face" style="background-image: url(pms_image_proxy?img=${top_stat['rows'][loop.index]['grandparent_thumb']}&width=300&height=300&fallback=poster);"></div>
</div>
% else:
<div class="home-platforms-instance-poster2">
<div class="home-platforms-list-poster-face" style="background-image: url(interfaces/default/images/poster.png);"></div>
</div>
% endif
</a>
<div class="home-platforms-instance-list-number">
<h4>${loop.index + 1}</h4>
</div>
</li>
% endif
% endfor
</div>
</div>
</ul>
% endif
</li>
</div>
% elif top_stat['stat_id'] == 'top_users' and top_stat['rows']:
<div class="home-platforms-instance">
<li>
<div class="home-platforms-instance-info">
<div class="home-platforms-instance-name">
<h4>Most Active User</h4>
<h5>
% if top_stat['rows'][0]['user_id']:
<a href="user?user_id=${top_stat['rows'][0]['user_id']}">
% else:
<a href="user?user=${top_stat['rows'][0]['user']}">
% endif
${top_stat['rows'][0]['friendly_name']}
</a>
</h5>
</div>
<div class="home-platforms-instance-playcount">
<h4>
% if top_stat['rows'][0]['user_id']:
<a href="user?user_id=${top_stat['rows'][0]['user_id']}">
% else:
<a href="user?user=${top_stat['rows'][0]['user']}">
% endif
${top_stat['rows'][0]['friendly_name']}
</a>
</h4>
% if top_stat['stat_type'] == 'total_plays':
<h3>${top_stat['rows'][0]['total_plays']}</h3>
<p> plays</p>
@@ -473,9 +626,9 @@ DOCUMENTATION :: END
<div class="home-platforms-instance-info">
<div class="home-platforms-instance-name">
<h4>Most Active Platform</h4>
<h5>${top_stat['rows'][0]['platform_type']}</h5>
</div>
<div class="home-platforms-instance-playcount">
<h4>${top_stat['rows'][0]['platform_type']}</h4>
% if top_stat['stat_type'] == 'total_plays':
<h3>${top_stat['rows'][0]['total_plays']}</h3>
<p> plays</p>
@@ -535,13 +688,13 @@ DOCUMENTATION :: END
<div class="home-platforms-instance-info">
<div class="home-platforms-instance-name">
<h4>Last Watched</h4>
<h5>
</div>
<div class="home-platforms-instance-last-user">
<h4>
<a href="info?source=history&item_id=${top_stat['rows'][0]['row_id']}">
${top_stat['rows'][0]['title']}
</a>
</h5>
</div>
<div class="home-platforms-instance-last-user">
</h4>
<h5>
% if top_stat['rows'][0]['user_id']:
<a href="user?user_id=${top_stat['rows'][0]['user_id']}">

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="3086px" height="1000px" viewBox="0 0 3086 1000" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<!-- Generator: Sketch 3.2.2 (9983) - http://www.bohemiancoding.com/sketch -->
<title>plex-logo-light</title>
<desc>Created with Sketch.</desc>
<defs>
<radialGradient cx="89.2670157%" cy="49.76%" fx="89.2670157%" fy="49.76%" r="92.4996161%" id="radialGradient-1">
<stop stop-color="#F9BE03" offset="0%"></stop>
<stop stop-color="#CC7C19" offset="100%"></stop>
</radialGradient>
</defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
<g id="plex-logo-light" sketch:type="MSArtboardGroup">
<g sketch:type="MSLayerGroup">
<path d="M3085.99,0 L2795.989,0 L2505.99,500 L2795.989,1000 L3085.737,1000 L2795.989,500.25 L3085.99,0" id="X" fill="#FFFFFF" sketch:type="MSShapeGroup"></path>
<path d="M2186,0 L2476.00071,0 L2796,500.25 L2476.00071,1000.5 L2186,1000.5 L2505.99929,500.25 L2186,0" id="chevron" fill="url(#radialGradient-1)" sketch:type="MSShapeGroup"></path>
<path d="M2085.947,1000 L1508.874,1000 L1508.874,0 L2085.947,0 L2085.947,173.737 L1721.339,173.737 L1721.339,393.299 L2060.594,393.299 L2060.594,567.03 L1721.339,567.03 L1721.339,824.895 L2085.947,824.895 L2085.947,1000" id="E" fill="#FFFFFF" sketch:type="MSShapeGroup"></path>
<path d="M791.276,1000 L791.276,0 L1003.316,0 L1003.316,824.895 L1408.925,824.895 L1408.925,1000 L791.276,1000" id="L" fill="#FFFFFF" sketch:type="MSShapeGroup"></path>
<g id="P" fill="#FFFFFF" sketch:type="MSShapeGroup">
<path d="M589.947,558.824 C522.679,615.831 427.037,644.325 303.009,644.325 L212.04,644.325 L212.04,1000 L0,1000 L0,643.947829 L0,470.337388 L290,470.697418 C467.563171,468.627777 476.842468,359.878967 476.842468,322.200012 C476.842468,287.221283 476.842468,175.445374 319,173.699997 L0,173.703242 L0,0 L319.424,0 C440.717,0 532.939,26.107 596.101,78.321 C659.253,130.534 690.834,208.392 690.834,311.902 C690.834,419.527 657.202,501.83 589.947,558.824 Z" id="Path"></path>
<rect id="Path" x="0" y="110" width="212.2" height="429"></rect>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@@ -16,6 +16,7 @@
</div>
</div>
</div>
% if config['home_stats_cards'] > 'watch_statistics':
<div class="row">
<div class="col-md-12">
<div class="padded-header">
@@ -27,6 +28,8 @@
</div>
</div>
</div>
% endif
% if config['home_library_cards'] > 'library_statistics':
<div class="row">
<div class="col-md-12">
<div class="padded-header" id="library-statistics-header">
@@ -38,6 +41,7 @@
</div>
</div>
</div>
% endif
<div class='row'>
<div class="col-md-12">
<div class="padded-header">
@@ -82,12 +86,12 @@
currentActivity();
setInterval(currentActivity, 15000);
function getHomeStats(days, stat_type, stat_count) {
function getHomeStats(days) {
$.ajax({
url: 'home_stats',
cache: false,
async: true,
data: {time_range: days, stat_type: stat_type, stat_count: stat_count},
data: { },
complete: function(xhr, status) {
$("#home-stats").html(xhr.responseText);
}
@@ -165,7 +169,7 @@
}
});
getHomeStats(${config['home_stats_length']}, ${config['home_stats_type']}, ${config['home_stats_count']});
getHomeStats();
getLibraryStatsHeader();
getLibraryStats();

View File

@@ -61,19 +61,37 @@ DOCUMENTATION :: END
<span><i class="fa fa-chevron-right"></i></span>
<span><a href="#">${data['title']}</a></span>
% elif data['type'] == 'season':
<span>TV Shows</span>
<span><i class="fa fa-chevron-right"></i></span>
<span class="hidden-xs hidden-sm">TV Shows</span>
<span class="hidden-xs hidden-sm"><i class="fa fa-chevron-right"></i></span>
<span><a href="info?item_id=${data['parent_rating_key']}">${data['parent_title']}</a></span>
<span><i class="fa fa-chevron-right"></i></span>
<span><a href="#">Season ${data['index']}</a></span>
% elif data['type'] == 'episode':
<span>TV Shows</span>
<span><i class="fa fa-chevron-right"></i></span>
<span><a href="info?item_id=${data['grandparent_rating_key']}">${data['grandparent_title']}</a></span>
<span><i class="fa fa-chevron-right"></i></span>
<span class="hidden-xs hidden-sm">TV Shows</span>
<span class="hidden-xs hidden-sm"><i class="fa fa-chevron-right"></i></span>
<span class="hidden-xs hidden-sm"><a href="info?item_id=${data['grandparent_rating_key']}">${data['grandparent_title']}</a></span>
<span class="hidden-xs hidden-sm"><i class="fa fa-chevron-right"></i></span>
<span><a href="info?item_id=${data['parent_rating_key']}">Season ${data['parent_index']}</a></span>
<span><i class="fa fa-chevron-right"></i></span>
<span><a href="#">Episode ${data['index']} - ${data['title']}</a></span>
% elif data['type'] == 'artist':
<span>Music</span>
<span><i class="fa fa-chevron-right"></i></span>
<span><a href="#">${data['title']}</a></span>
% elif data['type'] == 'album':
<span class="hidden-xs hidden-sm">Music</span>
<span class="hidden-xs hidden-sm"><i class="fa fa-chevron-right"></i></span>
<span><a href="info?item_id=${data['parent_rating_key']}">${data['parent_title']}</a></span>
<span><i class="fa fa-chevron-right"></i></span>
<span><a href="#">${data['title']}</a></span>
% elif data['type'] == 'track':
<span class="hidden-xs hidden-sm">Music</span>
<span class="hidden-xs hidden-sm"><i class="fa fa-chevron-right"></i></span>
<span class="hidden-xs hidden-sm"><a href="info?item_id=${data['grandparent_rating_key']}">${data['grandparent_title']}</a></span>
<span class="hidden-xs hidden-sm"><i class="fa fa-chevron-right"></i></span>
<span><a href="info?item_id=${data['parent_rating_key']}">${data['parent_title']}</a></span>
<span><i class="fa fa-chevron-right"></i></span>
<span><a href="#">Track ${data['index']} - ${data['title']}</a></span>
% endif
</div>
</div>
@@ -81,16 +99,34 @@ DOCUMENTATION :: END
<div class="summary-content-title-wrapper">
<div class="col-md-9">
<div class="summary-content-poster hidden-xs hidden-sm">
% if data['type'] == 'episode':
<div class="summary-poster-face-episode" style="background-image: url(pms_image_proxy?img=${data['thumb']}&width=500&height=280&fallback=poster);"></div>
% elif data['type'] == 'season':
<div class="summary-poster-face" style="background-image: url(pms_image_proxy?img=${data['thumb']}&width=300&height=450&fallback=poster);"></div>
% if data['type'] == 'track':
<a href="http://app.plex.tv/web/app#!/server/${config['pms_identifier']}/details/%2Flibrary%2Fmetadata%2F${data['parent_rating_key']}" target="Plex/Web" title="View in Plex/Web">
% else:
<div class="summary-poster-face" style="background-image: url(pms_image_proxy?img=${data['thumb']}&width=300&height=450&fallback=poster);"></div>
<a href="http://app.plex.tv/web/app#!/server/${config['pms_identifier']}/details/%2Flibrary%2Fmetadata%2F${data['rating_key']}" target="Plex/Web" title="View in Plex/Web">
% endif
% if data['type'] == 'episode':
<div class="summary-poster-face-episode" style="background-image: url(pms_image_proxy?img=${data['thumb']}&width=500&height=280&fallback=poster);">
<div class="summary-poster-face-overlay">
<span></span>
</div>
</div>
% elif data['type'] == 'artist' or data['type'] == 'album' or data['type'] == 'track':
<div class="summary-poster-face-track" style="background-image: url(pms_image_proxy?img=${data['thumb']}&width=500&height=500&fallback=poster);">
<div class="summary-poster-face-overlay">
<span></span>
</div>
</div>
% else:
<div class="summary-poster-face" style="background-image: url(pms_image_proxy?img=${data['thumb']}&width=300&height=450&fallback=poster);">
<div class="summary-poster-face-overlay">
<span></span>
</div>
</div>
% endif
</a>
</div>
<div class="summary-content-title">
% if data['type'] == 'movie' or data['type'] == 'show':
% if data['type'] == 'movie' or data['type'] == 'show' or data['type'] == 'artist':
<h1>&nbsp;</h1><h1>${data['title']}</h1>
% elif data['type'] == 'season':
<h1>&nbsp;</h1><h1><a href="info?item_id=${data['parent_rating_key']}">${data['parent_title']}</a></h1>
@@ -99,6 +135,13 @@ DOCUMENTATION :: END
<h1><a href="info?item_id=${data['grandparent_rating_key']}">${data['grandparent_title']}</a></h1>
<h2>${data['title']}</h2>
<h3 class="hidden-xs">S${data['parent_index']} &middot; E${data['index']}</h3>
% elif data['type'] == 'album':
<h1><a href="info?item_id=${data['parent_rating_key']}">${data['parent_title']}</a></h1>
<h2>${data['title']}</h2>
% elif data['type'] == 'track':
<h1><a href="info?item_id=${data['grandparent_rating_key']}">${data['grandparent_title']}</a></h1>
<h2><a href="info?item_id=${data['parent_rating_key']}">${data['parent_title']}</a> - ${data['title']}</h2>
<h3 class="hidden-xs">T${data['index']}</h3>
% endif
</div>
</div>
@@ -107,43 +150,56 @@ DOCUMENTATION :: END
<div class="col-md-9">
% if data['type'] == 'movie' or data['type'] == 'show' or data['type'] == 'season':
<div class="summary-content-padding hidden-xs hidden-sm" style="height: 275px;"></div>
% elif data['type'] == 'episode':
<div class="summary-content-padding hidden-xs hidden-sm" style="height: 40px;"></div>
% elif data['type'] == 'artist' or data['type'] == 'album' or data['type'] == 'track':
<div class="summary-content-padding hidden-xs hidden-sm" style="height: 150px;"></div>
% else:
<div class="summary-content-padding hidden-xs hidden-sm"></div>
% endif
<div class="summary-content">
<div class="summary-content-details-wrapper">
% if (data['type'] == 'movie' or data['type'] == 'show' or data['type'] == 'episode') and data['rating']:
% if data['rating']:
<div id="stars" class="rateit hidden-xs hidden-sm" data-rateit-value=""
data-rateit-ispreset="true" data-rateit-readonly="true"></div>
% endif
<div class="summary-content-director">
% if (data['type'] == 'episode' or data['type'] == 'movie') and data['directors']:
<div class="summary-content-details-tag">
% if data['directors']:
Directed by <strong> ${data['directors'][0]}</strong>
% endif
</div>
<div class="summary-content-studio">
% if (data['type'] == 'show' or data['type'] == 'movie') and data['studio']:
<div class="summary-content-details-tag">
% if data['studio']:
Studio <strong> ${data['studio']}</strong>
% endif
</div>
<div class="summary-content-airdate">
<div class="summary-content-details-tag">
% if data['type'] == 'movie':
Year <strong> ${data['year']}</strong>
% elif data['type'] == 'show':
Aired <strong> ${data['year']}</strong>
% elif data['type'] == 'episode':
Aired <strong> <span id="airdate">${data['originally_available_at']}</span></strong>
% elif data['type'] == 'album' or data['type'] == 'track':
Released <strong> ${data['year']}</strong>
% endif
</div>
<div class="summary-content-duration">
<div class="summary-content-details-tag">
% if data['duration']:
Runtime <strong> <span id="runtime">${data['duration']}</span> mins</strong>
% endif
</div>
<div class="summary-content-content-rating">
% if (data['type'] == 'episode' or data['type'] == 'movie' or data['type'] == 'show') and data['content_rating']:
<div class="summary-content-details-tag">
% if data['content_rating']:
Rated <strong> ${data['content_rating']} </strong>
% endif
</div>
</div>
% if data['tagline']:
<div class="summary-content-summary">
<p><strong> ${data['tagline']} </strong></p>
</div>
% endif
<div class="summary-content-summary">
<p> ${data['summary']} </p>
</div>
@@ -151,7 +207,7 @@ DOCUMENTATION :: END
</div>
<div class="col-md-3">
<div class="summary-content-people-wrapper hidden-xs hidden-sm">
% if (data['type'] == 'episode' or data['type'] == 'movie') and data['writers']:
% if data['writers']:
<div class="summary-content-writers">
<strong>Written by</strong>
<ul>
@@ -165,7 +221,7 @@ DOCUMENTATION :: END
</ul>
</div>
% endif
% if (data['type'] == 'movie' or data['type'] == 'show') and data['actors']:
% if data['actors']:
<div class="summary-content-actors">
<strong>Starring</strong>
<ul>
@@ -181,7 +237,7 @@ DOCUMENTATION :: END
% endif
</div>
<div class="summary-content-people-wrapper hidden-xs hidden-sm">
% if (data['type'] == 'movie' or data['type'] == 'show') and data['genres']:
% if data['genres']:
<div class="summary-content-genres">
<strong>Genres</strong>
<ul>
@@ -205,7 +261,7 @@ DOCUMENTATION :: END
</div>
</div>
<div class='table-card-back'>
<div id="season-list"></div>
<div id="children-list"></div>
</div>
</div>
% elif data['type'] == 'season':
@@ -216,11 +272,32 @@ DOCUMENTATION :: END
</div>
</div>
<div class='table-card-back'>
<div id="episode-list"></div>
<div id="children-list"></div>
</div>
</div>
% elif data['type'] == 'artist':
<div class='col-md-12'>
<div class='table-card-header'>
<div class="header-bar">
<span>Album List for <strong>${data['title']}</strong></span>
</div>
</div>
<div class='table-card-back'>
<div id="children-list"></div>
</div>
</div>
% elif data['type'] == 'album':
<div class='col-md-12'>
<div class='table-card-header'>
<div class="header-bar">
<span>Track List for <strong>${data['title']}</strong></span>
</div>
</div>
<div class='table-card-back'>
<div id="children-list"></div>
</div>
</div>
% endif
% if data['type'] == 'movie' or data['type'] == 'episode' or data['type'] == 'show' or data['type'] == 'season':
<div class='col-md-12'>
<div class='table-card-header'>
<div class="header-bar">
@@ -258,8 +335,25 @@ DOCUMENTATION :: END
</div>
<div class="modal fade" id="ip-info-modal" tabindex="-1" role="dialog" aria-labelledby="ip-info-modal">
</div>
<div class="modal fade" id="confirm-modal" tabindex="-1" role="dialog" aria-labelledby="confirm-modal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true"><i class="fa fa-remove"></i></button>
<h4 class="modal-title" id="myModalLabel">Confirm Delete</h4>
</div>
<div class="modal-body" style="text-align: center;">
<p>Are you REALLY sure you want to delete <strong><span id="deleteCount"></span></strong> history item(s)?</p>
<p>This is permanent and cannot be undone!</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-dark" data-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-danger btn-ok" data-dismiss="modal" id="confirm-delete">Delete</button>
</div>
</div>
</div>
</div>
</div>
% endif
</div>
</div>
</div>
@@ -290,46 +384,14 @@ DOCUMENTATION :: END
% if data['type'] == 'movie' or data['type'] == 'show' or data['type'] == 'episode':
<script>
// Convert rating to 5 star rating type
var starRating = Math.round(${data['rating']} / 2)
$('#stars').attr('data-rateit-value', starRating)
var starRating = Math.round(${data['rating']} / 2);
$('#stars').attr('data-rateit-value', starRating);
</script>
% endif
% if data['type'] == 'movie' or data['type'] == 'episode':
<script src="interfaces/default/js/tables/history_table.js"></script>
% if data['type'] == 'show' or data['type'] == 'artist':
<script>
$(document).ready(function () {
history_table_options.ajax = {
"url": "get_history",
type: 'post',
data: function ( d ) {
return { 'json_data': JSON.stringify( d ),
'rating_key': ${data['rating_key']} };
}
}
history_table = $('#history_table').DataTable(history_table_options);
var colvis = new $.fn.dataTable.ColVis(history_table, { buttonText: '<i class="fa fa-columns"></i> 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');
});
}
});
});
</script>
% elif data['type'] == 'show':
<script src="interfaces/default/js/tables/history_table.js"></script>
<script>
$(document).ready(function () {
function get_history() {
history_table_options.ajax = {
"url": "get_history",
type: 'post',
@@ -338,63 +400,11 @@ DOCUMENTATION :: END
'grandparent_rating_key': ${data['rating_key']} };
}
}
history_table = $('#history_table').DataTable(history_table_options);
var colvis = new $.fn.dataTable.ColVis(history_table, { buttonText: '<i class="fa fa-columns"></i> Select columns', buttonClass: 'btn btn-dark', exclude: [0, 10] });
$(colvis.button()).appendTo('div.colvis-button-bar');
clearSearchButton('history_table', history_table);
$('#row-edit-mode').on('click', function() {
$('#row-edit-mode-alert').fadeIn(200);
if ($(this).hasClass('active')) {
if (history_to_delete.length > 0) {
$('#deleteCount').text(history_to_delete.length);
$('#confirm-modal').modal();
$('#confirm-modal').one('click', '#confirm-delete', function () {
for (var i = 0; i < history_to_delete.length; i++) {
$.ajax({
url: 'delete_history_rows',
data: { row_id: history_to_delete[i] },
async: true,
success: function (data) {
var msg = "History deleted";
showMsg(msg, false, true, 2000);
}
});
}
history_table.draw();
});
}
$('.delete-control').each(function () {
$(this).addClass('hidden');
$('#row-edit-mode-alert').fadeOut(200);
});
} else {
history_to_delete = [];
$('.delete-control').each(function() {
$(this).find('button.btn-danger').toggleClass('btn-warning').toggleClass('btn-danger');
$(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); }
});
}
</script>
% endif
% if data['type'] == 'season':
<script src="interfaces/default/js/tables/history_table.js"></script>
% elif data['type'] == 'season' or data['type'] == 'album':
<script>
$(document).ready(function () {
function get_history() {
history_table_options.ajax = {
"url": "get_history",
type: 'post',
@@ -403,6 +413,25 @@ DOCUMENTATION :: END
'parent_rating_key': ${data['rating_key']} };
}
}
}
</script>
% elif data['type'] == 'episode' or data['type'] == 'track' or data['type'] == 'movie':
<script>
function get_history() {
history_table_options.ajax = {
"url": "get_history",
type: 'post',
data: function ( d ) {
return { 'json_data': JSON.stringify( d ),
'rating_key': ${data['rating_key']} };
}
}
}
</script>
% endif
<script>
$(document).ready(function () {
get_history();
history_table = $('#history_table').DataTable(history_table_options);
var colvis = new $.fn.dataTable.ColVis(history_table, { buttonText: '<i class="fa fa-columns"></i> Select columns', buttonClass: 'btn btn-dark', exclude: [0, 10] });
$(colvis.button()).appendTo('div.colvis-button-bar');
@@ -446,23 +475,23 @@ DOCUMENTATION :: END
}
});
});
</script>
% if data['type'] == 'show' or data['type'] == 'season' or data['type'] == 'artist' or data['type'] == 'album':
<script>
$.ajax({
url: 'get_season_children',
url: 'get_item_children',
type: "GET",
async: true,
data: { rating_key : ${data['rating_key']} },
complete: function(xhr, status) {
$("#episode-list").html(xhr.responseText); }
$("#children-list").html(xhr.responseText); }
});
</script>
% endif
<script>
$("#airdate").html(moment($("#airdate").text()).format('MMM DD, YYYY'));
$("#runtime").html(millisecondsToMinutes($("#runtime").text(), true));
</script>
% endif
<script>
$('div.art-face').animate({ opacity: 0.2 }, { duration: 1000 });
</script>
% endif
</%def>

View File

@@ -0,0 +1,102 @@
<%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_children_list.html
Version: 0.1
Variable names: data [list]
data :: Usable parameters
== Global keys ==
children_type Returns the type of children in the array.
children_count Returns the number of episodes in the array.
children_list Returns an array of episodes.
data['children_list'] :: Usable paramaters
== Global keys ==
rating_key Returns the unique identifier for the media item.
index Returns the episode number.
title Returns the name of the episode.
thumb Returns the location of the item's thumbnail. Use with pms_image_proxy.
parent_thumb Returns the location of the item's parent thumbnail. Use with pms_image_proxy.
DOCUMENTATION :: END
</%doc>
% if data != None:
% if data['children_count'] > 0:
<div class="item-children-wrapper">
<ul class="item-children-instance list-unstyled">
% for child in data['children_list']:
% if child['rating_key']:
% if data['children_type'] == 'track':
<li class="item-children-list-item">
% else:
<li>
% endif
<a href="info?item_id=${child['rating_key']}">
%if data['children_type'] == 'season':
<div class="item-children-poster">
% if child['thumb']:
<div class="item-children-poster-face season-poster" style="background-image: url(pms_image_proxy?img=${child['thumb']}&width=300&height=450);">
% else:
<div class="item-children-poster-face season-poster" style="background-image: url(pms_image_proxy?img=${child['parent_thumb']}&width=300&height=450);">
% endif
<div class="item-children-card-overlay">
<div class="item-children-overlay-text">
Season ${child['index']}
</div>
</div>
</div>
</div>
% elif data['children_type'] == 'episode':
<div class="item-children-poster">
<div class="item-children-poster-face episode-poster" style="background-image: url(pms_image_proxy?img=${child['thumb']}&width=300&height=450);">
<div class="item-children-card-overlay">
<div class="item-children-overlay-text">
Episode ${child['index']}
</div>
</div>
</div>
</div>
<div class="item-children-instance-text-wrapper episode-item">
<h3>${child['title']}</h3>
</div>
% elif data['children_type'] == 'album':
<div class="item-children-poster">
<div class="item-children-poster-face album-poster" style="background-image: url(pms_image_proxy?img=${child['thumb']}&width=300&height=300);"></div>
</div>
<div class="item-children-instance-text-wrapper album-item">
<h3>${child['title']}</h3>
</div>
% elif data['children_type'] == 'track':
% if loop.index % 2 == 0:
<div class="item-children-list-item-even">
<span class="item-children-list-item-index">${child['index']}</span>
<span class="item-children-list-item-title">${child['title']}</span>
<span class="item-children-list-item-duration" id="item-children-list-item-duration-${loop.index + 1}">
<script>$('#item-children-list-item-duration-${loop.index + 1}').text(moment.utc(${child['duration']}).format("m:ss"));</script>
</span>
</div>
% else:
<div class="item-children-list-item-odd">
<span class="item-children-list-item-index">${child['index']}</span>
<span class="item-children-list-item-title">${child['title']}</span>
<span class="item-children-list-item-duration" id="item-children-list-item-duration-${loop.index + 1}">
<script>$('#item-children-list-item-duration-${loop.index + 1}').text(moment.utc(${child['duration']}).format("m:ss"));</script>
</span>
</div>
% endif
% endif
</a>
</li>
% endif
% endfor
</ul>
</div>
% endif
% endif

View File

@@ -1,53 +0,0 @@
<%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_episode_list.html
Version: 0.1
Variable names: data [list]
data :: Usable parameters
== Global keys ==
episode_count Returns the number of episodes in the array.
episode_list Returns an array of episodes.
data['episode_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 episode.
index Returns the episode number.
DOCUMENTATION :: END
</%doc>
% if data != None:
% if data['episode_count'] > 0:
<div class="season-episodes-wrapper">
<ul class="season-episodes-instance list-unstyled">
% for a in data['episode_list']:
<li>
<a href="info?item_id=${a['rating_key']}">
<div class="season-episodes-poster">
<div class="season-episodes-poster-face" style="background-image: url(pms_image_proxy?img=${a['thumb']}&width=500&height=280);">
<div class="season-episodes-card-overlay">
<div class="season-episodes-overlay-text">
Episode ${a['index']}
</div>
</div>
</div>
</div>
<div class="season-episodes-instance-text-wrapper">
<h3>${a['title']}</h3>
</div>
</a>
</li>
% endfor
</ul>
</div>
% endif
% endif

View File

@@ -1,55 +0,0 @@
<%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:
<div class="show-seasons-wrapper">
<ul class="show-seasons-instance list-unstyled">
% for a in data['season_list']:
% if a['rating_key']:
<li>
<a href="info?item_id=${a['rating_key']}">
<div class="show-seasons-poster">
% if a['thumb']:
<div class="poster-face" style="background-image: url(pms_image_proxy?img=${a['thumb']}&width=300&height=450);">
% else:
<div class="poster-face" style="background-image: url(pms_image_proxy?img=${a['parent_thumb']}&width=300&height=450);">
% endif
<div class="show-seasons-card-overlay">
<div class="show-seasons-overlay-text">
Season ${a['index']}
</div>
</div>
</div>
</div>
</a>
</li>
% endif
% endfor
</ul>
</div>
% endif
% endif

View File

@@ -35,7 +35,7 @@ var hc_plays_by_day_options = {
}
}
},
colors: ['#F9AA03', '#FFFFFF'],
colors: ['#F9AA03', '#FFFFFF', '#FF4747'],
xAxis: {
type: 'datetime',
labels: {

View File

@@ -29,7 +29,7 @@ var hc_plays_by_dayofweek_options = {
credits: {
enabled: false
},
colors: ['#F9AA03', '#FFFFFF'],
colors: ['#F9AA03', '#FFFFFF', '#FF4747'],
xAxis: {
categories: [{}],
labels: {
@@ -46,8 +46,26 @@ var hc_plays_by_dayofweek_options = {
style: {
color: '#aaa'
}
},
stackLabels: {
enabled: false,
style: {
color: '#fff'
}
}
},
plotOptions: {
column: {
stacking: 'normal',
borderWidth: '0',
dataLabels: {
enabled: false,
style: {
color: '#000'
}
}
}
},
tooltip: {
shared: true
},

View File

@@ -29,7 +29,7 @@ var hc_plays_by_hourofday_options = {
credits: {
enabled: false
},
colors: ['#F9AA03', '#FFFFFF'],
colors: ['#F9AA03', '#FFFFFF', '#FF4747'],
xAxis: {
categories: [{}],
labels: {
@@ -46,8 +46,26 @@ var hc_plays_by_hourofday_options = {
style: {
color: '#aaa'
}
},
stackLabels: {
enabled: false,
style: {
color: '#fff'
}
}
},
plotOptions: {
column: {
stacking: 'normal',
borderWidth: '0',
dataLabels: {
enabled: false,
style: {
color: '#000'
}
}
}
},
tooltip: {
shared: true
},

View File

@@ -23,7 +23,7 @@ var hc_plays_by_month_options = {
credits: {
enabled: false
},
colors: ['#F9AA03', '#FFFFFF'],
colors: ['#F9AA03', '#FFFFFF', '#FF4747'],
xAxis: {
labels: {
style: {

View File

@@ -29,7 +29,7 @@ var hc_plays_by_platform_options = {
credits: {
enabled: false
},
colors: ['#F9AA03', '#FFFFFF'],
colors: ['#F9AA03', '#FFFFFF', '#FF4747'],
xAxis: {
categories: [{}],
labels: {
@@ -46,8 +46,26 @@ var hc_plays_by_platform_options = {
style: {
color: '#aaa'
}
},
stackLabels: {
enabled: false,
style: {
color: '#fff'
}
}
},
plotOptions: {
column: {
stacking: 'normal',
borderWidth: '0',
dataLabels: {
enabled: false,
style: {
color: '#000'
}
}
}
},
tooltip: {
shared: true
},

View File

@@ -29,7 +29,7 @@ var hc_plays_by_source_resolution_options = {
credits: {
enabled: false
},
colors: ['#F9AA03', '#FFFFFF'],
colors: ['#F9AA03', '#FFFFFF', '#FF4747'],
xAxis: {
categories: [{}],
labels: {
@@ -46,8 +46,26 @@ var hc_plays_by_source_resolution_options = {
style: {
color: '#aaa'
}
},
stackLabels: {
enabled: false,
style: {
color: '#fff'
}
}
},
plotOptions: {
column: {
stacking: 'normal',
borderWidth: '0',
dataLabels: {
enabled: false,
style: {
color: '#000'
}
}
}
},
tooltip: {
shared: true
},

View File

@@ -29,7 +29,7 @@ var hc_plays_by_stream_resolution_options = {
credits: {
enabled: false
},
colors: ['#F9AA03', '#FFFFFF'],
colors: ['#F9AA03', '#FFFFFF', '#FF4747'],
xAxis: {
categories: [{}],
labels: {
@@ -46,8 +46,26 @@ var hc_plays_by_stream_resolution_options = {
style: {
color: '#aaa'
}
},
stackLabels: {
enabled: false,
style: {
color: '#fff'
}
}
},
plotOptions: {
column: {
stacking: 'normal',
borderWidth: '0',
dataLabels: {
enabled: false,
style: {
color: '#000'
}
}
}
},
tooltip: {
shared: true
},

View File

@@ -29,7 +29,7 @@ var hc_plays_by_user_options = {
credits: {
enabled: false
},
colors: ['#F9AA03', '#FFFFFF'],
colors: ['#F9AA03', '#FFFFFF', '#FF4747'],
xAxis: {
categories: [{}],
labels: {
@@ -46,8 +46,26 @@ var hc_plays_by_user_options = {
style: {
color: '#aaa'
}
},
stackLabels: {
enabled: false,
style: {
color: '#fff'
}
}
},
plotOptions: {
column: {
stacking: 'normal',
borderWidth: '0',
dataLabels: {
enabled: false,
style: {
color: '#000'
}
}
}
},
tooltip: {
shared: true
},

View File

@@ -219,7 +219,11 @@ function getPlatformImagePath(platformName) {
return 'interfaces/default/images/platforms/playstation.png';
} else if (platformName.indexOf("Mystery 5") > -1) {
return 'interfaces/default/images/platforms/xbox.png';
} else {
} else if (platformName.indexOf("Windows") > -1) {
return 'interfaces/default/images/platforms/win8.png';
} else if (platformName.indexOf("Windows phone") > -1) {
return 'interfaces/default/images/platforms/wp.png';
} else {
return 'interfaces/default/images/platforms/default.png';
}
}

View File

@@ -125,12 +125,12 @@ history_table_options = {
} else if (rowData['media_type'] === 'episode') {
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Episode"><i class="fa fa-television fa-fw"></i></span>';
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=450&fallback=poster" data-height="120">' + cellData + ' \
(S' + ('00' + rowData['parent_media_index']).slice(-2) + 'E' + ('00' + rowData['media_index']).slice(-2) + ')</span>'
(S' + rowData['parent_media_index'] + '&middot; E' + rowData['media_index'] + ')</span>'
$(td).html('<div class="history-title"><a href="info?source=history&item_id=' + rowData['id'] + '"><div style="float: left;" >' + media_type + '&nbsp' + thumb_popover + '</div></a></div>');
} else if (rowData['media_type'] === 'track') {
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Track"><i class="fa fa-music fa-fw"></i></span>';
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=300&fallback=poster" data-height="80">' + cellData + ' (' + rowData['parent_title'] + ')</span>'
$(td).html('<div class="history-title"><div style="float: left;">' + media_type + '&nbsp' + thumb_popover + '</div></div>');
$(td).html('<div class="history-title"><a href="info?source=history&item_id=' + rowData['id'] + '"><div style="float: left;">' + media_type + '&nbsp' + thumb_popover + '</div></a></div>');
} else {
$(td).html('<a href="info?item_id=' + rowData['id'] + '">' + cellData + '</a>');
}

View File

@@ -103,12 +103,12 @@ history_table_modal_options = {
} else if (rowData['media_type'] === 'episode') {
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Episode"><i class="fa fa-television fa-fw"></i></span>';
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=450&fallback=poster" data-height="120">' + cellData + ' \
(S' + ('00' + rowData['parent_media_index']).slice(-2) + 'E' + ('00' + rowData['media_index']).slice(-2) + ')</span>'
(S' + rowData['parent_media_index'] + '&middot; E' + rowData['media_index'] + ')</span>'
$(td).html('<div class="history-title"><a href="info?source=history&item_id=' + rowData['id'] + '"><div style="float: left;" >' + media_type + '&nbsp' + thumb_popover + '</div></a></div>');
} else if (rowData['media_type'] === 'track') {
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Track"><i class="fa fa-music fa-fw"></i></span>';
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=300&fallback=poster" data-height="80">' + cellData + ' (' + rowData['parent_title'] + ')</span>'
$(td).html('<div class="history-title"><div style="float: left;">' + media_type + '&nbsp' + thumb_popover + '</div></div>');
$(td).html('<div class="history-title"><a href="info?source=history&item_id=' + rowData['id'] + '"><div style="float: left;">' + media_type + '&nbsp' + thumb_popover + '</div></a></div>');
} else {
$(td).html('<a href="info?item_id=' + rowData['id'] + '">' + cellData + '</a>');
}

View File

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

View File

@@ -86,7 +86,7 @@ user_ip_table_options = {
} else if (rowData['media_type'] === 'track') {
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Track"><i class="fa fa-music fa-fw"></i></span>';
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=80&height=80&fallback=poster" data-height="80">' + cellData + '</span>'
$(td).html('<div class="history-title"><div style="float: left;">' + media_type + '&nbsp' + thumb_popover + '</div></div>');
$(td).html('<div class="history-title"><a href="info?source=history&item_id=' + rowData['id'] + '"><div style="float: left;">' + media_type + '&nbsp' + thumb_popover + '</div></a></div>');
} else if (rowData['media_type']) {
$(td).html('<a href="info?item_id=' + rowData['id'] + '">' + cellData + '</a>');
} else {

View File

@@ -141,7 +141,7 @@ users_list_table_options = {
} else if (rowData['media_type'] === 'track') {
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Track"><i class="fa fa-music fa-fw"></i></span>';
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=80&height=80&fallback=poster" data-height="80">' + cellData + '</span>'
$(td).html('<div class="history-title"><div style="float: left;">' + media_type + '&nbsp' + thumb_popover + '</div></div>');
$(td).html('<div class="history-title"><a href="info?source=history&item_id=' + rowData['id'] + '"><div style="float: left;">' + media_type + '&nbsp' + thumb_popover + '</div></a></div>');
} else if (rowData['media_type']) {
$(td).html('<a href="info?item_id=' + rowData['id'] + '">' + cellData + '</a>');
} else {

View File

@@ -38,21 +38,21 @@ DOCUMENTATION :: END
<div class="home-platforms-instance-info">
<div class="home-platforms-instance-name">
<h4>${library['rows']['title']}</h4>
<h5>${library['rows']['count_type']}</h5>
</div>
<div class="home-platforms-instance-playcount">
<h5>${library['rows']['count_type']}</h5>
<h3>${library['rows']['count']}</h3>
<p> items</p>
</div>
% if library['type'] == 'show':
<div class="home-platforms-instance-name2">
<div class="home-platforms-instance-playcount" style="padding-left: 10px;">
<h5>${library['rows']['episode_count_type']}</h5>
<h3>${library['rows']['episode_count']}</h3>
<p> items</p>
</div>
% endif
% if library['type'] == 'artist':
<div class="home-platforms-instance-name2">
<div class="home-platforms-instance-playcount" style="padding-left: 10px;">
<h5>${library['rows']['album_count_type']}</h5>
<h3>${library['rows']['album_count']}</h3>
<p> items</p>
@@ -73,6 +73,6 @@ DOCUMENTATION :: END
% endfor
</ul>
% else:
<div class="text-muted">Unable to retrieve data from database. Please check your <a href="settings">settings</a>.
<div class="text-muted">Unable to retrieve data from server. Please check your <a href="settings">settings</a>.
</div><br>
% endif

View File

@@ -1,3 +1,6 @@
<%!
from plexpy import helpers
%>
% if data:
<div class="modal-dialog" role="document">
<div class="modal-content">
@@ -9,9 +12,9 @@
<div class="container-fluid">
<div class="row">
<form action="set_notification_config" method="post" class="form" id="set_notification_config" data-parsley-validate>
<div class="col-md-6">
<div class="col-md-8">
% for item in data:
% if item['input_type'] != 'checkbox':
% if item['input_type'] == 'text' or item['input_type'] == 'number' or item['input_type'] == 'password':
<div class="form-group">
<label for="${item['name']}">${item['label']}</label>
<input type="${item['input_type']}" class="form-control" id="${item['name']}" name="${item['name']}" value="${item['value']}" size="30">
@@ -20,12 +23,18 @@
% endif
<p class="help-block">${item['description']}</p>
</div>
% elif item['input_type'] == 'button':
<div class="form-group">
<input type="${item['input_type']}" class="btn btn-bright" id="${item['name']}" name="${item['name']}" value="${item['value']}">
</div>
<p class="help-block">${item['description']}</p>
% elif item['input_type'] == 'checkbox':
<div class="checkbox">
<label>
<input type="checkbox" id="${item['name']}" name="${item['name']}" value="1" ${item['value']}> ${item['label']}
<input type="checkbox" data-id="${item['name']}" class="checkboxes" value="1" ${helpers.checked(item['value'])}> ${item['label']}
</label>
<p class="help-block">${item['description']}</p>
<input type="hidden" id="${item['name']}" name="${item['name']}" value="${item['value']}">
</div>
% endif
% endfor
@@ -35,7 +44,14 @@
</div>
</div>
<div class="modal-footer">
<input type="button" id="save-notification-item" class="btn btn-bright" value="Save">
<%
nosave = any(d['input_type'] == 'nosave' for d in data)
%>
% if not nosave:
<input type="button" id="save-notification-item" class="btn btn-bright" value="Save">
% else:
<input type="button" class="btn btn-bright" data-dismiss="modal" value="Close">
% endif
</div>
</div>
</div>
@@ -53,4 +69,30 @@
doAjaxCall('set_notification_config',$(this),'tabs',true);
return false;
});
$('#twitterStep1').click(function () {
$.get("/twitterStep1", function (data) {window.open(data); })
.done(function () { $('#ajaxMsg').html("<div class='msg'><span class='ui-icon ui-icon-check'></span>Confirm Authorization. Check pop-up blocker if no response.</div>"); });
$('#ajaxMsg').addClass('success').fadeIn().delay(3000).fadeOut();
});
$('#twitterStep2').click(function () {
var twitter_key = $("#twitter_key").val();
$.get("/twitterStep2", {'key': twitter_key}, function (data) { $('#ajaxMsg').html("<div class='msg'><span class='ui-icon ui-icon-check'></span>"+data+"</div>"); });
$('#ajaxMsg').addClass('success').fadeIn().delay(3000).fadeOut();
});
$('#testTwitter').click(function () {
$.get("/testTwitter",
function (data) { $('#ajaxMsg').html("<div class='msg'><span class='ui-icon ui-icon-check'></span>"+data+"</div>"); });
$('#ajaxMsg').addClass('success').fadeIn().delay(3000).fadeOut();
});
// Never send checkbox values directly, always substitute value in hidden input.
$('.checkboxes').click(function() {
var configToggle = $(this).data('id');
if ($(this).is(":checked")) {
$("#"+configToggle).val(1);
} else {
$("#"+configToggle).val(0);
}
});
</script>

View File

@@ -31,35 +31,48 @@ DOCUMENTATION :: END
<li>
% if item['type'] == 'season' or item['type'] == 'movie':
<a href="info?item_id=${item['rating_key']}">
<div class="poster">
<div class="poster-face" style="background-image: url(pms_image_proxy?img=${item['thumb']}&width=300&height=450&fallback=poster);"></div>
<div class="dashboard-recent-media-poster">
<div class="dashboard-recent-media-poster-face" style="background-image: url(pms_image_proxy?img=${item['thumb']}&width=300&height=450&fallback=poster);">
<div class="dashboard-recent-media-overlay">
<div class="dashboard-recent-media-overlay-text" id="added_at-${item['rating_key']}">
<script>
$('#added_at-${item['rating_key']}').text('Added ' + moment(${item['added_at']}, "X").fromNow())
</script>
</div>
</div>
</div>
</div>
<div class="dashboard-recent-media-metacontainer">
% if item['type'] == 'season':
<h3>${item['parent_title']}</h3>
<h3>(${item['title']})</h3>
<h3 class="text-muted">${item['title']}</h3>
% elif item['type'] == 'movie':
<h3>${item['title']}</h3>
<h3>(${item['year']})</h3>
<h3 class="text-muted">${item['year']}</h3>
% endif
<div class="text-muted" id="added_at-${item['rating_key']}">${item['added_at']}</div>
</div>
</a>
% elif item['type'] == 'album':
<div class="poster">
<div class="cover-face" style="background-image: url(pms_image_proxy?img=${item['thumb']}&width=300&height=300&fallback=cover);"></div>
</div>
<div class="dashboard-recent-media-metacontainer">
<h3>${item['parent_title']}</h3>
<h3>${item['title']}</h3>
<div class="text-muted" id="added_at-${item['rating_key']}">${item['added_at']}</div>
</div>
<a href="info?item_id=${item['rating_key']}">
<div class="dashboard-recent-media-cover">
<div class="dashboard-recent-media-cover-face" style="background-image: url(pms_image_proxy?img=${item['thumb']}&width=300&height=300&fallback=cover);">
<div class="dashboard-recent-media-overlay">
<div class="dashboard-recent-media-overlay-text" id="added_at-${item['rating_key']}">
<script>
$('#added_at-${item['rating_key']}').text('Added ' + moment(${item['added_at']}, "X").fromNow())
</script>
</div>
</div>
</div>
</div>
<div class="dashboard-recent-media-metacontainer">
<h3>${item['parent_title']}</h3>
<h3 class="text-muted">${item['title']}</h3>
</div>
</a>
% endif
</li>
</div>
<script>
$('#added_at-${item['rating_key']}').html('Added ' + moment(${item['added_at']}, "X").fromNow())
</script>
% endfor
</ul>
</div>

View File

@@ -34,14 +34,15 @@ available_notification_agents = notifiers.available_notification_agents()
<div class="col-md-4">
<ul class="nav-settings list-unstyled" role="tablist">
<li role="presentation" class="active"><a href="#tabs-1" aria-controls="tabs-1" role="tab" data-toggle="tab">General</a></li>
<li role="presentation"><a href="#tabs-2" aria-controls="tabs-2" role="tab" data-toggle="tab">Web Interface</a></li>
<li role="presentation"><a href="#tabs-3" aria-controls="tabs-3" role="tab" data-toggle="tab">Access Control</a></li>
<li role="presentation"><a href="#tabs-4" aria-controls="tabs-4" role="tab" data-toggle="tab">Plex Media Server</a></li>
<li role="presentation"><a href="#tabs-5" aria-controls="tabs-5" role="tab" data-toggle="tab">Plex.tv Account</a></li>
<li role="presentation"><a href="#tabs-6" aria-controls="tabs-6" role="tab" data-toggle="tab">Extra Settings</a></li>
<li role="presentation"><a href="#tabs-7" aria-controls="tabs-7" role="tab" data-toggle="tab">Monitoring</a></li>
<li role="presentation"><a href="#tabs-8" aria-controls="tabs-8" role="tab" data-toggle="tab">Notifications</a></li>
<li role="presentation"><a href="#tabs-9" aria-controls="tabs-9" role="tab" data-toggle="tab">Notification Agents</a></li>
<li role="presentation"><a href="#tabs-2" aria-controls="tabs-2" role="tab" data-toggle="tab">Homepage Statistics</a></li>
<li role="presentation"><a href="#tabs-3" aria-controls="tabs-3" role="tab" data-toggle="tab">Web Interface</a></li>
<li role="presentation"><a href="#tabs-4" aria-controls="tabs-4" role="tab" data-toggle="tab">Access Control</a></li>
<li role="presentation"><a href="#tabs-5" aria-controls="tabs-5" role="tab" data-toggle="tab">Plex Media Server</a></li>
<li role="presentation"><a href="#tabs-6" aria-controls="tabs-6" role="tab" data-toggle="tab">Plex.tv Account</a></li>
<li role="presentation"><a href="#tabs-7" aria-controls="tabs-7" role="tab" data-toggle="tab">Extra Settings</a></li>
<li role="presentation"><a href="#tabs-8" aria-controls="tabs-8" role="tab" data-toggle="tab">Monitoring</a></li>
<li role="presentation"><a href="#tabs-9" aria-controls="tabs-9" role="tab" data-toggle="tab">Notifications</a></li>
<li role="presentation"><a href="#tabs-10" aria-controls="tabs-10" role="tab" data-toggle="tab">Notification Agents</a></li>
</ul>
</div>
<div class="col-md-8">
@@ -83,10 +84,33 @@ available_notification_agents = notifiers.available_notification_agents()
</div>
<p class="help-block">Set your preferred time format. <a href="javascript:void(0)" data-target="#dateTimeOptionsModal" data-toggle="modal">Click here</a> to see the parameter list.</p>
</div>
<p><input type="button" class="btn btn-bright save-button" value="Save" data-success="Changes saved successfully"></p>
</div>
<div role="tabpanel" class="tab-pane" id="tabs-2">
<div class="padded-header">
<h3>Homepage Statistics</h3>
<h3>Watch Statistics</h3>
</div>
<div class="form-group">
<label for="home_stats_cards">Cards</label>
<div class="row">
<div class="col-md-6">
<select multiple class="form-control" id="home_stats_cards" name="home_stats_cards" data-parsley-trigger="change">
<option id="card-watch_statistics" value="watch_statistics" class="hidden" selected>Watch Statistics</option>
<option id="card-top_tv" value="top_tv">Most Watched TV</option>
<option id="card-popular_tv" value="popular_tv">Most Popular TV</option>
<option id="card-top_movies" value="top_movies">Most Watched Movie</option>
<option id="card-popular_movies" value="popular_movies">Most Popular Movie</option>
<option id="card-top_music" value="top_music">Most Listened Music</option>
<option id="card-popular_music" value="popular_music">Most Popular Music</option>
<option id="card-top_users" value="top_users">Most Active User</option>
<option id="card-top_platforms" value="top_platforms">Most Active Platform</option>
<option id="card-last_watched" value="last_watched">Last Watched</option>
</select>
</div>
</div>
<p class="help-block">Select the cards to show in the watch statistics on the home page. Select none to disable.</p>
</div>
<div class="form-group">
<label for="home_stats_length">Time Frame</label>
<div class="row">
@@ -95,7 +119,7 @@ available_notification_agents = notifiers.available_notification_agents()
</div>
<div id="home_stats_length_error" class="alert alert-danger settings-alert" role="alert"></div>
</div>
<p class="help-block">Specify the number of days for the statistics on the home page. Default is 30 days.</p>
<p class="help-block">Specify the number of days for the watch statistics on the home page. Default is 30 days.</p>
</div>
<div class="form-group">
<label for="home_stats_count">Top Lists</label>
@@ -105,7 +129,7 @@ available_notification_agents = notifiers.available_notification_agents()
</div>
<div id="home_stats_count_error" class="alert alert-danger settings-alert" role="alert"></div>
</div>
<p class="help-block">Specify the number of items to show in the top lists for the statistics on the home page. Max is 10 items, default is 5 items, 0 to disable.</p>
<p class="help-block">Specify the number of items to show in the top lists for the watch statistics on the home page. Max is 10 items, default is 5 items, 0 to disable.</p>
</div>
<div class="checkbox">
<label>
@@ -113,9 +137,26 @@ available_notification_agents = notifiers.available_notification_agents()
</label>
<p class="help-block">Use play duration instead of play count to generate statistics.</p>
</div>
<div class="padded-header">
<h3>Library Statistics</h3>
</div>
<div class="form-group">
<label for="home_library_cards">Cards</label>
<div class="row">
<div class="col-md-6">
<select multiple class="form-control" id="home_library_cards" name="home_library_cards" data-parsley-trigger="change">
<option id="card-library_statistics" value="library_statistics" class="hidden" selected>Library Statistics</option>
</select>
</div>
</div>
<p class="help-block">Select the cards to show in the library statistics on the home page. Select none to disable.</p>
</div>
<p><input type="button" class="btn btn-bright save-button" value="Save" data-success="Changes saved successfully"></p>
</div>
<div role="tabpanel" class="tab-pane" id="tabs-2">
<div role="tabpanel" class="tab-pane" id="tabs-3">
<div class="padded-header">
<h3>Web Interface</h3>
</div>
@@ -164,7 +205,7 @@ available_notification_agents = notifiers.available_notification_agents()
<p><input type="button" class="btn btn-bright save-button" value="Save" data-success="Changes saved successfully"></p>
</div>
<div role="tabpanel" class="tab-pane" id="tabs-3">
<div role="tabpanel" class="tab-pane" id="tabs-4">
<div class="padded-header">
<h3>Authentication</h3>
@@ -216,7 +257,7 @@ available_notification_agents = notifiers.available_notification_agents()
<p><input type="button" class="btn btn-bright save-button" value="Save" data-success="Changes saved successfully"></p>
</div>
<div role="tabpanel" class="tab-pane" id="tabs-4">
<div role="tabpanel" class="tab-pane" id="tabs-5">
<div class="padded-header">
<h3>Plex Media Server</h3>
@@ -272,7 +313,7 @@ available_notification_agents = notifiers.available_notification_agents()
<input type="button" class="btn btn-bright save-button" value="Save" data-success="Changes saved successfully">
</div>
<div role="tabpanel" class="tab-pane" id="tabs-5">
<div role="tabpanel" class="tab-pane" id="tabs-6">
<div class="padded-header">
<h3>Plex.tv Authentication</h3>
@@ -282,12 +323,13 @@ available_notification_agents = notifiers.available_notification_agents()
<div class="row">
<div class="col-md-6">
<div class="input-group">
<input type="text" class="form-control" id="pms_token" name="pms_token" value="${config['pms_token']}" data-parsley-trigger="change" required>
<input type="text" class="form-control" id="pms_token" name="pms_token" value="${config['pms_token']}" data-parsley-trigger="change" data-parsley-errors-container="#pms_token_error" required>
<span class="input-group-btn">
<button class="btn btn-form" type="button" data-toggle="modal" data-target="#pms-auth-modal">Fetch Token</button>
</span>
</div>
</div>
<div id="pms_token_error" class="alert alert-danger settings-alert" role="alert"></div>
</div>
<p class="help-block">Token for Plex.tv authentication.</p>
</div>
@@ -314,14 +356,14 @@ available_notification_agents = notifiers.available_notification_agents()
<p><input type="button" class="btn btn-bright save-button" value="Save" data-success="Changes saved successfully"></p>
</div>
<div role="tabpanel" class="tab-pane" id="tabs-6">
<div role="tabpanel" class="tab-pane" id="tabs-7">
<div class="padded-header">
<h3>Extra Settings</h3>
</div>
<div class="checkbox">
<label>
<input type="checkbox" id="pms_use_bif" name="pms_use_bif" value="1" ${config['pms_use_bif']}> Use BIF thumbs
<input type="checkbox" id="pms_use_bif" name="pms_use_bif" value="1" ${config['pms_use_bif']}> Use video preview thumbnails (BIF)
</label>
<p class="help-block">If you have media indexing enabled on your server, use these on the activity pane.</p>
</div>
@@ -333,7 +375,7 @@ available_notification_agents = notifiers.available_notification_agents()
<p><input type="button" class="btn btn-bright save-button" value="Save" data-success="Changes saved successfully"></p>
</div>
<div role="tabpanel" class="tab-pane" id="tabs-7">
<div role="tabpanel" class="tab-pane" id="tabs-8">
<div class="padded-header">
<h3>Monitoring Settings</h3>
@@ -366,7 +408,7 @@ available_notification_agents = notifiers.available_notification_agents()
</div>
<div id="logging_ignore_interval_error" class="alert alert-danger settings-alert" role="alert"></div>
</div>
<p class="help-block">The interval (in seconds) PlexPy will wait for a video item to be active before logging it. 0 to disable.</p>
<p class="help-block">The interval (in seconds) an item must be in a playing state before logging it. 0 to disable.</p>
</div>
<div class="checkbox">
<label>
@@ -415,7 +457,7 @@ available_notification_agents = notifiers.available_notification_agents()
<p><input type="button" class="btn btn-bright save-button" value="Save" data-success="Changes saved successfully"></p>
</div>
<div role="tabpanel" class="tab-pane" id="tabs-8">
<div role="tabpanel" class="tab-pane" id="tabs-9">
<div class="padded-header">
<h3>Global Notification Toggles</h3>
@@ -565,7 +607,7 @@ available_notification_agents = notifiers.available_notification_agents()
<p><input type="button" class="btn btn-bright save-button" value="Save" data-success="Changes saved successfully"></p>
</div>
<div role="tabpanel" class="tab-pane" id="tabs-9">
<div role="tabpanel" class="tab-pane" id="tabs-10">
<div class="padded-header">
<h3>Notification Agents</h3>
@@ -1168,7 +1210,7 @@ $(document).ready(function() {
function checkLogsPath() {
if ($("#pms_logs_folder").val() == '') {
$("#debugLogCheck").html("You must first define your Plex Server Logs folder path under the Extra Settings tab.");
$("#debugLogCheck").html("You must first define your Plex Server Logs folder path under the Plex Media Server tab.");
$("#ip_logging_enable").attr("disabled", true);
} else {
$("#ip_logging_enable").attr("disabled", false);
@@ -1177,6 +1219,47 @@ $(document).ready(function() {
}
var accordion = new Accordion($('#accordion'), false);
var cards = "${config['home_stats_cards']}".split(/[\s,]+/);
cards.forEach(function (item) {
$('#card-'+item).prop('selected', !$(this).prop('selected'));
});
$('#home_stats_cards').on('mousedown', function(e) {
e.preventDefault();
var scroll = this.scrollTop;
e.target.selected = !e.target.selected;
this.scrollTop = scroll;
}).on('mousemove', function(e) {
e.preventDefault()
});
$.ajax({
url: 'get_server_children',
data: { },
async: true,
complete: function (xhr, status) {
server_children_info = $.parseJSON(xhr.responseText);
libraries_list = server_children_info.libraries_list;
for (var i in libraries_list) {
title = libraries_list[i].title;
key = libraries_list[i].key;
$('#home_library_cards').append('<option id="card-' + key + '" value="' + key + '">' + title + '</option>')
}
var cards = "${config['home_library_cards']}".split(/[\s,]+/);
cards.forEach(function (item) {
$('#card-'+item).prop('selected', !$(this).prop('selected'));
});
}
});
$('#home_library_cards').on('mousedown', function(e) {
e.preventDefault();
var scroll = this.scrollTop;
e.target.selected = !e.target.selected;
this.scrollTop = scroll;
}).on('mousemove', function(e) {
e.preventDefault()
});
});
</script>
</%def>

View File

@@ -32,29 +32,54 @@ DOCUMENTATION :: END
<div class="dashboard-recent-media-row">
<ul class="dashboard-recent-media list-unstyled">
% for item in data:
<div class="dashboard-recent-media-instance">
<li>
<a href="info?source=history&item_id=${item['row_id']}">
<div class="poster">
<div class="poster-face" style="background-image: url(pms_image_proxy?img=${item['thumb']}&width=300&height=450&fallback=poster);"></div>
<li>
% if item['type'] == 'episode' or item['type'] == 'movie':
<a href="info?source=history&item_id=${item['row_id']}">
<div class="dashboard-recent-media-poster">
<div class="dashboard-recent-media-poster-face" style="background-image: url(pms_image_proxy?img=${item['thumb']}&width=300&height=450&fallback=poster);">
<div class="dashboard-recent-media-overlay">
<div class="dashboard-recent-media-overlay-text" id="time-${item['time']}">
<script>
$('#time-${item['time']}').text('Watched ' + moment(${item['time']}, "X").fromNow())
</script>
</div>
</div>
</div>
<div class="dashboard-recent-media-metacontainer">
% if item['type'] == 'episode':
<h3>${item['parent_title']}</h3>
<h3>${item['title']}</h3>
<h3>(Season ${item['parent_index']}, Episode ${item['index']})</h3>
% elif item['type'] == 'movie':
<h3>${item['title']}</h3>
<h3>(${item['year']})</h3>
% endif
<div class="text-muted" id="time-${item['time']}">${item['time']}</div>
</div>
</a>
</li>
</div>
<script>
$('#time-${item['time']}').html('Watched ' + moment(${item['time']}, "X").fromNow())
</script>
</div>
<div class="dashboard-recent-media-metacontainer">
% if item['type'] == 'episode':
<h3>${item['grandparent_title']}</h3>
<h3>${item['title']}</h3>
<h3 class="text-muted">S${item['parent_index']} &middot; E${item['index']}</h3>
% elif item['type'] == 'movie':
<h3>${item['title']}</h3>
<h3 class="text-muted">${item['year']}</h3>
% endif
<div class="text-muted" id="time-${item['time']}">
</div>
</div>
</a>
% elif item['type'] == 'track':
<a href="info?source=history&item_id=${item['row_id']}">
<div class="dashboard-recent-media-cover">
<div class="dashboard-recent-media-cover-face" style="background-image: url(pms_image_proxy?img=${item['thumb']}&width=300&height=300&fallback=cover);">
<div class="dashboard-recent-media-overlay">
<div class="dashboard-recent-media-overlay-text" id="time-${item['time']}">
<script>
$('#time-${item['time']}').text('Watched ' + moment(${item['time']}, "X").fromNow())
</script>
</div>
</div>
</div>
</div>
<div class="dashboard-recent-media-metacontainer">
<h3>${item['grandparent_title']}</h3>
<h3>${item['title']}</h3>
<h3 class="text-muted">${item['parent_title']}</h3>
</div>
</a>
% endif
</li>
% endfor
</ul>
</div>

View File

@@ -16,7 +16,7 @@
<button class="btn btn-danger btn-edit" data-toggle="button" aria-pressed="false" autocomplete="off" id="row-edit-mode">
<i class="fa fa-pencil"></i> Edit mode
</button>&nbsp
<div class="alert alert-danger alert-edit" role="alert" id="row-edit-mode-alert"><i class="fa fa-exclamation-triangle"></i>&nbspSelect rows to delete. Data is deleted upon exiting delete mode.</div>
<div class="alert alert-danger alert-edit" role="alert" id="row-edit-mode-alert"><i class="fa fa-exclamation-triangle"></i>&nbspSelect users to purge. Data is purged upon exiting edit mode.</div>
</div>
</div>
<div class='table-card-back'>
@@ -119,6 +119,13 @@
$(this).addClass('hidden');
$('#row-edit-mode-alert').fadeOut(200);
});
$('.edit-user-control > .edit-user-name').each(function () {
a = $(this).children('a');
input = $(this).children('input');
a.text(input.val());
a.removeClass('hidden');
input.addClass('hidden');
});
} else {
users_to_purge = [];
@@ -126,6 +133,10 @@
$(this).find('button.btn-danger').toggleClass('btn-warning').toggleClass('btn-danger');
$(this).removeClass('hidden');
});
$('.edit-user-control > .edit-user-name').each(function () {
$(this).children('a').addClass('hidden');
$(this).children('input').removeClass('hidden');
});
}
});
});

View File

@@ -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
@@ -17,11 +17,16 @@ import os
import sys
import subprocess
import threading
import webbrowser
import sqlite3
import cherrypy
import datetime
import uuid
# Some cut down versions of Python may not include this module and it's not critical for us
try:
import webbrowser
no_browser = False
except ImportError:
no_browser = True
from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.triggers.interval import IntervalTrigger
@@ -228,18 +233,19 @@ def daemonize():
def launch_browser(host, port, root):
if host == '0.0.0.0':
host = 'localhost'
if not no_browser:
if host == '0.0.0.0':
host = 'localhost'
if CONFIG.ENABLE_HTTPS:
protocol = 'https'
else:
protocol = 'http'
if CONFIG.ENABLE_HTTPS:
protocol = 'https'
else:
protocol = 'http'
try:
webbrowser.open('%s://%s:%i%s' % (protocol, host, port, root))
except Exception as e:
logger.error('Could not launch browser: %s', e)
try:
webbrowser.open('%s://%s:%i%s' % (protocol, host, port, root))
except Exception as e:
logger.error('Could not launch browser: %s', e)
def initialize_scheduler():
@@ -377,7 +383,7 @@ def dbcheck():
'title TEXT, parent_title TEXT, grandparent_title TEXT, full_title TEXT, media_index INTEGER, '
'parent_media_index INTEGER, thumb TEXT, parent_thumb TEXT, grandparent_thumb TEXT, art TEXT, media_type TEXT, '
'year INTEGER, originally_available_at TEXT, added_at INTEGER, updated_at INTEGER, last_viewed_at INTEGER, '
'content_rating TEXT, summary TEXT, rating TEXT, duration INTEGER DEFAULT 0, guid TEXT, '
'content_rating TEXT, summary TEXT, tagline TEXT, rating TEXT, duration INTEGER DEFAULT 0, guid TEXT, '
'directors TEXT, writers TEXT, actors TEXT, genres TEXT, studio TEXT)'
''
)
@@ -517,15 +523,24 @@ def dbcheck():
'ALTER TABLE sessions ADD COLUMN transcode_height INTEGER'
)
# Upgrade sessions table from earlier versions
# Upgrade session_history_metadata table from earlier versions
try:
c_db.execute('SELECT full_title from session_history_metadata')
except sqlite3.OperationalError:
logger.debug(u"Altering database. Updating database table sessions.")
logger.debug(u"Altering database. Updating database table session_history_metadata.")
c_db.execute(
'ALTER TABLE session_history_metadata ADD COLUMN full_title TEXT'
)
# Upgrade session_history_metadata table from earlier versions
try:
c_db.execute('SELECT tagline from session_history_metadata')
except sqlite3.OperationalError:
logger.debug(u"Altering database. Updating database table session_history_metadata.")
c_db.execute(
'ALTER TABLE session_history_metadata ADD COLUMN tagline TEXT'
)
# notify_log table :: This is a table which logs notifications sent
c_db.execute(
'CREATE TABLE IF NOT EXISTS notify_log (id INTEGER PRIMARY KEY AUTOINCREMENT, '

View File

@@ -82,9 +82,11 @@ _CONFIG_DEFINITIONS = {
'GROWL_ON_RESUME': (int, 'Growl', 0),
'GROWL_ON_BUFFER': (int, 'Growl', 0),
'GROWL_ON_WATCHED': (int, 'Growl', 0),
'HOME_LIBRARY_CARDS': (str, 'General', 'library_statistics_first'),
'HOME_STATS_LENGTH': (int, 'General', 30),
'HOME_STATS_TYPE': (int, 'General', 0),
'HOME_STATS_COUNT': (int, 'General', 5),
'HOME_STATS_CARDS': (str, 'General', 'watch_statistics, top_tv, popular_tv, top_movies, popular_movies, top_music, popular_music, top_users, top_platforms, last_watched'),
'HTTPS_CERT': (str, 'General', ''),
'HTTPS_KEY': (str, 'General', ''),
'HTTP_HOST': (str, 'General', '0.0.0.0'),
@@ -194,8 +196,14 @@ _CONFIG_DEFINITIONS = {
'TV_NOTIFY_ON_PAUSE': (int, 'Monitoring', 0),
'TWITTER_ENABLED': (int, 'Twitter', 0),
'TWITTER_PASSWORD': (str, 'Twitter', ''),
'TWITTER_PREFIX': (str, 'Twitter', 'Headphones'),
'TWITTER_PREFIX': (str, 'Twitter', 'PlexPy'),
'TWITTER_USERNAME': (str, 'Twitter', ''),
'TWITTER_ON_PLAY': (int, 'Twitter', 0),
'TWITTER_ON_STOP': (int, 'Twitter', 0),
'TWITTER_ON_PAUSE': (int, 'Twitter', 0),
'TWITTER_ON_RESUME': (int, 'Twitter', 0),
'TWITTER_ON_BUFFER': (int, 'Twitter', 0),
'TWITTER_ON_WATCHED': (int, 'Twitter', 0),
'UPDATE_DB_INTERVAL': (int, 'General', 24),
'VERIFY_SSL_CERT': (bool_int, 'Advanced', 1),
'VIDEO_LOGGING_ENABLE': (int, 'Monitoring', 1),

View File

@@ -131,32 +131,24 @@ class DataFactory(object):
return dict
def get_home_stats(self, time_range='30', stat_type='0', stat_count='5'):
def get_home_stats(self, time_range='30', stats_type=0, stats_count='5', stats_cards='', notify_watched_percent='85'):
monitor_db = database.MonitorDatabase()
if not time_range.isdigit():
time_range = '30'
sort_type = 'total_plays' if stats_type == 0 else 'total_duration'
sort_type = 'total_plays' if stat_type == '0' else 'total_duration'
if not time_range.isdigit():
stat_count = '5'
# This actually determines the output order in the home page
stats_queries = ["top_tv", "popular_tv", "top_movies", "popular_movies", "top_users", "top_platforms", "last_watched"]
home_stats = []
for stat in stats_queries:
for stat in stats_cards:
if 'top_tv' in stat:
top_tv = []
try:
query = 'SELECT session_history_metadata.id, ' \
'session_history_metadata.grandparent_title, ' \
'COUNT(session_history_metadata.grandparent_title) as total_plays, ' \
'cast(round(SUM(round((julianday(datetime(session_history.stopped, "unixepoch", "localtime")) - ' \
'julianday(datetime(session_history.started, "unixepoch", "localtime"))) * 86400) - ' \
'(CASE WHEN session_history.paused_counter IS NULL THEN 0 ' \
'ELSE session_history.paused_counter END))/60) as integer) as total_duration,' \
'SUM(case when session_history.stopped > 0 ' \
'then (session_history.stopped - session_history.started) ' \
' - (case when session_history.paused_counter is NULL then 0 else session_history.paused_counter end) ' \
'else 0 end) as total_duration, ' \
'session_history_metadata.grandparent_rating_key, ' \
'MAX(session_history.started) as last_watch,' \
'session_history_metadata.grandparent_thumb ' \
@@ -166,7 +158,7 @@ class DataFactory(object):
'>= datetime("now", "-%s days", "localtime") ' \
'AND session_history_metadata.media_type = "episode" ' \
'GROUP BY session_history_metadata.grandparent_title ' \
'ORDER BY %s DESC LIMIT %s' % (time_range, sort_type, stat_count)
'ORDER BY %s DESC LIMIT %s' % (time_range, sort_type, stats_count)
result = monitor_db.select(query)
except:
logger.warn("Unable to execute database query.")
@@ -193,16 +185,62 @@ class DataFactory(object):
'stat_type': sort_type,
'rows': top_tv})
elif 'popular_tv' in stat:
popular_tv = []
try:
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, ' \
'COUNT(session_history.id) as total_plays, ' \
'SUM(case when session_history.stopped > 0 ' \
'then (session_history.stopped - session_history.started) ' \
' - (case when session_history.paused_counter is NULL then 0 else session_history.paused_counter end) ' \
'else 0 end) as total_duration, ' \
'session_history_metadata.grandparent_thumb ' \
'FROM session_history_metadata ' \
'JOIN session_history ON session_history_metadata.id = session_history.id ' \
'WHERE datetime(session_history.stopped, "unixepoch", "localtime") ' \
'>= datetime("now", "-%s days", "localtime") ' \
'AND session_history_metadata.media_type = "episode" ' \
'GROUP BY session_history_metadata.grandparent_title ' \
'ORDER BY users_watched DESC, %s DESC ' \
'LIMIT %s' % (time_range, sort_type, stats_count)
result = monitor_db.select(query)
except:
logger.warn("Unable to execute database query.")
return None
for item in result:
row = {'title': item[1],
'users_watched': item[2],
'rating_key': item[3],
'last_play': item[4],
'total_plays': item[5],
'grandparent_thumb': item[7],
'thumb': '',
'user': '',
'friendly_name': '',
'platform_type': '',
'platform': '',
'row_id': item[0]
}
popular_tv.append(row)
home_stats.append({'stat_id': stat,
'rows': popular_tv})
elif 'top_movies' in stat:
top_movies = []
try:
query = 'SELECT session_history_metadata.id, ' \
'session_history_metadata.full_title, ' \
'COUNT(session_history_metadata.full_title) as total_plays, ' \
'cast(round(SUM(round((julianday(datetime(session_history.stopped, "unixepoch", "localtime")) - ' \
'julianday(datetime(session_history.started, "unixepoch", "localtime"))) * 86400) - ' \
'(CASE WHEN session_history.paused_counter IS NULL THEN 0 ' \
'ELSE session_history.paused_counter END))/60) as integer) as total_duration,' \
'SUM(case when session_history.stopped > 0 ' \
'then (session_history.stopped - session_history.started) ' \
' - (case when session_history.paused_counter is NULL then 0 else session_history.paused_counter end) ' \
'else 0 end) as total_duration, ' \
'session_history_metadata.rating_key, ' \
'MAX(session_history.started) as last_watch,' \
'session_history_metadata.thumb ' \
@@ -212,7 +250,7 @@ class DataFactory(object):
'>= datetime("now", "-%s days", "localtime") ' \
'AND session_history_metadata.media_type = "movie" ' \
'GROUP BY session_history_metadata.full_title ' \
'ORDER BY %s DESC LIMIT %s' % (time_range, sort_type, stat_count)
'ORDER BY %s DESC LIMIT %s' % (time_range, sort_type, stats_count)
result = monitor_db.select(query)
except:
logger.warn("Unable to execute database query.")
@@ -239,48 +277,6 @@ class DataFactory(object):
'stat_type': sort_type,
'rows': top_movies})
elif 'popular_tv' in stat:
popular_tv = []
try:
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, ' \
'COUNT(session_history.id) as total_plays, ' \
'session_history_metadata.grandparent_thumb ' \
'FROM session_history_metadata ' \
'JOIN session_history ON session_history_metadata.id = session_history.id ' \
'WHERE datetime(session_history.stopped, "unixepoch", "localtime") ' \
'>= datetime("now", "-%s days", "localtime") ' \
'AND session_history_metadata.media_type = "episode" ' \
'GROUP BY session_history_metadata.grandparent_title ' \
'ORDER BY users_watched DESC, total_plays DESC ' \
'LIMIT %s' % (time_range, stat_count)
result = monitor_db.select(query)
except:
logger.warn("Unable to execute database query.")
return None
for item in result:
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': '',
'row_id': item[0]
}
popular_tv.append(row)
home_stats.append({'stat_id': stat,
'rows': popular_tv})
elif 'popular_movies' in stat:
popular_movies = []
try:
@@ -290,6 +286,10 @@ class DataFactory(object):
'session_history_metadata.rating_key, ' \
'MAX(session_history.started) as last_watch, ' \
'COUNT(session_history.id) as total_plays, ' \
'SUM(case when session_history.stopped > 0 ' \
'then (session_history.stopped - session_history.started) ' \
' - (case when session_history.paused_counter is NULL then 0 else session_history.paused_counter end) ' \
'else 0 end) as total_duration, ' \
'session_history_metadata.thumb ' \
'FROM session_history_metadata ' \
'JOIN session_history ON session_history_metadata.id = session_history.id ' \
@@ -297,8 +297,8 @@ class DataFactory(object):
'>= datetime("now", "-%s days", "localtime") ' \
'AND session_history_metadata.media_type = "movie" ' \
'GROUP BY session_history_metadata.full_title ' \
'ORDER BY users_watched DESC, total_plays DESC ' \
'LIMIT %s' % (time_range, stat_count)
'ORDER BY users_watched DESC, %s DESC ' \
'LIMIT %s' % (time_range, sort_type, stats_count)
result = monitor_db.select(query)
except:
logger.warn("Unable to execute database query.")
@@ -311,7 +311,7 @@ class DataFactory(object):
'last_play': item[4],
'total_plays': item[5],
'grandparent_thumb': '',
'thumb': item[6],
'thumb': item[7],
'user': '',
'friendly_name': '',
'platform_type': '',
@@ -323,6 +323,98 @@ class DataFactory(object):
home_stats.append({'stat_id': stat,
'rows': popular_movies})
elif 'top_music' in stat:
top_music = []
try:
query = 'SELECT session_history_metadata.id, ' \
'session_history_metadata.grandparent_title, ' \
'COUNT(session_history_metadata.grandparent_title) as total_plays, ' \
'SUM(case when session_history.stopped > 0 ' \
'then (session_history.stopped - session_history.started) ' \
' - (case when session_history.paused_counter is NULL then 0 else session_history.paused_counter end) ' \
'else 0 end) as total_duration, ' \
'session_history_metadata.grandparent_rating_key, ' \
'MAX(session_history.started) as last_watch,' \
'session_history_metadata.grandparent_thumb ' \
'FROM session_history_metadata ' \
'JOIN session_history on session_history_metadata.id = session_history.id ' \
'WHERE datetime(session_history.stopped, "unixepoch", "localtime") ' \
'>= datetime("now", "-%s days", "localtime") ' \
'AND session_history_metadata.media_type = "track" ' \
'GROUP BY session_history_metadata.grandparent_title ' \
'ORDER BY %s DESC LIMIT %s' % (time_range, sort_type, stats_count)
result = monitor_db.select(query)
except:
logger.warn("Unable to execute database query.")
return None
for item in result:
row = {'title': item[1],
'total_plays': item[2],
'total_duration': item[3],
'users_watched': '',
'rating_key': item[4],
'last_play': item[5],
'grandparent_thumb': item[6],
'thumb': '',
'user': '',
'friendly_name': '',
'platform_type': '',
'platform': '',
'row_id': item[0]
}
top_music.append(row)
home_stats.append({'stat_id': stat,
'stat_type': sort_type,
'rows': top_music})
elif 'popular_music' in stat:
popular_music = []
try:
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, ' \
'COUNT(session_history.id) as total_plays, ' \
'SUM(case when session_history.stopped > 0 ' \
'then (session_history.stopped - session_history.started) ' \
' - (case when session_history.paused_counter is NULL then 0 else session_history.paused_counter end) ' \
'else 0 end) as total_duration, ' \
'session_history_metadata.grandparent_thumb ' \
'FROM session_history_metadata ' \
'JOIN session_history ON session_history_metadata.id = session_history.id ' \
'WHERE datetime(session_history.stopped, "unixepoch", "localtime") ' \
'>= datetime("now", "-%s days", "localtime") ' \
'AND session_history_metadata.media_type = "track" ' \
'GROUP BY session_history_metadata.grandparent_title ' \
'ORDER BY users_watched DESC, %s DESC ' \
'LIMIT %s' % (time_range, sort_type, stats_count)
result = monitor_db.select(query)
except:
logger.warn("Unable to execute database query.")
return None
for item in result:
row = {'title': item[1],
'users_watched': item[2],
'rating_key': item[3],
'last_play': item[4],
'total_plays': item[5],
'grandparent_thumb': item[7],
'thumb': '',
'user': '',
'friendly_name': '',
'platform_type': '',
'platform': '',
'row_id': item[0]
}
popular_music.append(row)
home_stats.append({'stat_id': stat,
'rows': popular_music})
elif 'top_users' in stat:
top_users = []
try:
@@ -330,10 +422,10 @@ class DataFactory(object):
'(case when users.friendly_name is null then session_history.user else ' \
'users.friendly_name end) as friendly_name,' \
'COUNT(session_history.id) as total_plays, ' \
'cast(round(SUM(round((julianday(datetime(session_history.stopped, "unixepoch", "localtime")) - ' \
'julianday(datetime(session_history.started, "unixepoch", "localtime"))) * 86400) - ' \
'(CASE WHEN session_history.paused_counter IS NULL THEN 0 ' \
'ELSE session_history.paused_counter END))/60) as integer) as total_duration,' \
'SUM(case when session_history.stopped > 0 ' \
'then (session_history.stopped - session_history.started) ' \
' - (case when session_history.paused_counter is NULL then 0 else session_history.paused_counter end) ' \
'else 0 end) as total_duration, ' \
'MAX(session_history.started) as last_watch, ' \
'users.custom_avatar_url as thumb, ' \
'users.user_id ' \
@@ -343,7 +435,7 @@ class DataFactory(object):
'WHERE datetime(session_history.stopped, "unixepoch", "localtime") >= ' \
'datetime("now", "-%s days", "localtime") '\
'GROUP BY session_history.user_id ' \
'ORDER BY %s DESC LIMIT %s' % (time_range, sort_type, stat_count)
'ORDER BY %s DESC LIMIT %s' % (time_range, sort_type, stats_count)
result = monitor_db.select(query)
except:
logger.warn("Unable to execute database query.")
@@ -382,16 +474,16 @@ class DataFactory(object):
try:
query = 'SELECT session_history.platform, ' \
'COUNT(session_history.id) as total_plays, ' \
'cast(round(SUM(round((julianday(datetime(session_history.stopped, "unixepoch", "localtime")) - ' \
'julianday(datetime(session_history.started, "unixepoch", "localtime"))) * 86400) - ' \
'(CASE WHEN session_history.paused_counter IS NULL THEN 0 ' \
'ELSE session_history.paused_counter END))/60) as integer) as total_duration,' \
'SUM(case when session_history.stopped > 0 ' \
'then (session_history.stopped - session_history.started) ' \
' - (case when session_history.paused_counter is NULL then 0 else session_history.paused_counter end) ' \
'else 0 end) as total_duration, ' \
'MAX(session_history.started) as last_watch ' \
'FROM session_history ' \
'WHERE datetime(session_history.stopped, "unixepoch", "localtime") ' \
'>= datetime("now", "-%s days", "localtime") ' \
'GROUP BY session_history.platform ' \
'ORDER BY %s DESC LIMIT %s' % (time_range, sort_type, stat_count)
'ORDER BY %s DESC LIMIT %s' % (time_range, sort_type, stats_count)
result = monitor_db.select(query)
except:
logger.warn("Unable to execute database query.")
@@ -432,7 +524,11 @@ class DataFactory(object):
'session_history_metadata.thumb, ' \
'session_history_metadata.grandparent_thumb, ' \
'MAX(session_history.started) as last_watch, ' \
'session_history.player as platform ' \
'session_history.player as platform, ' \
'((CASE WHEN session_history.view_offset IS NULL THEN 0.1 ELSE \
session_history.view_offset * 1.0 END) / \
(CASE WHEN session_history_metadata.duration IS NULL THEN 1.0 ELSE \
session_history_metadata.duration * 1.0 END) * 100) as percent_complete ' \
'FROM session_history_metadata ' \
'JOIN session_history ON session_history_metadata.id = session_history.id ' \
'LEFT OUTER JOIN users ON session_history.user_id = users.user_id ' \
@@ -440,9 +536,10 @@ class DataFactory(object):
'>= datetime("now", "-%s days", "localtime") ' \
'AND (session_history_metadata.media_type = "movie" ' \
'OR session_history_metadata.media_type = "episode") ' \
'AND percent_complete >= %s ' \
'GROUP BY session_history_metadata.full_title ' \
'ORDER BY last_watch DESC ' \
'LIMIT %s' % (time_range, stat_count)
'LIMIT %s' % (time_range, notify_watched_percent, stats_count)
result = monitor_db.select(query)
except:
logger.warn("Unable to execute database query.")
@@ -524,24 +621,35 @@ class DataFactory(object):
try:
if user_id:
query = 'SELECT session_history.id, session_history.media_type, session_history.rating_key, title, ' \
'grandparent_title, thumb, parent_thumb, grandparent_thumb, media_index, parent_media_index, year, started, user ' \
query = 'SELECT session_history.id, session_history.media_type, session_history.rating_key, session_history.parent_rating_key, ' \
'title, parent_title, grandparent_title, thumb, parent_thumb, grandparent_thumb, media_index, parent_media_index, ' \
'year, started, user ' \
'FROM session_history_metadata ' \
'JOIN session_history ON session_history_metadata.id = session_history.id ' \
'WHERE user_id = ? AND session_history.media_type != "track" ORDER BY started DESC LIMIT ?'
'WHERE user_id = ? ' \
'GROUP BY (CASE WHEN session_history.media_type = "track" THEN session_history.parent_rating_key ' \
' ELSE session_history.rating_key END) ' \
'ORDER BY started DESC LIMIT ?'
result = monitor_db.select(query, args=[user_id, limit])
elif user:
query = 'SELECT session_history.id, session_history.media_type, session_history.rating_key, title, ' \
'grandparent_title, thumb, parent_thumb, grandparent_thumb, media_index, parent_media_index, year, started, user ' \
query = 'SELECT session_history.id, session_history.media_type, session_history.rating_key, session_history.parent_rating_key, ' \
'title, parent_title, grandparent_title, thumb, parent_thumb, grandparent_thumb, media_index, parent_media_index, ' \
'year, started, user ' \
'FROM session_history_metadata ' \
'JOIN session_history ON session_history_metadata.id = session_history.id ' \
'WHERE user = ? AND session_history.media_type != "track" ORDER BY started DESC LIMIT ?'
'WHERE user = ? ' \
'GROUP BY (CASE WHEN session_history.media_type = "track" THEN session_history.parent_rating_key ' \
' ELSE session_history.rating_key END) ' \
'ORDER BY started DESC LIMIT ?'
result = monitor_db.select(query, args=[user, limit])
else:
query = 'SELECT session_history.id, session_history.media_type, session_history.rating_key, title, ' \
'grandparent_title, thumb, parent_thumb, grandparent_thumb, media_index, parent_media_index, year, started, user ' \
'FROM session_history_metadata WHERE session_history.media_type != "track"' \
query = 'SELECT session_history.id, session_history.media_type, session_history.rating_key, session_history.parent_rating_key, ' \
'title, parent_title, grandparent_title, thumb, parent_thumb, grandparent_thumb, media_index, parent_media_index, ' \
'year, started, user ' \
'FROM session_history_metadata ' \
'JOIN session_history ON session_history_metadata.id = session_history.id ' \
'GROUP BY (CASE WHEN session_history.media_type = "track" THEN session_history.parent_rating_key ' \
' ELSE session_history.rating_key END) ' \
'ORDER BY started DESC LIMIT ?'
result = monitor_db.select(query, args=[limit])
except:
@@ -549,24 +657,25 @@ class DataFactory(object):
return None
for row in result:
if row[1] == 'episode' and row[6]:
thumb = row[6]
if row[1] == 'episode' and row[8]:
thumb = row[8]
elif row[1] == 'episode':
thumb = row[7]
thumb = row[9]
else:
thumb = row[5]
thumb = row[7]
recent_output = {'row_id': row[0],
'type': row[1],
'rating_key': row[2],
'title': row[3],
'parent_title': row[4],
'title': row[4],
'parent_title': row[5],
'grandparent_title': row[6],
'thumb': thumb,
'index': row[8],
'parent_index': row[9],
'year': row[10],
'time': row[11],
'user': row[12]
'index': row[10],
'parent_index': row[11],
'year': row[12],
'time': row[13],
'user': row[14]
}
recently_watched.append(recent_output)
@@ -578,8 +687,8 @@ class DataFactory(object):
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 ' \
'year, originally_available_at, added_at, updated_at, last_viewed_at, content_rating, summary, tagline, ' \
'rating, duration, guid, directors, writers, actors, genres, studio ' \
'FROM session_history_metadata ' \
'WHERE id = ?'
result = monitor_db.select(query=query, args=[row_id])
@@ -605,6 +714,7 @@ class DataFactory(object):
'title': item['title'],
'content_rating': item['content_rating'],
'summary': item['summary'],
'tagline': item['tagline'],
'rating': item['rating'],
'duration': item['duration'],
'year': item['year'],

View File

@@ -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
@@ -33,7 +33,8 @@ class Graphs(object):
if y_axis == 'plays':
query = 'SELECT date(started, "unixepoch", "localtime") as date_played, ' \
'SUM(case when media_type = "episode" then 1 else 0 end) as tv_count, ' \
'SUM(case when media_type = "movie" then 1 else 0 end) as movie_count ' \
'SUM(case when media_type = "movie" then 1 else 0 end) as movie_count, ' \
'SUM(case when media_type = "track" then 1 else 0 end) as music_count ' \
'FROM session_history ' \
'WHERE datetime(stopped, "unixepoch", "localtime") >= datetime("now", "-%s days", "localtime") ' \
'GROUP BY date_played ' \
@@ -42,8 +43,12 @@ class Graphs(object):
result = monitor_db.select(query)
else:
query = 'SELECT date(started, "unixepoch", "localtime") as date_played, ' \
'SUM(case when media_type = "episode" and stopped > 0 then (stopped - started) else 0 end) as tv_duration, ' \
'SUM(case when media_type = "movie" and stopped > 0 then (stopped - started) else 0 end) as movie_duration ' \
'SUM(case when media_type = "episode" and stopped > 0 then (stopped - started) ' \
' - (case when paused_counter is NULL then 0 else paused_counter end) else 0 end) as tv_duration, ' \
'SUM(case when media_type = "movie" and stopped > 0 then (stopped - started) ' \
' - (case when paused_counter is NULL then 0 else paused_counter end) else 0 end) as movie_duration, ' \
'SUM(case when media_type = "track" and stopped > 0 then (stopped - started) ' \
' - (case when paused_counter is NULL then 0 else paused_counter end) else 0 end) as music_duration ' \
'FROM session_history ' \
'WHERE datetime(stopped, "unixepoch", "localtime") >= datetime("now", "-%s days", "localtime") ' \
'GROUP BY date_played ' \
@@ -62,31 +67,38 @@ class Graphs(object):
categories = []
series_1 = []
series_2 = []
series_3 = []
for date_item in sorted(date_list):
date_string = date_item.strftime('%Y-%m-%d')
categories.append(date_string)
series_1_value = 0
series_2_value = 0
series_3_value = 0
for item in result:
if date_string == item[0]:
series_1_value = item[1]
series_2_value = item[2]
series_3_value = item[3]
break
else:
series_1_value = 0
series_2_value = 0
series_3_value = 0
series_1.append(series_1_value)
series_2.append(series_2_value)
series_3.append(series_3_value)
series_1_output = {'name': 'TV',
'data': series_1}
series_2_output = {'name': 'Movies',
'data': series_2}
series_3_output = {'name': 'Music',
'data': series_3}
output = {'categories': categories,
'series': [series_1_output, series_2_output]}
'series': [series_1_output, series_2_output, series_3_output]}
return output
def get_total_plays_per_dayofweek(self, time_range='30', y_axis='plays'):
@@ -105,16 +117,16 @@ class Graphs(object):
'when 4 then "Thursday" ' \
'when 5 then "Friday" ' \
'else "Saturday" end as dayofweek, ' \
'COUNT(id) as total_plays ' \
'from session_history ' \
'SUM(case when media_type = "episode" then 1 else 0 end) as tv_count, ' \
'SUM(case when media_type = "movie" then 1 else 0 end) as movie_count, ' \
'SUM(case when media_type = "track" then 1 else 0 end) as music_count ' \
'FROM session_history ' \
'WHERE datetime(stopped, "unixepoch", "localtime") >= ' \
'datetime("now", "-' + time_range + ' days", "localtime") AND ' \
'(media_type = "episode" OR media_type = "movie") ' \
'datetime("now", "-' + time_range + ' days", "localtime") ' \
'GROUP BY dayofweek ' \
'ORDER BY daynumber'
result = monitor_db.select(query)
y_axis_label = 'Total plays'
else:
query = 'SELECT strftime("%w", datetime(started, "unixepoch", "localtime")) as daynumber, ' \
'case cast (strftime("%w", datetime(started, "unixepoch", "localtime")) as integer) ' \
@@ -125,40 +137,57 @@ class Graphs(object):
'when 4 then "Thursday" ' \
'when 5 then "Friday" ' \
'else "Saturday" end as dayofweek, ' \
'SUM(case when media_type != "track" and stopped > 0 then (stopped - started) else 0 end) as duration ' \
'from session_history ' \
'SUM(case when media_type = "episode" and stopped > 0 then (stopped - started) ' \
' - (case when paused_counter is NULL then 0 else paused_counter end) else 0 end) as tv_duration, ' \
'SUM(case when media_type = "movie" and stopped > 0 then (stopped - started) ' \
' - (case when paused_counter is NULL then 0 else paused_counter end) else 0 end) as movie_duration, ' \
'SUM(case when media_type = "track" and stopped > 0 then (stopped - started) ' \
' - (case when paused_counter is NULL then 0 else paused_counter end) else 0 end) as music_duration ' \
'FROM session_history ' \
'WHERE datetime(stopped, "unixepoch", "localtime") >= ' \
'datetime("now", "-' + time_range + ' days", "localtime") AND ' \
'(media_type = "episode" OR media_type = "movie") ' \
'datetime("now", "-' + time_range + ' days", "localtime") ' \
'GROUP BY dayofweek ' \
'ORDER BY daynumber'
result = monitor_db.select(query)
y_axis_label = 'Total duration'
days_list = ['Sunday', 'Monday', 'Tuesday', 'Wednesday',
'Thursday', 'Friday', 'Saturday']
categories = []
series_1 = []
series_2 = []
series_3 = []
for day_item in days_list:
categories.append(day_item)
series_1_value = 0
series_2_value = 0
series_3_value = 0
for item in result:
if day_item == item[1]:
series_1_value = item[2]
series_2_value = item[3]
series_3_value = item[4]
break
else:
series_1_value = 0
series_2_value = 0
series_3_value = 0
series_1.append(series_1_value)
series_2.append(series_2_value)
series_3.append(series_3_value)
series_1_output = {'name': y_axis_label,
series_1_output = {'name': 'TV',
'data': series_1}
series_2_output = {'name': 'Movies',
'data': series_2}
series_3_output = {'name': 'Music',
'data': series_3}
output = {'categories': categories,
'series': [series_1_output]}
'series': [series_1_output, series_2_output, series_3_output]}
return output
def get_total_plays_per_hourofday(self, time_range='30', y_axis='plays'):
@@ -169,28 +198,31 @@ class Graphs(object):
if y_axis == 'plays':
query = 'select strftime("%H", datetime(started, "unixepoch", "localtime")) as hourofday, ' \
'COUNT(id) ' \
'SUM(case when media_type = "episode" then 1 else 0 end) as tv_count, ' \
'SUM(case when media_type = "movie" then 1 else 0 end) as movie_count, ' \
'SUM(case when media_type = "track" then 1 else 0 end) as music_count ' \
'FROM session_history ' \
'WHERE datetime(stopped, "unixepoch", "localtime") >= ' \
'datetime("now", "-' + time_range + ' days", "localtime") AND ' \
'(media_type = "episode" OR media_type = "movie") ' \
'datetime("now", "-' + time_range + ' days", "localtime") ' \
'GROUP BY hourofday ' \
'ORDER BY hourofday'
result = monitor_db.select(query)
y_axis_label = 'Total plays'
else:
query = 'select strftime("%H", datetime(started, "unixepoch", "localtime")) as hourofday, ' \
'SUM(case when media_type != "track" and stopped > 0 then (stopped - started) else 0 end) as duration ' \
'SUM(case when media_type = "episode" and stopped > 0 then (stopped - started) ' \
' - (case when paused_counter is NULL then 0 else paused_counter end) else 0 end) as tv_duration, ' \
'SUM(case when media_type = "movie" and stopped > 0 then (stopped - started) ' \
' - (case when paused_counter is NULL then 0 else paused_counter end) else 0 end) as movie_duration, ' \
'SUM(case when media_type = "track" and stopped > 0 then (stopped - started) ' \
' - (case when paused_counter is NULL then 0 else paused_counter end) else 0 end) as music_duration ' \
'FROM session_history ' \
'WHERE datetime(stopped, "unixepoch", "localtime") >= ' \
'datetime("now", "-' + time_range + ' days", "localtime") AND ' \
'(media_type = "episode" OR media_type = "movie") ' \
'datetime("now", "-' + time_range + ' days", "localtime") ' \
'GROUP BY hourofday ' \
'ORDER BY hourofday'
result = monitor_db.select(query)
y_axis_label = 'Total duration'
hours_list = ['00','01','02','03','04','05',
'06','07','08','09','10','11',
@@ -199,24 +231,38 @@ class Graphs(object):
categories = []
series_1 = []
series_2 = []
series_3 = []
for hour_item in hours_list:
categories.append(hour_item)
series_1_value = 0
series_2_value = 0
series_3_value = 0
for item in result:
if hour_item == item[0]:
series_1_value = item[1]
series_2_value = item[2]
series_3_value = item[3]
break
else:
series_1_value = 0
series_2_value = 0
series_3_value = 0
series_1.append(series_1_value)
series_2.append(series_2_value)
series_3.append(series_3_value)
series_1_output = {'name': y_axis_label,
series_1_output = {'name': 'TV',
'data': series_1}
series_2_output = {'name': 'Movies',
'data': series_2}
series_3_output = {'name': 'Music',
'data': series_3}
output = {'categories': categories,
'series': [series_1_output]}
'series': [series_1_output, series_2_output, series_3_output]}
return output
def get_total_plays_per_month(self, y_axis='plays'):
@@ -226,7 +272,8 @@ class Graphs(object):
if y_axis == 'plays':
query = 'SELECT strftime("%Y-%m", datetime(started, "unixepoch", "localtime")) as datestring, ' \
'SUM(case when media_type = "episode" then 1 else 0 end) as tv_count, ' \
'SUM(case when media_type = "movie" then 1 else 0 end) as movie_count ' \
'SUM(case when media_type = "movie" then 1 else 0 end) as movie_count, ' \
'SUM(case when media_type = "track" then 1 else 0 end) as music_count ' \
'FROM session_history ' \
'WHERE datetime(started, "unixepoch", "localtime") >= datetime("now", "-12 months", "localtime") ' \
'GROUP BY strftime("%Y-%m", datetime(started, "unixepoch", "localtime")) ' \
@@ -235,8 +282,12 @@ class Graphs(object):
result = monitor_db.select(query)
else:
query = 'SELECT strftime("%Y-%m", datetime(started, "unixepoch", "localtime")) as datestring, ' \
'SUM(case when media_type = "episode" and stopped > 0 then (stopped - started) else 0 end) as tv_duration, ' \
'SUM(case when media_type = "movie" and stopped > 0 then (stopped - started) else 0 end) as movie_duration ' \
'SUM(case when media_type = "episode" and stopped > 0 then (stopped - started) ' \
' - (case when paused_counter is NULL then 0 else paused_counter end) else 0 end) as tv_duration, ' \
'SUM(case when media_type = "movie" and stopped > 0 then (stopped - started) ' \
' - (case when paused_counter is NULL then 0 else paused_counter end) else 0 end) as movie_duration, ' \
'SUM(case when media_type = "track" and stopped > 0 then (stopped - started) ' \
' - (case when paused_counter is NULL then 0 else paused_counter end) else 0 end) as music_duration ' \
'FROM session_history ' \
'WHERE datetime(started, "unixepoch", "localtime") >= datetime("now", "-12 months", "localtime") ' \
'GROUP BY strftime("%Y-%m", datetime(started, "unixepoch", "localtime")) ' \
@@ -254,6 +305,7 @@ class Graphs(object):
categories = []
series_1 = []
series_2 = []
series_3 = []
for month_item in sorted(month_range):
dt = datetime.datetime(*month_item[:6])
@@ -262,25 +314,31 @@ class Graphs(object):
categories.append(dt.strftime('%b %Y'))
series_1_value = 0
series_2_value = 0
series_3_value = 0
for item in result:
if date_string == item[0]:
series_1_value = item[1]
series_2_value = item[2]
series_3_value = item[3]
break
else:
series_1_value = 0
series_2_value = 0
series_3_value = 0
series_1.append(series_1_value)
series_2.append(series_2_value)
series_3.append(series_3_value)
series_1_output = {'name': 'TV',
'data': series_1}
series_2_output = {'name': 'Movies',
'data': series_2}
series_3_output = {'name': 'Music',
'data': series_3}
output = {'categories': categories,
'series': [series_1_output, series_2_output]}
'series': [series_1_output, series_2_output, series_3_output]}
return output
def get_total_plays_by_top_10_platforms(self, time_range='30', y_axis='plays'):
@@ -291,43 +349,64 @@ class Graphs(object):
if y_axis == 'plays':
query = 'SELECT platform, ' \
'count(id) as platform_count ' \
'SUM(case when media_type = "episode" then 1 else 0 end) as tv_count, ' \
'SUM(case when media_type = "movie" then 1 else 0 end) as movie_count, ' \
'SUM(case when media_type = "track" then 1 else 0 end) as music_count, ' \
'COUNT(id) as total_count ' \
'FROM session_history ' \
'WHERE (datetime(stopped, "unixepoch", "localtime") >= ' \
'datetime("now", "-' + time_range + ' days", "localtime")) AND ' \
'(media_type = "episode" OR media_type = "movie") ' \
'datetime("now", "-' + time_range + ' days", "localtime")) ' \
'GROUP BY platform ' \
'ORDER BY platform_count DESC ' \
'ORDER BY total_count DESC ' \
'LIMIT 10'
result = monitor_db.select(query)
y_axis_label = 'Total plays'
else:
query = 'SELECT platform, ' \
'SUM(case when stopped > 0 then (stopped - started) else 0 end) as duration ' \
'SUM(case when media_type = "episode" and stopped > 0 then (stopped - started) ' \
' - (case when paused_counter is NULL then 0 else paused_counter end) else 0 end) as tv_duration, ' \
'SUM(case when media_type = "movie" and stopped > 0 then (stopped - started) ' \
' - (case when paused_counter is NULL then 0 else paused_counter end) else 0 end) as movie_duration, ' \
'SUM(case when media_type = "track" and stopped > 0 then (stopped - started) ' \
' - (case when paused_counter is NULL then 0 else paused_counter end) else 0 end) as music_duration, ' \
'SUM(case when stopped > 0 then (stopped - started) ' \
' - (case when paused_counter is NULL then 0 else paused_counter end) else 0 end) as total_duration ' \
'FROM session_history ' \
'WHERE (datetime(stopped, "unixepoch", "localtime") >= ' \
'datetime("now", "-' + time_range + ' days", "localtime")) AND ' \
'(media_type = "episode" OR media_type = "movie") ' \
'datetime("now", "-' + time_range + ' days", "localtime")) ' \
'GROUP BY platform ' \
'ORDER BY duration DESC ' \
'ORDER BY total_duration DESC ' \
'LIMIT 10'
result = monitor_db.select(query)
y_axis_label = 'Total duration'
categories = []
series_1 = []
series_2 = []
series_3 = []
for item in result:
categories.append(item[0])
series_1.append(item[1])
series_2.append(item[2])
series_3.append(item[3])
series_1_output = {'name': y_axis_label,
# Rename Mystery platform names
platform_names = [('Mystery 3', 'Playstation 3'),
('Mystery 4', 'Playstation 4'),
('Mystery 5', 'Xbox 360')]
for old_name, new_name in platform_names:
categories = [item.replace(old_name, new_name) for item in categories]
series_1_output = {'name': 'TV',
'data': series_1}
series_2_output = {'name': 'Movies',
'data': series_2}
series_3_output = {'name': 'Music',
'data': series_3}
output = {'categories': categories,
'series': [series_1_output]}
'series': [series_1_output, series_2_output, series_3_output]}
return output
def get_total_plays_by_top_10_users(self, time_range='30', y_axis='plays'):
@@ -340,47 +419,61 @@ class Graphs(object):
query = 'SELECT ' \
'(case when users.friendly_name is null then session_history.user else ' \
'users.friendly_name end) as friendly_name,' \
'count(session_history.id) as user_count ' \
'SUM(case when media_type = "episode" then 1 else 0 end) as tv_count, ' \
'SUM(case when media_type = "movie" then 1 else 0 end) as movie_count, ' \
'SUM(case when media_type = "track" then 1 else 0 end) as music_count, ' \
'COUNT(session_history.id) as total_count ' \
'FROM session_history ' \
'JOIN users on session_history.user_id = users.user_id ' \
'WHERE (datetime(session_history.stopped, "unixepoch", "localtime") >= ' \
'datetime("now", "-' + time_range + ' days", "localtime")) AND ' \
'(session_history.media_type = "episode" OR session_history.media_type = "movie") ' \
'datetime("now", "-' + time_range + ' days", "localtime")) ' \
'GROUP BY session_history.user_id ' \
'ORDER BY user_count DESC ' \
'ORDER BY total_count DESC ' \
'LIMIT 10'
result = monitor_db.select(query)
y_axis_label = 'Total plays'
else:
query = 'SELECT ' \
'(case when users.friendly_name is null then session_history.user else ' \
'users.friendly_name end) as friendly_name,' \
'SUM(case when stopped > 0 then (stopped - started) else 0 end) as duration ' \
'SUM(case when media_type = "episode" and stopped > 0 then (stopped - started) ' \
' - (case when paused_counter is NULL then 0 else paused_counter end) else 0 end) as tv_duration, ' \
'SUM(case when media_type = "movie" and stopped > 0 then (stopped - started) ' \
' - (case when paused_counter is NULL then 0 else paused_counter end) else 0 end) as movie_duration, ' \
'SUM(case when media_type = "track" and stopped > 0 then (stopped - started) ' \
' - (case when paused_counter is NULL then 0 else paused_counter end) else 0 end) as music_duration, ' \
'SUM(case when stopped > 0 then (stopped - started) ' \
' - (case when paused_counter is NULL then 0 else paused_counter end) else 0 end) as total_duration ' \
'FROM session_history ' \
'JOIN users on session_history.user_id = users.user_id ' \
'WHERE (datetime(session_history.stopped, "unixepoch", "localtime") >= ' \
'datetime("now", "-' + time_range + ' days", "localtime")) AND ' \
'(session_history.media_type = "episode" OR session_history.media_type = "movie") ' \
'datetime("now", "-' + time_range + ' days", "localtime")) ' \
'GROUP BY session_history.user_id ' \
'ORDER BY duration DESC ' \
'ORDER BY total_duration DESC ' \
'LIMIT 10'
result = monitor_db.select(query)
y_axis_label = 'Total duration'
categories = []
series_1 = []
series_2 = []
series_3 = []
for item in result:
categories.append(item[0])
series_1.append(item[1])
series_2.append(item[2])
series_3.append(item[3])
series_1_output = {'name': y_axis_label,
series_1_output = {'name': 'TV',
'data': series_1}
series_2_output = {'name': 'Movies',
'data': series_2}
series_3_output = {'name': 'Music',
'data': series_3}
output = {'categories': categories,
'series': [series_1_output]}
'series': [series_1_output, series_2_output, series_3_output]}
return output
def get_total_plays_per_stream_type(self, time_range='30', y_axis='plays'):
@@ -392,31 +485,43 @@ class Graphs(object):
try:
if y_axis == 'plays':
query = 'SELECT date(session_history.started, "unixepoch", "localtime") as date_played, ' \
'SUM(case when session_history_media_info.video_decision = "direct play" then 1 else 0 end) as dp_count, ' \
'SUM(case when session_history_media_info.video_decision = "copy" then 1 else 0 end) as ds_count, ' \
'SUM(case when session_history_media_info.video_decision = "transcode" then 1 else 0 end) as tc_count ' \
'SUM(case when session_history_media_info.video_decision = "direct play" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "direct play") ' \
'then 1 else 0 end) as dp_count, ' \
'SUM(case when session_history_media_info.video_decision = "copy" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "copy") ' \
'then 1 else 0 end) as ds_count, ' \
'SUM(case when session_history_media_info.video_decision = "transcode" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "transcode") ' \
'then 1 else 0 end) as tc_count ' \
'FROM session_history ' \
'JOIN session_history_media_info ON session_history.id = session_history_media_info.id ' \
'WHERE (datetime(session_history.stopped, "unixepoch", "localtime") >= ' \
'datetime("now", "-%s days", "localtime")) AND ' \
'(session_history.media_type = "episode" OR session_history.media_type = "movie") ' \
'(session_history.media_type = "episode" OR session_history.media_type = "movie" OR session_history.media_type = "track") ' \
'GROUP BY date_played ' \
'ORDER BY started ASC' % time_range
result = monitor_db.select(query)
else:
query = 'SELECT date(session_history.started, "unixepoch", "localtime") as date_played, ' \
'SUM(case when session_history_media_info.video_decision = "direct play" AND ' \
'session_history.stopped > 0 then (stopped - started) else 0 end) as dp_duration, ' \
'SUM(case when session_history_media_info.video_decision = "copy" AND ' \
'session_history.stopped > 0 then (stopped - started) else 0 end) as ds_duration, ' \
'SUM(case when session_history_media_info.video_decision = "transcode" ' \
'AND session_history.stopped > 0 then (stopped - started) else 0 end) as tc_duration ' \
'SUM(case when (session_history_media_info.video_decision = "direct play" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "direct play")) ' \
'and session_history.stopped > 0 then (session_history.stopped - session_history.started) ' \
' - (case when paused_counter is NULL then 0 else paused_counter end) else 0 end) as dp_duration, ' \
'SUM(case when (session_history_media_info.video_decision = "copy" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "copy")) ' \
'and session_history.stopped > 0 then (session_history.stopped - session_history.started) ' \
' - (case when paused_counter is NULL then 0 else paused_counter end) else 0 end) as ds_duration, ' \
'SUM(case when (session_history_media_info.video_decision = "transcode" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "transcode")) ' \
'and session_history.stopped > 0 then (session_history.stopped - session_history.started) ' \
' - (case when paused_counter is NULL then 0 else paused_counter end) else 0 end) as tc_duration ' \
'FROM session_history ' \
'JOIN session_history_media_info ON session_history.id = session_history_media_info.id ' \
'WHERE datetime(session_history.stopped, "unixepoch", "localtime") >= ' \
'datetime("now", "-%s days", "localtime") AND ' \
'(session_history.media_type = "episode" OR session_history.media_type = "movie") ' \
'(session_history.media_type = "episode" OR session_history.media_type = "movie" OR session_history.media_type = "track") ' \
'GROUP BY date_played ' \
'ORDER BY started ASC' % time_range
@@ -465,7 +570,6 @@ class Graphs(object):
output = {'categories': categories,
'series': [series_1_output, series_2_output, series_3_output]}
return output
def get_total_plays_by_source_resolution(self, time_range='30', y_axis='plays'):
@@ -475,49 +579,74 @@ class Graphs(object):
time_range = '30'
if y_axis == 'plays':
query = 'SELECT ' \
'count(session_history.id) as play_count, ' \
'session_history_media_info.video_resolution AS resolution ' \
query = 'SELECT session_history_media_info.video_resolution AS resolution, ' \
'SUM(case when session_history_media_info.video_decision = "direct play" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "direct play") ' \
'then 1 else 0 end) as dp_count, ' \
'SUM(case when session_history_media_info.video_decision = "copy" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "copy") ' \
'then 1 else 0 end) as ds_count, ' \
'SUM(case when session_history_media_info.video_decision = "transcode" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "transcode") ' \
'then 1 else 0 end) as tc_count, ' \
'COUNT(session_history.id) as total_count ' \
'FROM session_history ' \
'JOIN session_history_media_info on session_history.id = session_history_media_info.id ' \
'WHERE (datetime(session_history.stopped, "unixepoch", "localtime") >= ' \
'datetime("now", "-' + time_range + ' days", "localtime")) AND ' \
'(session_history.media_type = "episode" OR session_history.media_type = "movie") ' \
'GROUP BY resolution ' \
'ORDER BY play_count DESC ' \
'ORDER BY total_count DESC ' \
'LIMIT 10'
result = monitor_db.select(query)
y_axis_label = 'Total plays'
else:
query = 'SELECT ' \
'SUM(case when stopped > 0 then (stopped - started) else 0 end) as duration, ' \
'session_history_media_info.video_resolution AS resolution ' \
query = 'SELECT session_history_media_info.video_resolution AS resolution,' \
'SUM(case when (session_history_media_info.video_decision = "direct play" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "direct play")) ' \
'and session_history.stopped > 0 then (session_history.stopped - session_history.started) ' \
' - (case when paused_counter is NULL then 0 else paused_counter end) else 0 end) as dp_duration, ' \
'SUM(case when (session_history_media_info.video_decision = "copy" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "copy")) ' \
'and session_history.stopped > 0 then (session_history.stopped - session_history.started) ' \
' - (case when paused_counter is NULL then 0 else paused_counter end) else 0 end) as ds_duration, ' \
'SUM(case when (session_history_media_info.video_decision = "transcode" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "transcode")) ' \
'and session_history.stopped > 0 then (session_history.stopped - session_history.started) ' \
' - (case when paused_counter is NULL then 0 else paused_counter end) else 0 end) as tc_duration, ' \
'SUM(case when stopped > 0 then (stopped - started) ' \
' - (case when paused_counter is NULL then 0 else paused_counter end) else 0 end) as total_duration ' \
'FROM session_history ' \
'JOIN session_history_media_info on session_history.id = session_history_media_info.id ' \
'WHERE (datetime(session_history.stopped, "unixepoch", "localtime") >= ' \
'datetime("now", "-' + time_range + ' days", "localtime")) AND ' \
'(session_history.media_type = "episode" OR session_history.media_type = "movie") ' \
'GROUP BY resolution ' \
'ORDER BY duration DESC ' \
'ORDER BY total_duration DESC ' \
'LIMIT 10'
result = monitor_db.select(query)
y_axis_label = 'Total duration'
categories = []
series_1 = []
series_2 = []
series_3 = []
for item in result:
categories.append(item[1])
series_1.append(item[0])
categories.append(item[0])
series_1.append(item[1])
series_2.append(item[2])
series_3.append(item[3])
series_1_output = {'name': y_axis_label,
series_1_output = {'name': 'Direct Play',
'data': series_1}
series_2_output = {'name': 'Direct Stream',
'data': series_2}
series_3_output = {'name': 'Transcode',
'data': series_3}
output = {'categories': categories,
'series': [series_1_output]}
'series': [series_1_output, series_2_output, series_3_output]}
return output
def get_total_plays_by_stream_resolution(self, time_range='30', y_axis='plays'):
@@ -528,7 +657,6 @@ class Graphs(object):
if y_axis == 'plays':
query = 'SELECT ' \
'count(session_history.id) as play_count, ' \
'(case when session_history_media_info.video_decision = "transcode" then ' \
'(case ' \
'when session_history_media_info.transcode_height <= 360 then "sd" ' \
@@ -538,21 +666,29 @@ class Graphs(object):
'when session_history_media_info.transcode_height <= 1080 then "1080" ' \
'when session_history_media_info.transcode_height <= 1440 then "QHD" ' \
'when session_history_media_info.transcode_height <= 2160 then "4K" ' \
'else "unknown" end) else session_history_media_info.video_resolution end) as resolution ' \
'else "unknown" end) else session_history_media_info.video_resolution end) as resolution, ' \
'SUM(case when session_history_media_info.video_decision = "direct play" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "direct play") ' \
'then 1 else 0 end) as dp_count, ' \
'SUM(case when session_history_media_info.video_decision = "copy" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "copy") ' \
'then 1 else 0 end) as ds_count, ' \
'SUM(case when session_history_media_info.video_decision = "transcode" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "transcode") ' \
'then 1 else 0 end) as tc_count, ' \
'COUNT(session_history.id) as total_count ' \
'FROM session_history ' \
'JOIN session_history_media_info on session_history.id = session_history_media_info.id ' \
'WHERE (datetime(session_history.stopped, "unixepoch", "localtime") >= ' \
'datetime("now", "-' + time_range + ' days", "localtime")) AND ' \
'(session_history.media_type = "episode" OR session_history.media_type = "movie") ' \
'GROUP BY resolution ' \
'ORDER BY play_count DESC ' \
'ORDER BY total_count DESC ' \
'LIMIT 10'
result = monitor_db.select(query)
y_axis_label = 'Total plays'
else:
query = 'SELECT ' \
'SUM(case when stopped > 0 then (stopped - started) else 0 end) as duration, ' \
'(case when session_history_media_info.video_decision = "transcode" then ' \
'(case ' \
'when session_history_media_info.transcode_height <= 360 then "sd" ' \
@@ -562,31 +698,137 @@ class Graphs(object):
'when session_history_media_info.transcode_height <= 1080 then "1080" ' \
'when session_history_media_info.transcode_height <= 1440 then "QHD" ' \
'when session_history_media_info.transcode_height <= 2160 then "4K" ' \
'else "unknown" end) else session_history_media_info.video_resolution end) as resolution ' \
'else "unknown" end) else session_history_media_info.video_resolution end) as resolution, ' \
'SUM(case when (session_history_media_info.video_decision = "direct play" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "direct play")) ' \
'and session_history.stopped > 0 then (session_history.stopped - session_history.started) ' \
' - (case when paused_counter is NULL then 0 else paused_counter end) else 0 end) as dp_duration, ' \
'SUM(case when (session_history_media_info.video_decision = "copy" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "copy")) ' \
'and session_history.stopped > 0 then (session_history.stopped - session_history.started) ' \
' - (case when paused_counter is NULL then 0 else paused_counter end) else 0 end) as ds_duration, ' \
'SUM(case when (session_history_media_info.video_decision = "transcode" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "transcode")) ' \
'and session_history.stopped > 0 then (session_history.stopped - session_history.started) ' \
' - (case when paused_counter is NULL then 0 else paused_counter end) else 0 end) as tc_duration, ' \
'SUM(case when stopped > 0 then (stopped - started) ' \
' - (case when paused_counter is NULL then 0 else paused_counter end) else 0 end) as total_duration ' \
'FROM session_history ' \
'JOIN session_history_media_info on session_history.id = session_history_media_info.id ' \
'WHERE (datetime(session_history.stopped, "unixepoch", "localtime") >= ' \
'datetime("now", "-' + time_range + ' days", "localtime")) AND ' \
'(session_history.media_type = "episode" OR session_history.media_type = "movie") ' \
'GROUP BY resolution ' \
'ORDER BY duration DESC ' \
'ORDER BY total_duration DESC ' \
'LIMIT 10'
result = monitor_db.select(query)
y_axis_label = 'Total duration'
categories = []
series_1 = []
series_2 = []
series_3 = []
for item in result:
categories.append(item[1])
series_1.append(item[0])
categories.append(item[0])
series_1.append(item[1])
series_2.append(item[2])
series_3.append(item[3])
series_1_output = {'name': y_axis_label,
series_1_output = {'name': 'Direct Play',
'data': series_1}
series_2_output = {'name': 'Direct Stream',
'data': series_2}
series_3_output = {'name': 'Transcode',
'data': series_3}
output = {'categories': categories,
'series': [series_1_output]}
'series': [series_1_output, series_2_output, series_3_output]}
return output
def get_stream_type_by_top_10_platforms(self, time_range='30', y_axis='plays'):
monitor_db = database.MonitorDatabase()
if not time_range.isdigit():
time_range = '30'
if y_axis == 'plays':
query = 'SELECT ' \
'session_history.platform as platform, ' \
'SUM(case when session_history_media_info.video_decision = "direct play" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "direct play") ' \
'then 1 else 0 end) as dp_count, ' \
'SUM(case when session_history_media_info.video_decision = "copy" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "copy") ' \
'then 1 else 0 end) as ds_count, ' \
'SUM(case when session_history_media_info.video_decision = "transcode" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "transcode") ' \
'then 1 else 0 end) as tc_count, ' \
'COUNT(session_history.id) as total_count ' \
'FROM session_history ' \
'JOIN session_history_media_info ON session_history.id = session_history_media_info.id ' \
'WHERE datetime(session_history.started, "unixepoch", "localtime") >= ' \
'datetime("now", "-' + time_range + ' days", "localtime") AND ' \
'(session_history.media_type = "episode" OR session_history.media_type = "movie" OR session_history.media_type = "track") ' \
'GROUP BY platform ' \
'ORDER BY total_count DESC LIMIT 10'
result = monitor_db.select(query)
else:
query = 'SELECT ' \
'session_history.platform as platform, ' \
'SUM(case when (session_history_media_info.video_decision = "direct play" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "direct play")) ' \
'and session_history.stopped > 0 then (session_history.stopped - session_history.started) ' \
' - (case when paused_counter is NULL then 0 else paused_counter end) else 0 end) as dp_duration, ' \
'SUM(case when (session_history_media_info.video_decision = "copy" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "copy")) ' \
'and session_history.stopped > 0 then (session_history.stopped - session_history.started) ' \
' - (case when paused_counter is NULL then 0 else paused_counter end) else 0 end) as ds_duration, ' \
'SUM(case when (session_history_media_info.video_decision = "transcode" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "transcode")) ' \
'and session_history.stopped > 0 then (session_history.stopped - session_history.started) ' \
' - (case when paused_counter is NULL then 0 else paused_counter end) else 0 end) as tc_duration, ' \
'SUM(case when session_history.stopped > 0 ' \
'then (session_history.stopped - session_history.started) ' \
' - (case when paused_counter is NULL then 0 else paused_counter end) else 0 end) as total_duration ' \
'FROM session_history ' \
'JOIN session_history_media_info ON session_history.id = session_history_media_info.id ' \
'WHERE datetime(session_history.started, "unixepoch", "localtime") >= ' \
'datetime("now", "-' + time_range + ' days", "localtime") AND ' \
'(session_history.media_type = "episode" OR session_history.media_type = "movie" OR session_history.media_type = "track") ' \
'GROUP BY platform ' \
'ORDER BY total_duration DESC LIMIT 10'
result = monitor_db.select(query)
categories = []
series_1 = []
series_2 = []
series_3 = []
for item in result:
categories.append(item[0])
series_1.append(item[1])
series_2.append(item[2])
series_3.append(item[3])
# Rename Mystery platform names
platform_names = [('Mystery 3', 'Playstation 3'),
('Mystery 4', 'Playstation 4'),
('Mystery 5', 'Xbox 360')]
for old_name, new_name in platform_names:
categories = [item.replace(old_name, new_name) for item in categories]
series_1_output = {'name': 'Direct Play',
'data': series_1}
series_2_output = {'name': 'Direct Stream',
'data': series_2}
series_3_output = {'name': 'Transcode',
'data': series_3}
output = {'categories': categories,
'series': [series_1_output, series_2_output, series_3_output]}
return output
@@ -599,15 +841,22 @@ class Graphs(object):
if y_axis == 'plays':
query = 'SELECT ' \
'CASE WHEN users.friendly_name is null then users.username else users.friendly_name end as username, ' \
'SUM(case when session_history_media_info.video_decision = "direct play" then 1 else 0 end) as dp_count, ' \
'SUM(case when session_history_media_info.video_decision = "copy" then 1 else 0 end) as ds_count, ' \
'SUM(case when session_history_media_info.video_decision = "transcode" then 1 else 0 end) as tr_count, ' \
'SUM(case when session_history.media_type != "track" then 1 else 0 end) as total_count ' \
'SUM(case when session_history_media_info.video_decision = "direct play" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "direct play") ' \
'then 1 else 0 end) as dp_count, ' \
'SUM(case when session_history_media_info.video_decision = "copy" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "copy") ' \
'then 1 else 0 end) as ds_count, ' \
'SUM(case when session_history_media_info.video_decision = "transcode" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "transcode") ' \
'then 1 else 0 end) as tc_count, ' \
'COUNT(session_history.id) as total_count ' \
'FROM session_history ' \
'JOIN users ON session_history.user_id = users.user_id ' \
'JOIN session_history_media_info ON session_history.id = session_history_media_info.id ' \
'WHERE datetime(session_history.started, "unixepoch", "localtime") >= ' \
'datetime("now", "-' + time_range + ' days", "localtime") ' \
'datetime("now", "-' + time_range + ' days", "localtime") AND ' \
'(session_history.media_type = "episode" OR session_history.media_type = "movie" OR session_history.media_type = "track") ' \
'GROUP BY username ' \
'ORDER BY total_count DESC LIMIT 10'
@@ -615,85 +864,29 @@ class Graphs(object):
else:
query = 'SELECT ' \
'CASE WHEN users.friendly_name is null then users.username else users.friendly_name end as username, ' \
'SUM(case when session_history.stopped > 0 AND session_history_media_info.video_decision = "direct play" ' \
'then (session_history.stopped - session_history.started) else 0 end) as dp_count, ' \
'SUM(case when session_history.stopped > 0 AND session_history_media_info.video_decision = "copy" ' \
'then (session_history.stopped - session_history.started) else 0 end) as ds_count, ' \
'SUM(case when session_history.stopped > 0 AND session_history_media_info.video_decision = "transcode" ' \
'then (session_history.stopped - session_history.started) else 0 end) as tr_count, ' \
'SUM(case when session_history.stopped > 0 AND session_history.media_type != "track" ' \
'then (session_history.stopped - session_history.started) else 0 end) as total_count ' \
'SUM(case when (session_history_media_info.video_decision = "direct play" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "direct play")) ' \
'and session_history.stopped > 0 then (session_history.stopped - session_history.started) ' \
' - (case when paused_counter is NULL then 0 else paused_counter end) else 0 end) as dp_duration, ' \
'SUM(case when (session_history_media_info.video_decision = "copy" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "copy")) ' \
'and session_history.stopped > 0 then (session_history.stopped - session_history.started) ' \
' - (case when paused_counter is NULL then 0 else paused_counter end) else 0 end) as ds_duration, ' \
'SUM(case when (session_history_media_info.video_decision = "transcode" ' \
'or (session_history_media_info.video_decision = "" and session_history_media_info.audio_decision = "transcode")) ' \
'and session_history.stopped > 0 then (session_history.stopped - session_history.started) ' \
' - (case when paused_counter is NULL then 0 else paused_counter end) else 0 end) as tc_duration, ' \
'SUM(case when session_history.stopped > 0 ' \
'then (session_history.stopped - session_history.started) ' \
' - (case when paused_counter is NULL then 0 else paused_counter end) else 0 end) as total_duration ' \
'FROM session_history ' \
'JOIN users ON session_history.user_id = users.user_id ' \
'JOIN session_history_media_info ON session_history.id = session_history_media_info.id ' \
'WHERE datetime(session_history.started, "unixepoch", "localtime") >= ' \
'datetime("now", "-' + time_range + ' days", "localtime") ' \
'datetime("now", "-' + time_range + ' days", "localtime") AND ' \
'(session_history.media_type = "episode" OR session_history.media_type = "movie" OR session_history.media_type = "track") ' \
'GROUP BY username ' \
'ORDER BY total_count DESC LIMIT 10'
result = monitor_db.select(query)
categories = []
series_1 = []
series_2 = []
series_3 = []
for item in result:
categories.append(item[0])
series_1.append(item[1])
series_2.append(item[2])
series_3.append(item[3])
series_1_output = {'name': 'Direct Play',
'data': series_1}
series_2_output = {'name': 'Direct Stream',
'data': series_2}
series_3_output = {'name': 'Transcode',
'data': series_3}
output = {'categories': categories,
'series': [series_1_output, series_2_output, series_3_output]}
return output
def get_stream_type_by_top_10_platforms(self, time_range='30', y_axis='plays'):
monitor_db = database.MonitorDatabase()
if not time_range.isdigit():
time_range = '30'
if y_axis == 'plays':
query = 'SELECT ' \
'session_history.platform as platform, ' \
'SUM(case when session_history_media_info.video_decision = "direct play" then 1 else 0 end) as dp_count, ' \
'SUM(case when session_history_media_info.video_decision = "copy" then 1 else 0 end) as ds_count, ' \
'SUM(case when session_history_media_info.video_decision = "transcode" then 1 else 0 end) as tr_count, ' \
'SUM(case when session_history.media_type != "track" then 1 else 0 end) as total_count ' \
'FROM session_history ' \
'JOIN session_history_media_info ON session_history.id = session_history_media_info.id ' \
'WHERE datetime(session_history.started, "unixepoch", "localtime") >= ' \
'datetime("now", "-' + time_range + ' days", "localtime") ' \
'GROUP BY platform ' \
'ORDER BY total_count DESC LIMIT 10'
result = monitor_db.select(query)
else:
query = 'SELECT ' \
'session_history.platform as platform, ' \
'SUM(case when session_history.stopped > 0 AND session_history_media_info.video_decision = "direct play" ' \
'then (session_history.stopped - session_history.started) else 0 end) as dp_count, ' \
'SUM(case when session_history.stopped > 0 AND session_history_media_info.video_decision = "copy" ' \
'then (session_history.stopped - session_history.started) else 0 end) as ds_count, ' \
'SUM(case when session_history.stopped > 0 AND session_history_media_info.video_decision = "transcode" ' \
'then (session_history.stopped - session_history.started) else 0 end) as tr_count, ' \
'SUM(case when session_history.stopped > 0 AND session_history.media_type != "track" ' \
'then (session_history.stopped - session_history.started) else 0 end) as total_count ' \
'FROM session_history ' \
'JOIN session_history_media_info ON session_history.id = session_history_media_info.id ' \
'WHERE datetime(session_history.started, "unixepoch", "localtime") >= ' \
'datetime("now", "-' + time_range + ' days", "localtime") ' \
'GROUP BY platform ' \
'ORDER BY total_count DESC LIMIT 10'
'ORDER BY total_duration DESC LIMIT 10'
result = monitor_db.select(query)

View File

@@ -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
@@ -241,37 +241,41 @@ class MonitorProcessing(object):
if is_import:
if str(session['stopped']).isdigit():
stopped = session['stopped']
stopped = int(session['stopped'])
else:
stopped = int(time.time())
else:
stopped = int(time.time())
if plexpy.CONFIG.VIDEO_LOGGING_ENABLE and \
if plexpy.CONFIG.VIDEO_LOGGING_ENABLE and str(session['rating_key']).isdigit() and \
(session['media_type'] == 'movie' or session['media_type'] == 'episode'):
logging_enabled = True
elif plexpy.CONFIG.MUSIC_LOGGING_ENABLE and \
elif plexpy.CONFIG.MUSIC_LOGGING_ENABLE and str(session['rating_key']).isdigit() and \
session['media_type'] == 'track':
logging_enabled = True
else:
logger.debug(u"PlexPy Monitor :: ratingKey %s not logged. Does not meet logging criteria. "
u"Media type is '%s'" % (session['rating_key'], session['media_type']))
if str(session['paused_counter']).isdigit():
real_play_time = stopped - session['started'] - int(session['paused_counter'])
else:
real_play_time = stopped - session['started']
if plexpy.CONFIG.LOGGING_IGNORE_INTERVAL and not is_import:
if (session['media_type'] == 'movie' or session['media_type'] == 'episode') and \
(int(stopped) - session['started'] < int(plexpy.CONFIG.LOGGING_IGNORE_INTERVAL)):
(real_play_time < int(plexpy.CONFIG.LOGGING_IGNORE_INTERVAL)):
logging_enabled = False
logger.debug(u"PlexPy Monitor :: Play duration for ratingKey %s is %s secs which is less than %s "
u"seconds, so we're not logging it." %
(session['rating_key'], str(int(stopped) - session['started']),
plexpy.CONFIG.LOGGING_IGNORE_INTERVAL))
(session['rating_key'], str(real_play_time), plexpy.CONFIG.LOGGING_IGNORE_INTERVAL))
elif is_import and import_ignore_interval:
if (session['media_type'] == 'movie' or session['media_type'] == 'episode') and \
(int(stopped) - session['started'] < int(import_ignore_interval)):
(real_play_time < int(import_ignore_interval)):
logging_enabled = False
logger.debug(u"PlexPy Monitor :: Play duration for ratingKey %s is %s secs which is less than %s "
u"seconds, so we're not logging it." %
(session['rating_key'], str(int(stopped) - session['started']),
(session['rating_key'], str(real_play_time),
import_ignore_interval))
if not user_details['keep_history'] and not is_import:
@@ -343,17 +347,17 @@ class MonitorProcessing(object):
'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) VALUES ' \
'tagline, rating, duration, guid, directors, writers, actors, genres, studio) VALUES ' \
'(last_insert_rowid(), ' \
'?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'
'?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'
args = [session['rating_key'], session['parent_rating_key'], session['grandparent_rating_key'],
session['title'], session['parent_title'], session['grandparent_title'], full_title,
metadata['index'], metadata['parent_index'], metadata['thumb'], metadata['parent_thumb'],
metadata['grandparent_thumb'], metadata['art'], session['media_type'], metadata['year'],
metadata['originally_available_at'], metadata['added_at'], metadata['updated_at'],
metadata['last_viewed_at'], metadata['content_rating'], metadata['summary'], metadata['rating'],
metadata['duration'], metadata['guid'], directors, writers, actors, genres, metadata['studio']]
metadata['last_viewed_at'], metadata['content_rating'], metadata['summary'], metadata['tagline'],
metadata['rating'], metadata['duration'], metadata['guid'], directors, writers, actors, genres, metadata['studio']]
# logger.debug(u"PlexPy Monitor :: Writing session_history_metadata transaction...")
self.db.action(query=query, args=args)

View File

@@ -349,14 +349,14 @@ def build_notify_text(session, state):
if on_start_subject and on_start_body:
try:
subject_text = on_start_subject.format(**available_params)
subject_text = unicode(on_start_subject).format(**available_params)
except LookupError, e:
logger.error(u"PlexPy Notifier :: Unable to parse field %s in notification subject. Using fallback." % e)
except:
logger.error(u"PlexPy Notifier :: Unable to parse custom notification subject. Using fallback.")
try:
body_text = on_start_body.format(**available_params)
body_text = unicode(on_start_body).format(**available_params)
except LookupError, e:
logger.error(u"PlexPy Notifier :: Unable to parse field %s in notification body. Using fallback." % e)
except:
@@ -373,14 +373,14 @@ def build_notify_text(session, state):
if on_stop_subject and on_stop_body:
try:
subject_text = on_stop_subject.format(**available_params)
subject_text = unicode(on_stop_subject).format(**available_params)
except LookupError, e:
logger.error(u"PlexPy Notifier :: Unable to parse field %s in notification subject. Using fallback." % e)
except:
logger.error(u"PlexPy Notifier :: Unable to parse custom notification subject. Using fallback.")
try:
body_text = on_stop_body.format(**available_params)
body_text = unicode(on_stop_body).format(**available_params)
except LookupError, e:
logger.error(u"PlexPy Notifier :: Unable to parse field %s in notification body. Using fallback." % e)
except:
@@ -397,14 +397,14 @@ def build_notify_text(session, state):
if on_pause_subject and on_pause_body:
try:
subject_text = on_pause_subject.format(**available_params)
subject_text = unicode(on_pause_subject).format(**available_params)
except LookupError, e:
logger.error(u"PlexPy Notifier :: Unable to parse field %s in notification subject. Using fallback." % e)
except:
logger.error(u"PlexPy Notifier :: Unable to parse custom notification subject. Using fallback.")
try:
body_text = on_pause_body.format(**available_params)
body_text = unicode(on_pause_body).format(**available_params)
except LookupError, e:
logger.error(u"PlexPy Notifier :: Unable to parse field %s in notification body. Using fallback." % e)
except:
@@ -421,14 +421,14 @@ def build_notify_text(session, state):
if on_resume_subject and on_resume_body:
try:
subject_text = on_resume_subject.format(**available_params)
subject_text = unicode(on_resume_subject).format(**available_params)
except LookupError, e:
logger.error(u"PlexPy Notifier :: Unable to parse field %s in notification subject. Using fallback." % e)
except:
logger.error(u"PlexPy Notifier :: Unable to parse custom notification subject. Using fallback.")
try:
body_text = on_resume_body.format(**available_params)
body_text = unicode(on_resume_body).format(**available_params)
except LookupError, e:
logger.error(u"PlexPy Notifier :: Unable to parse field %s in notification body. Using fallback." % e)
except:
@@ -445,14 +445,14 @@ def build_notify_text(session, state):
if on_buffer_subject and on_buffer_body:
try:
subject_text = on_buffer_subject.format(**available_params)
subject_text = unicode(on_buffer_subject).format(**available_params)
except LookupError, e:
logger.error(u"PlexPy Notifier :: Unable to parse field %s in notification subject. Using fallback." % e)
except:
logger.error(u"PlexPy Notifier :: Unable to parse custom notification subject. Using fallback.")
try:
body_text = on_buffer_body.format(**available_params)
body_text = unicode(on_buffer_body).format(**available_params)
except LookupError, e:
logger.error(u"PlexPy Notifier :: Unable to parse field %s in notification body. Using fallback." % e)
except:
@@ -469,14 +469,14 @@ def build_notify_text(session, state):
if on_watched_subject and on_watched_body:
try:
subject_text = on_watched_subject.format(**available_params)
subject_text = unicode(on_watched_subject).format(**available_params)
except LookupError, e:
logger.error(u"PlexPy Notifier :: Unable to parse field %s in notification subject. Using fallback." % e)
except:
logger.error(u"PlexPy Notifier :: Unable to parse custom notification subject. Using fallback.")
try:
body_text = on_watched_body.format(**available_params)
body_text = unicode(on_watched_body).format(**available_params)
except LookupError, e:
logger.error(u"PlexPy Notifier :: Unable to parse field %s in notification body. Using fallback." % e)
except:

View File

@@ -49,7 +49,8 @@ AGENT_IDS = {"Growl": 0,
"Pushover": 7,
"OSX Notify": 8,
"Boxcar2": 9,
"Email": 10}
"Email": 10,
"Twitter": 11}
def available_notification_agents():
agents = [{'name': 'Growl',
@@ -171,6 +172,18 @@ def available_notification_agents():
'on_resume': plexpy.CONFIG.EMAIL_ON_RESUME,
'on_buffer': plexpy.CONFIG.EMAIL_ON_BUFFER,
'on_watched': plexpy.CONFIG.EMAIL_ON_WATCHED
},
{'name': 'Twitter',
'id': AGENT_IDS['Twitter'],
'config_prefix': 'twitter',
'has_config': True,
'state': checked(plexpy.CONFIG.TWITTER_ENABLED),
'on_play': plexpy.CONFIG.TWITTER_ON_PLAY,
'on_stop': plexpy.CONFIG.TWITTER_ON_STOP,
'on_pause': plexpy.CONFIG.TWITTER_ON_PAUSE,
'on_resume': plexpy.CONFIG.TWITTER_ON_RESUME,
'on_buffer': plexpy.CONFIG.TWITTER_ON_BUFFER,
'on_watched': plexpy.CONFIG.TWITTER_ON_WATCHED
}
]
@@ -229,6 +242,9 @@ def get_notification_agent_config(config_id):
elif config_id == 10:
email = Email()
return email.return_config_options()
elif config_id == 11:
tweet = TwitterNotifier()
return tweet.return_config_options()
else:
return []
else:
@@ -271,6 +287,9 @@ def send_notification(config_id, subject, body):
elif config_id == 10:
email = Email()
email.notify(subject=subject, message=body)
elif config_id == 11:
tweet = TwitterNotifier()
tweet.notify(subject=subject, message=body)
else:
logger.debug(u"PlexPy Notifier :: Unknown agent id received.")
else:
@@ -912,19 +931,17 @@ class TwitterNotifier(object):
SIGNIN_URL = 'https://api.twitter.com/oauth/authenticate'
def __init__(self):
self.consumer_key = "oYKnp2ddX5gbARjqX8ZAAg"
self.consumer_secret = "A4Xkw9i5SjHbTk7XT8zzOPqivhj9MmRDR9Qn95YA9sk"
self.consumer_key = "2LdJKXHDUwJtjYBsdwJisIOsh"
self.consumer_secret = "QWbUcZzAIiL4zbDCIhy2EdUkV8yEEav3qMdo5y3FugxCFelWrA"
def notify_snatch(self, title):
if plexpy.CONFIG.TWITTER_ONSNATCH:
self._notifyTwitter(common.notifyStrings[common.NOTIFY_SNATCH] + ': ' + title + ' at ' + helpers.now())
def notify_download(self, title):
if plexpy.CONFIG.TWITTER_ENABLED:
self._notifyTwitter(common.notifyStrings[common.NOTIFY_DOWNLOAD] + ': ' + title + ' at ' + helpers.now())
def notify(self, subject, message):
if not subject or not message:
return
else:
self._send_tweet(subject + ': ' + message)
def test_notify(self):
return self._notifyTwitter("This is a test notification from PlexPy at " + helpers.now(), force=True)
return self._send_tweet("This is a test notification from PlexPy at " + helpers.now())
def _get_authorization(self):
@@ -958,7 +975,7 @@ class TwitterNotifier(object):
logger.info('Generating and signing request for an access token using key ' + key)
oauth_consumer = oauth.Consumer(key=self.consumer_key, secret=self.consumer_secret)
logger.info('oauth_consumer: ' + str(oauth_consumer))
# logger.debug('oauth_consumer: ' + str(oauth_consumer))
oauth_client = oauth.Client(oauth_consumer, token)
logger.info('oauth_client: ' + str(oauth_client))
resp, content = oauth_client.request(self.ACCESS_TOKEN_URL, method='POST', body='oauth_verifier=%s' % key)
@@ -979,7 +996,6 @@ class TwitterNotifier(object):
return True
def _send_tweet(self, message=None):
username = self.consumer_key
password = self.consumer_secret
access_token_key = plexpy.CONFIG.TWITTER_USERNAME
@@ -997,13 +1013,36 @@ class TwitterNotifier(object):
return True
def _notifyTwitter(self, message='', force=False):
prefix = plexpy.CONFIG.TWITTER_PREFIX
def return_config_options(self):
config_option = [{'label': 'Request Authorisation',
'value': 'Request Authorisation',
'name': 'twitterStep1',
'description': 'Step 1: Click Request button above. (Ensure you allow the browser pop-up).',
'input_type': 'button'
},
{'label': 'Authorisation Key',
'value': '',
'name': 'twitter_key',
'description': 'Step 2: Input the authorisation key you received from Step 1.',
'input_type': 'text'
},
{'label': 'Verify Key',
'value': 'Verify Key',
'name': 'twitterStep2',
'description': 'Step 3: Verify the key.',
'input_type': 'button'
},
{'label': 'Test Twitter',
'value': 'Test Twitter',
'name': 'testTwitter',
'description': 'Test if Twitter notifications are working. See logs for troubleshooting.',
'input_type': 'button'
},
{'input_type': 'nosave'
}
]
if not plexpy.CONFIG.TWITTER_ENABLED and not force:
return False
return self._send_tweet(prefix + ": " + message)
return config_option
class OSX_NOTIFY(object):
@@ -1204,7 +1243,7 @@ class Email(object):
'input_type': 'password'
},
{'label': 'TLS',
'value': checked(plexpy.CONFIG.EMAIL_TLS),
'value': plexpy.CONFIG.EMAIL_TLS,
'name': 'email_tls',
'description': 'Does the server use encryption.',
'input_type': 'checkbox'

View File

@@ -55,6 +55,7 @@ def extract_plexwatch_xml(xml=None):
parent_title = helpers.get_xml_attr(a, 'parentTitle')
studio = helpers.get_xml_attr(a, 'studio')
title = helpers.get_xml_attr(a, 'title')
tagline = helpers.get_xml_attr(a, 'tagline')
directors = []
if a.getElementsByTagName('Director'):
@@ -153,6 +154,7 @@ def extract_plexwatch_xml(xml=None):
'grandparent_title': grandparent_title,
'parent_title': parent_title,
'title': title,
'tagline': tagline,
'guid': guid,
'media_index': media_index,
'originally_available_at': originally_available_at,
@@ -356,6 +358,7 @@ def import_from_plexwatch(database=None, table_name=None, import_ignore_interval
'last_viewed_at': extracted_xml['last_viewed_at'],
'content_rating': row['content_rating'],
'summary': row['summary'],
'tagline': extracted_xml['tagline'],
'rating': extracted_xml['rating'],
'duration': extracted_xml['duration'],
'guid': extracted_xml['guid'],

View File

@@ -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
@@ -90,31 +90,14 @@ class PmsConnect(object):
return request
"""
Return list of seasons in requested show.
Return list of children in requested library item.
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.
Parameters required: rating_key { ratingKey of parent }
Optional parameters: output_format { dict, json }
Output: array
"""
def get_episode_list(self, rating_key='', output_format=''):
def get_children_list(self, rating_key='', output_format=''):
uri = '/library/metadata/' + rating_key + '/children'
request = self.request_handler.make_request(uri=uri,
proto=self.protocol,
@@ -362,6 +345,7 @@ class PmsConnect(object):
'title': helpers.get_xml_attr(metadata_main, 'title'),
'content_rating': helpers.get_xml_attr(metadata_main, 'contentRating'),
'summary': helpers.get_xml_attr(metadata_main, 'summary'),
'tagline': helpers.get_xml_attr(metadata_main, 'tagline'),
'rating': helpers.get_xml_attr(metadata_main, 'rating'),
'duration': helpers.get_xml_attr(metadata_main, 'duration'),
'year': helpers.get_xml_attr(metadata_main, 'year'),
@@ -380,9 +364,44 @@ class PmsConnect(object):
'actors': actors
}
metadata_list = {'metadata': metadata}
elif metadata_type == 'season':
parent_rating_key = helpers.get_xml_attr(metadata_main, 'parentRatingKey')
show_details = self.get_metadata_details(parent_rating_key)
metadata = {'type': metadata_type,
'rating_key': helpers.get_xml_attr(metadata_main, 'ratingKey'),
'parent_rating_key': helpers.get_xml_attr(metadata_main, 'parentRatingKey'),
'grandparent_title': helpers.get_xml_attr(metadata_main, 'grandparentTitle'),
'parent_index': helpers.get_xml_attr(metadata_main, 'parentIndex'),
'parent_title': helpers.get_xml_attr(metadata_main, 'parentTitle'),
'index': helpers.get_xml_attr(metadata_main, 'index'),
'studio': helpers.get_xml_attr(metadata_main, 'studio'),
'title': helpers.get_xml_attr(metadata_main, 'title'),
'content_rating': helpers.get_xml_attr(metadata_main, 'contentRating'),
'summary': show_details['metadata']['summary'],
'tagline': helpers.get_xml_attr(metadata_main, 'tagline'),
'rating': helpers.get_xml_attr(metadata_main, 'rating'),
'duration': show_details['metadata']['duration'],
'year': helpers.get_xml_attr(metadata_main, 'year'),
'thumb': helpers.get_xml_attr(metadata_main, 'thumb'),
'parent_thumb': helpers.get_xml_attr(metadata_main, 'parentThumb'),
'grandparent_thumb': helpers.get_xml_attr(metadata_main, 'grandparentThumb'),
'art': helpers.get_xml_attr(metadata_main, 'art'),
'originally_available_at': helpers.get_xml_attr(metadata_main, 'originallyAvailableAt'),
'added_at': helpers.get_xml_attr(metadata_main, 'addedAt'),
'updated_at': helpers.get_xml_attr(metadata_main, 'updatedAt'),
'last_viewed_at': helpers.get_xml_attr(metadata_main, 'lastViewedAt'),
'guid': helpers.get_xml_attr(metadata_main, 'guid'),
'genres': genres,
'actors': actors,
'writers': writers,
'directors': directors
}
metadata_list = {'metadata': metadata}
elif metadata_type == 'episode':
metadata = {'type': metadata_type,
'rating_key': helpers.get_xml_attr(metadata_main, 'ratingKey'),
'parent_rating_key': helpers.get_xml_attr(metadata_main, 'parentRatingKey'),
'grandparent_rating_key': helpers.get_xml_attr(metadata_main, 'grandparentRatingKey'),
'grandparent_title': helpers.get_xml_attr(metadata_main, 'grandparentTitle'),
'parent_index': helpers.get_xml_attr(metadata_main, 'parentIndex'),
'parent_title': helpers.get_xml_attr(metadata_main, 'parentTitle'),
@@ -391,6 +410,7 @@ class PmsConnect(object):
'title': helpers.get_xml_attr(metadata_main, 'title'),
'content_rating': helpers.get_xml_attr(metadata_main, 'contentRating'),
'summary': helpers.get_xml_attr(metadata_main, 'summary'),
'tagline': helpers.get_xml_attr(metadata_main, 'tagline'),
'rating': helpers.get_xml_attr(metadata_main, 'rating'),
'duration': helpers.get_xml_attr(metadata_main, 'duration'),
'year': helpers.get_xml_attr(metadata_main, 'year'),
@@ -420,6 +440,7 @@ class PmsConnect(object):
'title': helpers.get_xml_attr(metadata_main, 'title'),
'content_rating': helpers.get_xml_attr(metadata_main, 'contentRating'),
'summary': helpers.get_xml_attr(metadata_main, 'summary'),
'tagline': helpers.get_xml_attr(metadata_main, 'tagline'),
'rating': helpers.get_xml_attr(metadata_main, 'rating'),
'duration': helpers.get_xml_attr(metadata_main, 'duration'),
'year': helpers.get_xml_attr(metadata_main, 'year'),
@@ -438,9 +459,7 @@ class PmsConnect(object):
'directors': directors
}
metadata_list = {'metadata': metadata}
elif metadata_type == 'season':
parent_rating_key = helpers.get_xml_attr(metadata_main, 'parentRatingKey')
show_details = self.get_metadata_details(parent_rating_key)
elif metadata_type == 'artist':
metadata = {'type': metadata_type,
'rating_key': helpers.get_xml_attr(metadata_main, 'ratingKey'),
'grandparent_title': helpers.get_xml_attr(metadata_main, 'grandparentTitle'),
@@ -450,9 +469,43 @@ class PmsConnect(object):
'studio': helpers.get_xml_attr(metadata_main, 'studio'),
'title': helpers.get_xml_attr(metadata_main, 'title'),
'content_rating': helpers.get_xml_attr(metadata_main, 'contentRating'),
'summary': show_details['metadata']['summary'],
'summary': helpers.get_xml_attr(metadata_main, 'summary'),
'tagline': helpers.get_xml_attr(metadata_main, 'tagline'),
'rating': helpers.get_xml_attr(metadata_main, 'rating'),
'duration': show_details['metadata']['duration'],
'duration': helpers.get_xml_attr(metadata_main, 'duration'),
'year': helpers.get_xml_attr(metadata_main, 'year'),
'thumb': helpers.get_xml_attr(metadata_main, 'thumb'),
'parent_thumb': helpers.get_xml_attr(metadata_main, 'parentThumb'),
'grandparent_thumb': helpers.get_xml_attr(metadata_main, 'grandparentThumb'),
'art': helpers.get_xml_attr(metadata_main, 'art'),
'originally_available_at': helpers.get_xml_attr(metadata_main, 'originallyAvailableAt'),
'added_at': helpers.get_xml_attr(metadata_main, 'addedAt'),
'updated_at': helpers.get_xml_attr(metadata_main, 'updatedAt'),
'last_viewed_at': helpers.get_xml_attr(metadata_main, 'lastViewedAt'),
'guid': helpers.get_xml_attr(metadata_main, 'guid'),
'writers': writers,
'directors': directors,
'genres': genres,
'actors': actors
}
metadata_list = {'metadata': metadata}
elif metadata_type == 'album':
parent_rating_key = helpers.get_xml_attr(metadata_main, 'parentRatingKey')
artist_details = self.get_metadata_details(parent_rating_key)
metadata = {'type': metadata_type,
'rating_key': helpers.get_xml_attr(metadata_main, 'ratingKey'),
'parent_rating_key': helpers.get_xml_attr(metadata_main, 'parentRatingKey'),
'grandparent_title': helpers.get_xml_attr(metadata_main, 'grandparentTitle'),
'parent_index': helpers.get_xml_attr(metadata_main, 'parentIndex'),
'parent_title': helpers.get_xml_attr(metadata_main, 'parentTitle'),
'index': helpers.get_xml_attr(metadata_main, 'index'),
'studio': helpers.get_xml_attr(metadata_main, 'studio'),
'title': helpers.get_xml_attr(metadata_main, 'title'),
'content_rating': helpers.get_xml_attr(metadata_main, 'contentRating'),
'summary': artist_details['metadata']['summary'],
'tagline': helpers.get_xml_attr(metadata_main, 'tagline'),
'rating': helpers.get_xml_attr(metadata_main, 'rating'),
'duration': helpers.get_xml_attr(metadata_main, 'duration'),
'year': helpers.get_xml_attr(metadata_main, 'year'),
'thumb': helpers.get_xml_attr(metadata_main, 'thumb'),
'parent_thumb': helpers.get_xml_attr(metadata_main, 'parentThumb'),
@@ -470,8 +523,12 @@ class PmsConnect(object):
}
metadata_list = {'metadata': metadata}
elif metadata_type == 'track':
parent_rating_key = helpers.get_xml_attr(metadata_main, 'parentRatingKey')
album_details = self.get_metadata_details(parent_rating_key)
metadata = {'type': metadata_type,
'rating_key': helpers.get_xml_attr(metadata_main, 'ratingKey'),
'parent_rating_key': helpers.get_xml_attr(metadata_main, 'parentRatingKey'),
'grandparent_rating_key': helpers.get_xml_attr(metadata_main, 'grandparentRatingKey'),
'grandparent_title': helpers.get_xml_attr(metadata_main, 'grandparentTitle'),
'parent_index': helpers.get_xml_attr(metadata_main, 'parentIndex'),
'parent_title': helpers.get_xml_attr(metadata_main, 'parentTitle'),
@@ -480,9 +537,10 @@ class PmsConnect(object):
'title': helpers.get_xml_attr(metadata_main, 'title'),
'content_rating': helpers.get_xml_attr(metadata_main, 'contentRating'),
'summary': helpers.get_xml_attr(metadata_main, 'summary'),
'tagline': helpers.get_xml_attr(metadata_main, 'tagline'),
'rating': helpers.get_xml_attr(metadata_main, 'rating'),
'duration': helpers.get_xml_attr(metadata_main, 'duration'),
'year': helpers.get_xml_attr(metadata_main, 'year'),
'year': album_details['metadata']['year'],
'thumb': helpers.get_xml_attr(metadata_main, 'thumb'),
'parent_thumb': helpers.get_xml_attr(metadata_main, 'parentThumb'),
'grandparent_thumb': helpers.get_xml_attr(metadata_main, 'grandparentThumb'),
@@ -539,6 +597,12 @@ class PmsConnect(object):
for session in session_data:
session_output = self.get_session_each(session_type, session)
session_list.append(session_output)
if a.getElementsByTagName('Photo'):
session_data = a.getElementsByTagName('Photo')
session_type = 'photo'
for session in session_data:
session_output = self.get_session_each(session_type, session)
session_list.append(session_output)
output = {'stream_count': helpers.get_xml_attr(xml_head[0], 'size'),
'sessions': session_list
@@ -557,8 +621,8 @@ class PmsConnect(object):
def get_session_each(self, stream_type='', session=None):
session_output = None
user_data = users.Users()
if stream_type == 'track':
if stream_type == 'track':
media_info = session.getElementsByTagName('Media')[0]
audio_decision = 'direct play'
audio_channels = helpers.get_xml_attr(media_info, 'audioChannels')
@@ -570,6 +634,9 @@ class PmsConnect(object):
if session.getElementsByTagName('TranscodeSession'):
transcode_session = session.getElementsByTagName('TranscodeSession')[0]
throttled = helpers.get_xml_attr(transcode_session, 'throttled')
transcode_progress = helpers.get_xml_attr(transcode_session, 'progress')
transcode_speed = helpers.get_xml_attr(transcode_session, 'speed')
audio_decision = helpers.get_xml_attr(transcode_session, 'audioDecision')
transcode_audio_channels = helpers.get_xml_attr(transcode_session, 'audioChannels')
transcode_audio_codec = helpers.get_xml_attr(transcode_session, 'audioCodec')
@@ -577,6 +644,9 @@ class PmsConnect(object):
transcode_protocol = helpers.get_xml_attr(transcode_session, 'protocol')
duration = helpers.get_xml_attr(transcode_session, 'duration')
else:
throttled = '0'
transcode_progress = '0'
transcode_speed = ''
transcode_audio_channels = ''
transcode_audio_codec = ''
transcode_container = ''
@@ -612,6 +682,9 @@ class PmsConnect(object):
'rating_key': helpers.get_xml_attr(session, 'ratingKey'),
'parent_rating_key': helpers.get_xml_attr(session, 'parentRatingKey'),
'grandparent_rating_key': helpers.get_xml_attr(session, 'grandparentRatingKey'),
'throttled': throttled,
'transcode_progress': transcode_progress,
'transcode_speed': str(round(helpers.cast_to_float(transcode_speed), 1)),
'audio_decision': audio_decision,
'audio_channels': audio_channels,
'audio_codec': audio_codec,
@@ -637,6 +710,7 @@ class PmsConnect(object):
'type': 'track',
'indexes': 0
}
elif stream_type == 'video':
media_info = session.getElementsByTagName('Media')[0]
audio_decision = 'direct play'
@@ -656,6 +730,9 @@ class PmsConnect(object):
if session.getElementsByTagName('TranscodeSession'):
transcode_session = session.getElementsByTagName('TranscodeSession')[0]
throttled = helpers.get_xml_attr(transcode_session, 'throttled')
transcode_progress = helpers.get_xml_attr(transcode_session, 'progress')
transcode_speed = helpers.get_xml_attr(transcode_session, 'speed')
audio_decision = helpers.get_xml_attr(transcode_session, 'audioDecision')
transcode_audio_channels = helpers.get_xml_attr(transcode_session, 'audioChannels')
transcode_audio_codec = helpers.get_xml_attr(transcode_session, 'audioCodec')
@@ -666,6 +743,9 @@ class PmsConnect(object):
transcode_container = helpers.get_xml_attr(transcode_session, 'container')
transcode_protocol = helpers.get_xml_attr(transcode_session, 'protocol')
else:
throttled = '0'
transcode_progress = '0'
transcode_speed = ''
transcode_audio_channels = ''
transcode_audio_codec = ''
transcode_video_codec = ''
@@ -723,6 +803,9 @@ class PmsConnect(object):
'rating_key': helpers.get_xml_attr(session, 'ratingKey'),
'parent_rating_key': helpers.get_xml_attr(session, 'parentRatingKey'),
'grandparent_rating_key': helpers.get_xml_attr(session, 'grandparentRatingKey'),
'throttled': throttled,
'transcode_progress': transcode_progress,
'transcode_speed': str(round(helpers.cast_to_float(transcode_speed), 1)),
'audio_decision': audio_decision,
'audio_channels': audio_channels,
'audio_codec': audio_codec,
@@ -776,6 +859,9 @@ class PmsConnect(object):
'rating_key': helpers.get_xml_attr(session, 'ratingKey'),
'parent_rating_key': helpers.get_xml_attr(session, 'parentRatingKey'),
'grandparent_rating_key': helpers.get_xml_attr(session, 'grandparentRatingKey'),
'throttled': throttled,
'transcode_progress': transcode_progress,
'transcode_speed': str(round(helpers.cast_to_float(transcode_speed), 1)),
'audio_decision': audio_decision,
'audio_channels': audio_channels,
'audio_codec': audio_codec,
@@ -829,6 +915,9 @@ class PmsConnect(object):
'rating_key': helpers.get_xml_attr(session, 'ratingKey'),
'parent_rating_key': helpers.get_xml_attr(session, 'parentRatingKey'),
'grandparent_rating_key': helpers.get_xml_attr(session, 'grandparentRatingKey'),
'throttled': throttled,
'transcode_progress': transcode_progress,
'transcode_speed': str(round(helpers.cast_to_float(transcode_speed), 1)),
'audio_decision': audio_decision,
'audio_channels': audio_channels,
'audio_codec': audio_codec,
@@ -854,92 +943,151 @@ class PmsConnect(object):
'type': helpers.get_xml_attr(session, 'type'),
'indexes': 0
}
elif stream_type == 'photo':
media_info = session.getElementsByTagName('Media')[0]
video_decision = 'direct play'
container = helpers.get_xml_attr(media_info, 'container')
aspect_ratio = helpers.get_xml_attr(media_info, 'aspectRatio')
width = helpers.get_xml_attr(media_info, 'width')
height = helpers.get_xml_attr(media_info, 'height')
if session.getElementsByTagName('TranscodeSession'):
transcode_session = session.getElementsByTagName('TranscodeSession')[0]
throttled = helpers.get_xml_attr(transcode_session, 'throttled')
transcode_progress = helpers.get_xml_attr(transcode_session, 'progress')
transcode_speed = helpers.get_xml_attr(transcode_session, 'speed')
video_decision = helpers.get_xml_attr(transcode_session, 'videoDecision')
transcode_video_codec = helpers.get_xml_attr(transcode_session, 'videoCodec')
transcode_width = helpers.get_xml_attr(transcode_session, 'width')
transcode_height = helpers.get_xml_attr(transcode_session, 'height')
transcode_container = helpers.get_xml_attr(transcode_session, 'container')
transcode_protocol = helpers.get_xml_attr(transcode_session, 'protocol')
else:
throttled = '0'
transcode_progress = '0'
transcode_speed = ''
transcode_video_codec = ''
transcode_width = ''
transcode_height = ''
transcode_container = ''
transcode_protocol = ''
user_details = user_data.get_user_details(
user=helpers.get_xml_attr(session.getElementsByTagName('User')[0], 'title'))
if helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'machineIdentifier').endswith('_Photo'):
machine_id = helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'machineIdentifier')[:-6]
else:
machine_id = helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'machineIdentifier')
session_output = {'session_key': helpers.get_xml_attr(session, 'sessionKey'),
'media_index': helpers.get_xml_attr(session, 'index'),
'parent_media_index': helpers.get_xml_attr(session, 'parentIndex'),
'art': helpers.get_xml_attr(session, 'art'),
'parent_thumb': helpers.get_xml_attr(session, 'parentThumb'),
'grandparent_thumb': helpers.get_xml_attr(session, 'grandparentThumb'),
'thumb': helpers.get_xml_attr(session, 'thumb'),
'bif_thumb': '',
'user': user_details['username'],
'user_id': user_details['user_id'],
'friendly_name': user_details['friendly_name'],
'user_thumb': user_details['thumb'],
'player': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'title'),
'platform': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'platform'),
'machine_id': machine_id,
'state': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'state'),
'grandparent_title': helpers.get_xml_attr(session, 'grandparentTitle'),
'parent_title': helpers.get_xml_attr(session, 'parentTitle'),
'title': helpers.get_xml_attr(session, 'title'),
'year': helpers.get_xml_attr(session, 'year'),
'rating_key': helpers.get_xml_attr(session, 'ratingKey'),
'parent_rating_key': helpers.get_xml_attr(session, 'parentRatingKey'),
'grandparent_rating_key': helpers.get_xml_attr(session, 'grandparentRatingKey'),
'throttled': throttled,
'transcode_progress': transcode_progress,
'transcode_speed': str(round(helpers.cast_to_float(transcode_speed), 1)),
'audio_decision': '',
'audio_channels': '',
'audio_codec': '',
'video_decision': video_decision,
'video_codec': '',
'height': height,
'width': width,
'container': container,
'bitrate': '',
'video_resolution': '',
'video_framerate': '',
'aspect_ratio': aspect_ratio,
'transcode_audio_channels': '',
'transcode_audio_codec': '',
'transcode_video_codec': transcode_video_codec,
'transcode_width': transcode_width,
'transcode_height': transcode_height,
'transcode_container': transcode_container,
'transcode_protocol': transcode_protocol,
'duration': '',
'progress': '',
'progress_percent': '100',
'type': 'photo',
'indexes': 0
}
else:
logger.warn(u"No known stream types found in session list.")
return session_output
"""
Return processed and validated season list.
Return processed and validated children list.
Output: array
"""
def get_show_children(self, rating_key=''):
season_data = self.get_season_list(rating_key, output_format='xml')
def get_item_children(self, rating_key=''):
children_data = self.get_children_list(rating_key, output_format='xml')
try:
xml_head = season_data.getElementsByTagName('MediaContainer')
xml_head = children_data.getElementsByTagName('MediaContainer')
except:
logger.warn("Unable to parse XML for get_season_list.")
logger.warn("Unable to parse XML for get_children_list.")
return []
season_list = []
children_list = []
for a in xml_head:
if a.getAttribute('size'):
if a.getAttribute('size') == '0':
logger.debug(u"No season data.")
season_list = {'season_count': '0',
'season_list': []
}
return season_list
logger.debug(u"No children data.")
children_list = {'children_count': '0',
'children_list': []
}
return parent_list
result_data = []
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.
Output: array
"""
def get_season_children(self, rating_key=''):
episode_data = self.get_episode_list(rating_key, output_format='xml')
try:
xml_head = episode_data.getElementsByTagName('MediaContainer')
except:
logger.warn("Unable to parse XML for get_episode_list.")
return []
episode_list = []
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 = {'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')
}
episode_list.append(episode_output)
if a.getElementsByTagName('Track'):
result_data = a.getElementsByTagName('Track')
output = {'episode_count': helpers.get_xml_attr(xml_head[0], 'size'),
if result_data:
for result in result_data:
children_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'),
'duration': helpers.get_xml_attr(result, 'duration')
}
children_list.append(children_output)
output = {'children_count': helpers.get_xml_attr(xml_head[0], 'size'),
'children_type': helpers.get_xml_attr(xml_head[0], 'viewGroup'),
'title': helpers.get_xml_attr(xml_head[0], 'title2'),
'episode_list': episode_list
'children_list': children_list
}
return output
@@ -1060,7 +1208,7 @@ class PmsConnect(object):
'title': helpers.get_xml_attr(xml_head[0], 'title1'),
'libraries_list': libraries_list
}
return output
"""
@@ -1122,11 +1270,11 @@ class PmsConnect(object):
return output
"""
Return processed and validated server statistics.
Return processed and validated library statistics.
Output: array
"""
def get_library_stats(self):
def get_library_stats(self, library_cards=''):
server_libraries = self.get_server_children()
server_library_stats = []
@@ -1137,7 +1285,10 @@ class PmsConnect(object):
for library in libraries_list:
library_type = library['type']
section_key = library['key']
library_list = self.get_library_children(library_type, section_key)
if section_key in library_cards:
library_list = self.get_library_children(library_type, section_key)
else:
continue
if library_list['library_count'] != '0':
library_stats = {'title': library['title'],

View File

@@ -1,2 +1,2 @@
PLEXPY_VERSION = "master"
PLEXPY_RELEASE_VERSION = "1.1.6"
PLEXPY_RELEASE_VERSION = "1.1.10"

View File

@@ -66,9 +66,9 @@ class WebInterface(object):
def home(self):
config = {
"home_stats_length": plexpy.CONFIG.HOME_STATS_LENGTH,
"home_stats_type": plexpy.CONFIG.HOME_STATS_TYPE,
"home_stats_count": plexpy.CONFIG.HOME_STATS_COUNT,
"pms_identifier": plexpy.CONFIG.PMS_IDENTIFIER,
"home_stats_cards": plexpy.CONFIG.HOME_STATS_CARDS,
"home_library_cards": plexpy.CONFIG.HOME_LIBRARY_CARDS,
"pms_identifier": plexpy.CONFIG.PMS_IDENTIFIER
}
return serve_template(templatename="index.html", title="Home", config=config)
@@ -121,16 +121,41 @@ class WebInterface(object):
return json.dumps(formats)
@cherrypy.expose
def home_stats(self, time_range='30', stat_type='0', stat_count='5', **kwargs):
def home_stats(self, **kwargs):
data_factory = datafactory.DataFactory()
stats_data = data_factory.get_home_stats(time_range=time_range, stat_type=stat_type, stat_count=stat_count)
time_range = plexpy.CONFIG.HOME_STATS_LENGTH
stats_type = plexpy.CONFIG.HOME_STATS_TYPE
stats_count = plexpy.CONFIG.HOME_STATS_COUNT
stats_cards = plexpy.CONFIG.HOME_STATS_CARDS.split(', ')
notify_watched_percent = plexpy.CONFIG.NOTIFY_WATCHED_PERCENT
stats_data = data_factory.get_home_stats(time_range=time_range,
stats_type=stats_type,
stats_count=stats_count,
stats_cards=stats_cards,
notify_watched_percent=notify_watched_percent)
return serve_template(templatename="home_stats.html", title="Stats", data=stats_data)
@cherrypy.expose
def library_stats(self, **kwargs):
pms_connect = pmsconnect.PmsConnect()
stats_data = pms_connect.get_library_stats()
library_cards = plexpy.CONFIG.HOME_LIBRARY_CARDS.split(', ')
if library_cards == ['library_statistics_first']:
library_cards = ['library_statistics']
server_children = pms_connect.get_server_children()
server_libraries = server_children['libraries_list']
for library in server_libraries:
library_cards.append(library['key'])
plexpy.CONFIG.HOME_LIBRARY_CARDS = ', '.join(library_cards)
plexpy.CONFIG.write()
stats_data = pms_connect.get_library_stats(library_cards=library_cards)
return serve_template(templatename="library_stats.html", title="Library Stats", data=stats_data)
@@ -144,7 +169,12 @@ class WebInterface(object):
@cherrypy.expose
def graphs(self):
return serve_template(templatename="graphs.html", title="Graphs")
config = {
"music_logging_enable": plexpy.CONFIG.MUSIC_LOGGING_ENABLE
}
return serve_template(templatename="graphs.html", title="Graphs", config=config)
@cherrypy.expose
def sync(self):
@@ -373,46 +403,7 @@ class WebInterface(object):
"cache_dir": plexpy.CONFIG.CACHE_DIR,
"check_github": checked(plexpy.CONFIG.CHECK_GITHUB),
"interface_list": interface_list,
"growl_enabled": checked(plexpy.CONFIG.GROWL_ENABLED),
"growl_host": plexpy.CONFIG.GROWL_HOST,
"growl_password": plexpy.CONFIG.GROWL_PASSWORD,
"prowl_enabled": checked(plexpy.CONFIG.PROWL_ENABLED),
"prowl_keys": plexpy.CONFIG.PROWL_KEYS,
"prowl_priority": plexpy.CONFIG.PROWL_PRIORITY,
"xbmc_enabled": checked(plexpy.CONFIG.XBMC_ENABLED),
"xbmc_host": plexpy.CONFIG.XBMC_HOST,
"xbmc_username": plexpy.CONFIG.XBMC_USERNAME,
"xbmc_password": plexpy.CONFIG.XBMC_PASSWORD,
"plex_enabled": checked(plexpy.CONFIG.PLEX_ENABLED),
"plex_client_host": plexpy.CONFIG.PLEX_CLIENT_HOST,
"plex_username": plexpy.CONFIG.PLEX_USERNAME,
"plex_password": plexpy.CONFIG.PLEX_PASSWORD,
"nma_enabled": checked(plexpy.CONFIG.NMA_ENABLED),
"nma_apikey": plexpy.CONFIG.NMA_APIKEY,
"nma_priority": int(plexpy.CONFIG.NMA_PRIORITY),
"pushalot_enabled": checked(plexpy.CONFIG.PUSHALOT_ENABLED),
"pushalot_apikey": plexpy.CONFIG.PUSHALOT_APIKEY,
"pushover_enabled": checked(plexpy.CONFIG.PUSHOVER_ENABLED),
"pushover_keys": plexpy.CONFIG.PUSHOVER_KEYS,
"pushover_apitoken": plexpy.CONFIG.PUSHOVER_APITOKEN,
"pushover_priority": plexpy.CONFIG.PUSHOVER_PRIORITY,
"pushbullet_enabled": checked(plexpy.CONFIG.PUSHBULLET_ENABLED),
"pushbullet_apikey": plexpy.CONFIG.PUSHBULLET_APIKEY,
"pushbullet_deviceid": plexpy.CONFIG.PUSHBULLET_DEVICEID,
"twitter_enabled": checked(plexpy.CONFIG.TWITTER_ENABLED),
"osx_notify_enabled": checked(plexpy.CONFIG.OSX_NOTIFY_ENABLED),
"osx_notify_app": plexpy.CONFIG.OSX_NOTIFY_APP,
"boxcar_enabled": checked(plexpy.CONFIG.BOXCAR_ENABLED),
"boxcar_token": plexpy.CONFIG.BOXCAR_TOKEN,
"cache_sizemb": plexpy.CONFIG.CACHE_SIZEMB,
"email_enabled": checked(plexpy.CONFIG.EMAIL_ENABLED),
"email_from": plexpy.CONFIG.EMAIL_FROM,
"email_to": plexpy.CONFIG.EMAIL_TO,
"email_smtp_server": plexpy.CONFIG.EMAIL_SMTP_SERVER,
"email_smtp_user": plexpy.CONFIG.EMAIL_SMTP_USER,
"email_smtp_password": plexpy.CONFIG.EMAIL_SMTP_PASSWORD,
"email_smtp_port": int(plexpy.CONFIG.EMAIL_SMTP_PORT),
"email_tls": checked(plexpy.CONFIG.EMAIL_TLS),
"pms_identifier": plexpy.CONFIG.PMS_IDENTIFIER,
"pms_ip": plexpy.CONFIG.PMS_IP,
"pms_logs_folder": plexpy.CONFIG.PMS_LOGS_FOLDER,
@@ -421,7 +412,6 @@ class WebInterface(object):
"pms_ssl": checked(plexpy.CONFIG.PMS_SSL),
"pms_use_bif": checked(plexpy.CONFIG.PMS_USE_BIF),
"pms_uuid": plexpy.CONFIG.PMS_UUID,
"plexwatch_database": plexpy.CONFIG.PLEXWATCH_DATABASE,
"date_format": plexpy.CONFIG.DATE_FORMAT,
"time_format": plexpy.CONFIG.TIME_FORMAT,
"grouping_global_history": checked(plexpy.CONFIG.GROUPING_GLOBAL_HISTORY),
@@ -463,6 +453,8 @@ class WebInterface(object):
"home_stats_length": plexpy.CONFIG.HOME_STATS_LENGTH,
"home_stats_type": checked(plexpy.CONFIG.HOME_STATS_TYPE),
"home_stats_count": plexpy.CONFIG.HOME_STATS_COUNT,
"home_stats_cards": plexpy.CONFIG.HOME_STATS_CARDS,
"home_library_cards": plexpy.CONFIG.HOME_LIBRARY_CARDS,
"buffer_threshold": plexpy.CONFIG.BUFFER_THRESHOLD,
"buffer_wait": plexpy.CONFIG.BUFFER_WAIT
}
@@ -474,12 +466,7 @@ class WebInterface(object):
# Handle the variable config options. Note - keys with False values aren't getting passed
checked_configs = [
"launch_browser", "enable_https", "api_enabled", "freeze_db", "growl_enabled",
"prowl_enabled", "xbmc_enabled", "check_github",
"plex_enabled", "nma_enabled", "pushalot_enabled",
"pushover_enabled", "pushbullet_enabled",
"twitter_enabled", "osx_notify_enabled",
"boxcar_enabled", "email_enabled", "email_tls",
"launch_browser", "enable_https", "api_enabled", "freeze_db", "check_github",
"grouping_global_history", "grouping_user_history", "grouping_charts", "pms_use_bif", "pms_ssl",
"tv_notify_enable", "movie_notify_enable", "music_notify_enable",
"tv_notify_on_start", "movie_notify_on_start", "music_notify_on_start",
@@ -515,6 +502,14 @@ class WebInterface(object):
if kwargs['pms_ip'] != plexpy.CONFIG.PMS_IP:
refresh_users = True
if 'home_stats_cards' in kwargs:
if kwargs['home_stats_cards'] != 'watch_statistics':
kwargs['home_stats_cards'] = ', '.join(kwargs['home_stats_cards'])
if 'home_library_cards' in kwargs:
if kwargs['home_library_cards'] != 'library_statistics':
kwargs['home_library_cards'] = ', '.join(kwargs['home_library_cards'])
plexpy.CONFIG.process_kwargs(kwargs)
# Write the config
@@ -535,15 +530,6 @@ class WebInterface(object):
@cherrypy.expose
def set_notification_config(self, **kwargs):
# Handle the variable config options. Note - keys with False values aren't getting passed
checked_configs = [
"email_tls"
]
for checked_config in checked_configs:
if checked_config not in kwargs:
# checked items should be zero or one. if they were not sent then the item was not checked
kwargs[checked_config] = 0
for plain_config, use_config in [(x[4:], x) for x in kwargs if x.startswith('use_')]:
# the use prefix is fairly nice in the html, but does not match the actual config
@@ -762,6 +748,10 @@ class WebInterface(object):
def info(self, item_id=None, source=None, **kwargs):
metadata = None
config = {
"pms_identifier": plexpy.CONFIG.PMS_IDENTIFIER
}
if source == 'history':
data_factory = datafactory.DataFactory()
metadata = data_factory.get_metadata_details(row_id=item_id)
@@ -772,7 +762,7 @@ class WebInterface(object):
metadata = result['metadata']
if metadata:
return serve_template(templatename="info.html", data=metadata, title="Info")
return serve_template(templatename="info.html", data=metadata, title="Info", config=config)
else:
logger.warn('Unable to retrieve data.')
return serve_template(templatename="info.html", data=None, title="Info")
@@ -817,28 +807,16 @@ class WebInterface(object):
return serve_template(templatename="user_platform_stats.html", data=None, title="Platform Stats")
@cherrypy.expose
def get_show_children(self, rating_key='', **kwargs):
def get_item_children(self, rating_key='', **kwargs):
pms_connect = pmsconnect.PmsConnect()
result = pms_connect.get_show_children(rating_key)
result = pms_connect.get_item_children(rating_key)
if result:
return serve_template(templatename="info_season_list.html", data=result, title="Season List")
return serve_template(templatename="info_children_list.html", data=result, title="Children 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)
if result:
return serve_template(templatename="info_episode_list.html", data=result, title="Episode List")
else:
logger.warn('Unable to retrieve data.')
return serve_template(templatename="info_episode_list.html", data=None, title="Episode List")
return serve_template(templatename="info_children_list.html", data=None, title="Children List")
@cherrypy.expose
def get_metadata_json(self, rating_key='', **kwargs):
@@ -1120,6 +1098,18 @@ class WebInterface(object):
else:
logger.warn('Unable to retrieve data.')
@cherrypy.expose
def get_server_children(self, **kwargs):
pms_connect = pmsconnect.PmsConnect()
result = pms_connect.get_server_children()
if result:
cherrypy.response.headers['Content-type'] = 'application/json'
return json.dumps(result)
else:
logger.warn('Unable to retrieve data.')
@cherrypy.expose
def get_activity(self, **kwargs):