Compare commits
79 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
1761b14fe9 | ||
![]() |
8792aa6c70 | ||
![]() |
34e548cc15 | ||
![]() |
9c955771c0 | ||
![]() |
0c6ccc5d52 | ||
![]() |
7c6619ebc5 | ||
![]() |
22ed8a3a95 | ||
![]() |
924ed70458 | ||
![]() |
de4d8fb277 | ||
![]() |
d61e699dc9 | ||
![]() |
ad183ff9fe | ||
![]() |
078f4babf5 | ||
![]() |
8a989d71ca | ||
![]() |
78f959d39a | ||
![]() |
20056718db | ||
![]() |
6eec4d1ca6 | ||
![]() |
483f5825db | ||
![]() |
d23aaf91f7 | ||
![]() |
1f3a238ab2 | ||
![]() |
7170dbd800 | ||
![]() |
048b31c87a | ||
![]() |
e386d3ee21 | ||
![]() |
285946bf94 | ||
![]() |
578ba52215 | ||
![]() |
5126c39c26 | ||
![]() |
5ec9e41244 | ||
![]() |
5eebf6592a | ||
![]() |
7994351644 | ||
![]() |
e445228b8a | ||
![]() |
46e6250329 | ||
![]() |
2edfc1e3da | ||
![]() |
f2024b0854 | ||
![]() |
5f2cf6cb7a | ||
![]() |
73664b6a03 | ||
![]() |
af131ce16d | ||
![]() |
414c4c2ffa | ||
![]() |
d2cdc2cea2 | ||
![]() |
b860f9a5e8 | ||
![]() |
e5535b6167 | ||
![]() |
6359c02c80 | ||
![]() |
1c589fbefa | ||
![]() |
b768ad8a19 | ||
![]() |
60878ed12e | ||
![]() |
328d744efd | ||
![]() |
92a868c3c6 | ||
![]() |
7b9210a5fc | ||
![]() |
fb872596d6 | ||
![]() |
a43efef28a | ||
![]() |
e30e6dfe35 | ||
![]() |
eaadd5e2d6 | ||
![]() |
c608c7c9fc | ||
![]() |
451485d706 | ||
![]() |
849675185d | ||
![]() |
b060a23733 | ||
![]() |
bee9091182 | ||
![]() |
f8e1ba6798 | ||
![]() |
e5ce57fead | ||
![]() |
c9e2d1d200 | ||
![]() |
88b6eae3bf | ||
![]() |
c7d6ee8021 | ||
![]() |
7480508af2 | ||
![]() |
3fcc44aacf | ||
![]() |
fcc4575a86 | ||
![]() |
ebd0276eae | ||
![]() |
35521e127f | ||
![]() |
2c83554631 | ||
![]() |
56b717b1a1 | ||
![]() |
56f601e2a5 | ||
![]() |
3867dd7bdd | ||
![]() |
b7dc28c3fb | ||
![]() |
e6383d52ad | ||
![]() |
0a2ebb8815 | ||
![]() |
e44a0fed22 | ||
![]() |
2d7585d64b | ||
![]() |
df290d995b | ||
![]() |
36ee5234b1 | ||
![]() |
48e601d5ff | ||
![]() |
84aa727387 | ||
![]() |
29204cb6ba |
44
CHANGELOG.md
44
CHANGELOG.md
@@ -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.
|
||||
|
@@ -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')
|
||||
|
@@ -1,5 +1,7 @@
|
||||
#PlexPy
|
||||
|
||||
[](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.
|
||||
|
@@ -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:
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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 <strong>Direct Play</strong>
|
||||
% elif a['audio_decision'] == 'copy':
|
||||
Stream <strong>Direct Stream</strong>
|
||||
% else:
|
||||
Stream <strong>Transcoding</strong>
|
||||
Stream <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 <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 <strong>Direct Play</strong>
|
||||
% elif a['video_decision'] == 'copy' and a['audio_decision'] == 'copy':
|
||||
Stream <strong>Direct Stream</strong>
|
||||
% else:
|
||||
Stream <strong>Transcoding</strong>
|
||||
Stream <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 <strong>Transcode (${a['transcode_audio_codec']}) (${a['transcode_audio_channels']}ch)</strong>
|
||||
% endif
|
||||
% elif a['type'] == 'photo':
|
||||
% if a['video_decision'] == 'direct play':
|
||||
Stream <strong>Direct Play</strong>
|
||||
% elif a['video_decision'] == 'copy':
|
||||
Stream <strong>Direct Stream</strong>
|
||||
% else:
|
||||
Stream <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>
|
||||
% elif a['state'] == 'paused':
|
||||
<i class="fa fa-pause"></i>
|
||||
% elif a['state'] == 'buffering':
|
||||
<i class="fa fa-spinner"></i>
|
||||
% 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
|
||||
|
@@ -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);
|
||||
}
|
||||
});
|
||||
|
@@ -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']}">
|
||||
|
26
data/interfaces/default/images/plex-logo-light.svg
Normal file
26
data/interfaces/default/images/plex-logo-light.svg
Normal 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 |
@@ -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();
|
||||
|
||||
|
@@ -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> </h1><h1>${data['title']}</h1>
|
||||
% elif data['type'] == 'season':
|
||||
<h1> </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']} · 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>
|
||||
|
102
data/interfaces/default/info_children_list.html
Normal file
102
data/interfaces/default/info_children_list.html
Normal 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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
@@ -35,7 +35,7 @@ var hc_plays_by_day_options = {
|
||||
}
|
||||
}
|
||||
},
|
||||
colors: ['#F9AA03', '#FFFFFF'],
|
||||
colors: ['#F9AA03', '#FFFFFF', '#FF4747'],
|
||||
xAxis: {
|
||||
type: 'datetime',
|
||||
labels: {
|
||||
|
@@ -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
|
||||
},
|
||||
|
@@ -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
|
||||
},
|
||||
|
@@ -23,7 +23,7 @@ var hc_plays_by_month_options = {
|
||||
credits: {
|
||||
enabled: false
|
||||
},
|
||||
colors: ['#F9AA03', '#FFFFFF'],
|
||||
colors: ['#F9AA03', '#FFFFFF', '#FF4747'],
|
||||
xAxis: {
|
||||
labels: {
|
||||
style: {
|
||||
|
@@ -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
|
||||
},
|
||||
|
@@ -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
|
||||
},
|
||||
|
@@ -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
|
||||
},
|
||||
|
@@ -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
|
||||
},
|
||||
|
@@ -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';
|
||||
}
|
||||
}
|
||||
|
@@ -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'] + '· 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 + ' ' + 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 + ' ' + 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 + ' ' + thumb_popover + '</div></a></div>');
|
||||
} else {
|
||||
$(td).html('<a href="info?item_id=' + rowData['id'] + '">' + cellData + '</a>');
|
||||
}
|
||||
|
@@ -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'] + '· 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 + ' ' + 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 + ' ' + 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 + ' ' + thumb_popover + '</div></a></div>');
|
||||
} else {
|
||||
$(td).html('<a href="info?item_id=' + rowData['id'] + '">' + cellData + '</a>');
|
||||
}
|
||||
|
@@ -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);
|
||||
|
@@ -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 + ' ' + 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 + ' ' + thumb_popover + '</div></a></div>');
|
||||
} else if (rowData['media_type']) {
|
||||
$(td).html('<a href="info?item_id=' + rowData['id'] + '">' + cellData + '</a>');
|
||||
} else {
|
||||
|
@@ -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 + ' ' + 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 + ' ' + thumb_popover + '</div></a></div>');
|
||||
} else if (rowData['media_type']) {
|
||||
$(td).html('<a href="info?item_id=' + rowData['id'] + '">' + cellData + '</a>');
|
||||
} else {
|
||||
|
@@ -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
|
@@ -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>
|
||||
|
@@ -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>
|
||||
|
@@ -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>
|
||||
|
@@ -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']} · 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>
|
||||
|
@@ -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> 
|
||||
<div class="alert alert-danger alert-edit" role="alert" id="row-edit-mode-alert"><i class="fa fa-exclamation-triangle"></i> Select 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> Select 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');
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@@ -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, '
|
||||
|
@@ -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),
|
||||
|
@@ -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'],
|
||||
|
539
plexpy/graphs.py
539
plexpy/graphs.py
@@ -1,4 +1,4 @@
|
||||
# This file is part of PlexPy.
|
||||
# This file is part of PlexPy.
|
||||
#
|
||||
# PlexPy is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
@@ -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)
|
||||
|
||||
|
@@ -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)
|
||||
|
@@ -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:
|
||||
|
@@ -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'
|
||||
|
@@ -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'],
|
||||
|
@@ -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'],
|
||||
|
@@ -1,2 +1,2 @@
|
||||
PLEXPY_VERSION = "master"
|
||||
PLEXPY_RELEASE_VERSION = "1.1.6"
|
||||
PLEXPY_RELEASE_VERSION = "1.1.10"
|
||||
|
@@ -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):
|
||||
|
||||
|
Reference in New Issue
Block a user