Move everything to Bootstrap 3. (WIP)

Styling changes.
Remove old unused css.
Some code cleanup on notification handler.
This commit is contained in:
Tim 2015-08-02 16:46:35 +02:00
parent 227e63cb50
commit d6b646323f
56 changed files with 3397 additions and 22794 deletions

View file

@ -11,10 +11,10 @@ from plexpy import version
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="">
<meta name="author" content="">
<link href="interfaces/default/css/plexwatch.css" rel="stylesheet">
<link href="interfaces/default/css/style.css" rel="stylesheet">
<link href="interfaces/default/css/bootstrap3/bootstrap.css" rel="stylesheet">
<link href="interfaces/default/css/plexpy.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Open+Sans" rel="stylesheet" type="text/css">
<link href="interfaces/default/css/font-awesome.css" rel="stylesheet">
<link href="interfaces/default/css/font-awesome.min.css" rel="stylesheet">
<style type="text/css">
body {
padding-top: 60px;
@ -39,7 +39,7 @@ from plexpy import version
<link rel="apple-touch-icon" sizes="144x144" href="interfaces/default/images/icon_ipad@2x.png">
</head>
<body>
<body class="content">
<div class="container">
<div id="ajaxMsg" class="ajaxMsg"></div>
% if plexpy.CONFIG.CHECK_GITHUB and not plexpy.CURRENT_VERSION:
@ -55,139 +55,69 @@ from plexpy import version
<a href="#" onclick="$('#updatebar').slideUp('slow');">Close</a>
</div>
% endif
<div class="navbar navbar-fixed-top">
<div class="navbar-inner">
<a href="home">
<div class="logo hidden-phone"></div>
</a>
<ul class="nav">
% if title=="Home":
<li class="active">
<a href="home">
<i class="fa fa-home fa-2x" data-toggle="tooltip" data-placement="bottom" title="Home" id="home"></i>
</a>
</li>
% else:
<li>
<a href="home">
<i class="fa fa-home fa-2x" data-toggle="tooltip" data-placement="bottom" title="Home" id="home"></i>
</a>
</li>
% endif
% if title=="History":
<li class="active">
<a href="history">
<i class="fa fa-history fa-2x" data-toggle="tooltip" data-placement="bottom" title="History" id="history"></i>
</a>
</li>
% else:
<li>
<a href="history">
<i class="fa fa-history fa-2x" data-toggle="tooltip" data-placement="bottom" title="History" id="history"></i>
</a>
</li>
% endif
% if title=="Users":
<li class="active">
<a href="users">
<i class="fa fa-users fa-2x" data-toggle="tooltip" data-placement="bottom" title="Users" id="users"></i>
</a>
</li>
% else:
<li>
<a href="users">
<i class="fa fa-users fa-2x" data-toggle="tooltip" data-placement="bottom" title="Users" id="users"></i>
</a>
</li>
% endif
% if title=="Graphs":
<li class="active">
<a href="graphs">
<i class="fa fa-bar-chart fa-2x" data-toggle="tooltip" data-placement="bottom" title="Graphs" id="graphs"></i>
</a>
</li>
% else:
<li>
<a href="graphs">
<i class="fa fa-bar-chart fa-2x" data-toggle="tooltip" data-placement="bottom" title="Graphs" id="graphs"></i>
</a>
</li>
% endif
% if title=="Synced Items":
<li class="active">
<a href="sync">
<i class="fa fa-cloud-download fa-2x" data-toggle="tooltip" data-placement="bottom" title="Synced Items" id="sync"></i>
</a>
</li>
% else:
<li>
<a href="sync">
<i class="fa fa-cloud-download fa-2x" data-toggle="tooltip" data-placement="bottom" title="Synced Items" id="sync"></i>
</a>
</li>
% endif
% if title=="Log":
<li class="active">
<a href="logs">
<i class="fa fa-book fa-2x" data-toggle="tooltip" data-placement="bottom" title="Logs" id="logs"></i>
</a>
</li>
% else:
<li>
<a href="logs">
<i class="fa fa-book fa-2x" data-toggle="tooltip" data-placement="bottom" title="Logs" id="logs"></i>
</a>
</li>
% endif
% if title=="Settings":
<li class="active">
<a href="settings">
<i class="fa fa-cog fa-2x" data-toggle="tooltip" data-placement="bottom" title="Settings" id="settings"></i>
</a>
</li>
% else:
<li>
<a href="settings">
<i class="fa fa-cog fa-2x" data-toggle="tooltip" data-placement="bottom"
title="Settings" id="settings"></i></a></li>
% endif
</ul>
<nav class="navbar navbar-fixed-top">
<div class="container-fluid">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar-collapse-1" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="home">
<img alt="PlexPy" src="interfaces/default/images/logo-plexpy@2x.png" height="40px">
</a>
</div>
<div class="collapse navbar-collapse navbar-right" id="navbar-collapse-1">
<ul class="nav navbar-nav">
% if title=="Home":
<li class="active"><a href="home"><i class="fa fa-lg fa-home"></i></a></li>
% 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=="Graphs":
<li class="active"><a href="graphs">Graphs</a></li>
% else:
<li><a href="graphs">Graphs</a></li>
% endif
% if title=="Synced Items":
<li class="active"><a href="sync">Synced Items</a></li>
% else:
<li><a href="sync">Synced Items</a></li>
% endif
% if title=="Log":
<li class="active"><a href="logs">Logs</a></li>
% else:
<li><a href="logs">Logs</a></li>
% endif
% if title=="Settings":
<li class="active"><a href="settings">Settings</a></li>
% else:
<li><a href="settings">Settings</a></li>
% endif
</ul>
</div>
</div>
</div>
</nav>
</div>
${next.headerIncludes()}
${next.body()}
<script src="interfaces/default/js/jquery-2.1.4.min.js"></script>
<script src="interfaces/default/js/bootstrap.js"></script>
<script>
$(document).ready(function() {
$('#home').tooltip();
});
$(document).ready(function() {
$('#history').tooltip();
});
$(document).ready(function() {
$('#users').tooltip();
});
$(document).ready(function() {
$('#graphs').tooltip();
});
$(document).ready(function() {
$('#sync').tooltip();
});
$(document).ready(function() {
$('#logs').tooltip();
});
$(document).ready(function() {
$('#settings').tooltip();
});
</script>
<script src="interfaces/default/js/bootstrap3/bootstrap.min.js"></script>
<script src="interfaces/default/js/script.js"></script>
${next.javascriptIncludes()}
</body>
</html>

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

View file

@ -1085,7 +1085,7 @@ body {
font-family: 'Open Sans', sans-serif;
font-size: 14px;
line-height: 1.42857143;
color: #333;
color: #fff;
background-color: #1f1f1f;
}
input,
@ -1146,7 +1146,6 @@ input[type="color"]:focus,
/* IE6-9 */
}
a {
color: #337ab7;
text-decoration: none;
}
a:hover,

View file

@ -1,77 +0,0 @@
/* Variables */
@base-font-face: "Helvetica Neue", Helvetica, Arial, Geneva, sans-serif;
@alt-font-face: "Trebuchet MS", Helvetica, Arial, sans-serif;
@base-font-size: 12px;
@text-color: #343434;
@swatch-blue: #4183C4;
@swatch-grey: #666666;
@link-color: @swatch-blue;
@border-color: #CCCCCC;
@msg-bg: #FFF6A9;
@msg-bg-success: #D3FFD7;
@msg-bg-error: #FFD3D3;
/* Mixins */
.rounded(@radius: 5px) {
-moz-border-radius: @radius;
-webkit-border-radius: @radius;
border-radius: @radius;
}
.roundedTop(@radius: 5px) {
-moz-border-radius-topleft: @radius;
-moz-border-radius-topright: @radius;
-webkit-border-top-right-radius: @radius;
-webkit-border-top-left-radius: @radius;
border-top-left-radius: @radius;
border-top-right-radius: @radius;
}
.roundedLeftTop(@radius: 5px) {
-moz-border-radius-topleft: @radius;
-webkit-border-top-left-radius: @radius;
border-top-left-radius: @radius;
}
.roundedRightTop(@radius: 5px) {
-moz-border-radius-topright: @radius;
-webkit-border-top-right-radius: @radius;
border-top-right-radius: @radius;
}
.roundedBottom(@radius: 5px) {
-moz-border-radius-bottomleft: @radius;
-moz-border-radius-bottomright: @radius;
-webkit-border-bottom-right-radius: @radius;
-webkit-border-bottom-left-radius: @radius;
border-bottom-left-radius: @radius;
border-bottom-right-radius: @radius;
}
.roundedLeftBottom(@radius: 5px) {
-moz-border-radius-bottomleft: @radius;
-webkit-border-bottom-left-radius: @radius;
border-bottom-left-radius: @radius;
}
.roundedRightBottom(@radius: 5px) {
-moz-border-radius-bottomright: @radius;
-webkit-border-bottom-right-radius: @radius;
border-bottom-right-radius: @radius;
}
.shadow(@shadow: 0 17px 11px -1px #ced8d9) {
-moz-box-shadow: @shadow;
-webkit-box-shadow: @shadow;
-o-box-shadow: @shadow;
box-shadow: @shadow;
}
.gradient(@gradientFrom: #FFFFFF, @gradientTo: #EEEEEE){
background-image: -moz-linear-gradient(@gradientFrom, @gradientTo) !important;
background-image: linear-gradient(@gradientFrom, @gradientTo) !important;
background-image: -webkit-linear-gradient(@gradientFrom, @gradientTo) !important;
background-image: -o-linear-gradient(@gradientFrom, @gradientTo) !important;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=@gradientFrom, endColorstr=@gradientTo) !important;
-ms-filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=@gradientFrom, endColorstr=@gradientTo) !important;
}
.opacity(@opacity_percent:85) {
filter: ~"alpha(opacity=85)";
-moz-opacity: @opacity_percent / 100 !important;
-khtml-opacity:@opacity_percent / 100 !important;
-o-opacity:@opacity_percent / 100 !important;
opacity:@opacity_percent / 100 !important;
}

View file

@ -0,0 +1,371 @@
div.dataTables_length label {
font-weight: normal;
text-align: left;
white-space: nowrap;
}
div.dataTables_length select {
width: 75px;
display: inline-block;
}
div.dataTables_filter {
text-align: right;
}
div.dataTables_filter label {
font-weight: normal;
white-space: nowrap;
text-align: left;
}
div.dataTables_filter input {
margin-left: 0.5em;
display: inline-block;
width: auto;
}
div.dataTables_info {
padding-top: 8px;
white-space: nowrap;
}
div.dataTables_paginate {
margin: 0;
white-space: nowrap;
text-align: right;
}
div.dataTables_paginate ul.pagination {
margin: 2px 0;
white-space: nowrap;
}
@media screen and (max-width: 767px) {
div.dataTables_wrapper > div.row > div,
div.dataTables_length,
div.dataTables_filter,
div.dataTables_info,
div.dataTables_paginate {
text-align: center;
}
div.DTTT {
margin-bottom: 0.5em;
}
}
table.dataTable td,
table.dataTable th {
-webkit-box-sizing: content-box;
-moz-box-sizing: content-box;
box-sizing: content-box;
}
table.dataTable {
clear: both;
margin-top: 6px !important;
margin-bottom: 6px !important;
max-width: none !important;
}
table.dataTable thead .sorting,
table.dataTable thead .sorting_asc,
table.dataTable thead .sorting_desc,
table.dataTable thead .sorting_asc_disabled,
table.dataTable thead .sorting_desc_disabled {
cursor: pointer;
position: relative;
}
table.dataTable thead .sorting:after,
table.dataTable thead .sorting_asc:after,
table.dataTable thead .sorting_desc:after {
position: absolute;
top: 8px;
right: 8px;
display: block;
font-family: 'Glyphicons Halflings';
opacity: 0.5;
}
table.dataTable thead .sorting:after {
opacity: 0.2;
content: "\e150"; /* sort */
}
table.dataTable thead .sorting_asc:after {
content: "\e155"; /* sort-by-attributes */
}
table.dataTable thead .sorting_desc:after {
content: "\e156"; /* sort-by-attributes-alt */
}
div.dataTables_scrollBody table.dataTable thead .sorting:after,
div.dataTables_scrollBody table.dataTable thead .sorting_asc:after,
div.dataTables_scrollBody table.dataTable thead .sorting_desc:after {
display: none;
}
table.dataTable thead .sorting_asc_disabled:after,
table.dataTable thead .sorting_desc_disabled:after {
color: #eee;
}
table.dataTable thead > tr > th {
padding-right: 30px;
}
table.dataTable th:active {
outline: none;
}
/* Condensed */
table.dataTable.table-condensed thead > tr > th {
padding-right: 20px;
}
table.dataTable.table-condensed thead .sorting:after,
table.dataTable.table-condensed thead .sorting_asc:after,
table.dataTable.table-condensed thead .sorting_desc:after {
top: 6px;
right: 6px;
}
/* Scrolling */
div.dataTables_scrollHead table {
margin-bottom: 0 !important;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
div.dataTables_scrollHead table thead tr:last-child th:first-child,
div.dataTables_scrollHead table thead tr:last-child td:first-child {
border-bottom-left-radius: 0 !important;
border-bottom-right-radius: 0 !important;
}
div.dataTables_scrollBody table {
border-top: none;
margin-top: 0 !important;
margin-bottom: 0 !important;
}
div.dataTables_scrollBody tbody tr:first-child th,
div.dataTables_scrollBody tbody tr:first-child td {
border-top: none;
}
div.dataTables_scrollFoot table {
margin-top: 0 !important;
border-top: none;
}
/* Frustratingly the border-collapse:collapse used by Bootstrap makes the column
width calculations when using scrolling impossible to align columns. We have
to use separate
*/
table.table-bordered.dataTable {
border-collapse: separate !important;
}
table.table-bordered thead th,
table.table-bordered thead td {
border-left-width: 0;
border-top-width: 0;
}
table.table-bordered tbody th,
table.table-bordered tbody td {
border-left-width: 0;
border-bottom-width: 0;
}
table.table-bordered tfoot th,
table.table-bordered tfoot td {
border-left-width: 0;
border-bottom-width: 0;
}
table.table-bordered th:last-child,
table.table-bordered td:last-child {
border-right-width: 0;
}
div.dataTables_scrollHead table.table-bordered {
border-bottom-width: 0;
}
/*
* TableTools styles
*/
.table.dataTable tbody tr.active td,
.table.dataTable tbody tr.active th {
background-color: #08C;
color: white;
}
.table.dataTable tbody tr.active:hover td,
.table.dataTable tbody tr.active:hover th {
background-color: #0075b0 !important;
}
.table.dataTable tbody tr.active th > a,
.table.dataTable tbody tr.active td > a {
color: white;
}
.table-striped.dataTable tbody tr.active:nth-child(odd) td,
.table-striped.dataTable tbody tr.active:nth-child(odd) th {
background-color: #017ebc;
}
table.DTTT_selectable tbody tr {
cursor: pointer;
}
div.DTTT .btn:hover {
text-decoration: none !important;
}
ul.DTTT_dropdown.dropdown-menu {
z-index: 2003;
}
ul.DTTT_dropdown.dropdown-menu a {
color: #333 !important; /* needed only when demo_page.css is included */
}
ul.DTTT_dropdown.dropdown-menu li {
position: relative;
}
ul.DTTT_dropdown.dropdown-menu li:hover a {
background-color: #0088cc;
color: white !important;
}
div.DTTT_collection_background {
z-index: 2002;
}
/* TableTools information display */
div.DTTT_print_info {
position: fixed;
top: 50%;
left: 50%;
width: 400px;
height: 150px;
margin-left: -200px;
margin-top: -75px;
text-align: center;
color: #333;
padding: 10px 30px;
opacity: 0.95;
background-color: white;
border: 1px solid rgba(0, 0, 0, 0.2);
border-radius: 6px;
-webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.5);
box-shadow: 0 3px 7px rgba(0, 0, 0, 0.5);
}
div.DTTT_print_info h6 {
font-weight: normal;
font-size: 28px;
line-height: 28px;
margin: 1em;
}
div.DTTT_print_info p {
font-size: 14px;
line-height: 20px;
}
div.dataTables_processing {
position: absolute;
top: 50%;
left: 50%;
width: 100%;
height: 60px;
margin-left: -50%;
margin-top: -25px;
padding-top: 20px;
padding-bottom: 20px;
text-align: center;
font-size: 1.2em;
background-color: white;
background: -webkit-gradient(linear, left top, right top, color-stop(0%, rgba(255,255,255,0)), color-stop(25%, rgba(255,255,255,0.9)), color-stop(75%, rgba(255,255,255,0.9)), color-stop(100%, rgba(255,255,255,0)));
background: -webkit-linear-gradient(left, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%);
background: -moz-linear-gradient(left, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%);
background: -ms-linear-gradient(left, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%);
background: -o-linear-gradient(left, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%);
background: linear-gradient(to right, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%);
}
/*
* FixedColumns styles
*/
div.DTFC_LeftHeadWrapper table,
div.DTFC_LeftFootWrapper table,
div.DTFC_RightHeadWrapper table,
div.DTFC_RightFootWrapper table,
table.DTFC_Cloned tr.even {
background-color: white;
margin-bottom: 0;
}
div.DTFC_RightHeadWrapper table ,
div.DTFC_LeftHeadWrapper table {
border-bottom: none !important;
margin-bottom: 0 !important;
border-top-right-radius: 0 !important;
border-bottom-left-radius: 0 !important;
border-bottom-right-radius: 0 !important;
}
div.DTFC_RightHeadWrapper table thead tr:last-child th:first-child,
div.DTFC_RightHeadWrapper table thead tr:last-child td:first-child,
div.DTFC_LeftHeadWrapper table thead tr:last-child th:first-child,
div.DTFC_LeftHeadWrapper table thead tr:last-child td:first-child {
border-bottom-left-radius: 0 !important;
border-bottom-right-radius: 0 !important;
}
div.DTFC_RightBodyWrapper table,
div.DTFC_LeftBodyWrapper table {
border-top: none;
margin: 0 !important;
}
div.DTFC_RightBodyWrapper tbody tr:first-child th,
div.DTFC_RightBodyWrapper tbody tr:first-child td,
div.DTFC_LeftBodyWrapper tbody tr:first-child th,
div.DTFC_LeftBodyWrapper tbody tr:first-child td {
border-top: none;
}
div.DTFC_RightFootWrapper table,
div.DTFC_LeftFootWrapper table {
border-top: none;
margin-top: 0 !important;
}
div.DTFC_LeftBodyWrapper table.dataTable thead .sorting:after,
div.DTFC_LeftBodyWrapper table.dataTable thead .sorting_asc:after,
div.DTFC_LeftBodyWrapper table.dataTable thead .sorting_desc:after,
div.DTFC_RightBodyWrapper table.dataTable thead .sorting:after,
div.DTFC_RightBodyWrapper table.dataTable thead .sorting_asc:after,
div.DTFC_RightBodyWrapper table.dataTable thead .sorting_desc:after {
display: none;
}
/*
* FixedHeader styles
*/
div.FixedHeader_Cloned table {
margin: 0 !important
}

File diff suppressed because it is too large Load diff

View file

@ -26,128 +26,6 @@
* ../images/ - relative to this CSS file.
*/
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* DataTables features
*/
.dataTables_wrapper {
position: relative;
clear: both;
zoom: 1; /* Feeling sorry for IE */
}
.dataTables_processing {
width: 50%;
float: left;
margin-top: -60px;
margin-left: 25%;
margin-bottom: 12px;
height: 40px;
padding: 8px 0px 0px 20px;
border: none;
color: #ccc;
font-size: 16px;
background-color: rgba(0,0,0,.5);
border-radius: 8px;
}
@media (min-width: 768px) {
.dataTables_length {
width: 40%;
float: left;
margin-bottom: 20px;
}
}
@media (max-width: 767px) {
.dataTables_length {
display: none;
}
}
.dataTables_filter {
float: right;
text-align: right;
margin-bottom: 20px;
}
@media (min-width: 768px) {
.dataTables_info {
width: 60%;
float: left;
margin-top: 12px;
margin-left: 15px;
margin-bottom: 12px;
text-overflow: ellipsis;
overflow: hidden;
}
}
@media (max-width: 767px) {
.dataTables_info {
display: none;
}
}
.dataTables_paginate {
float: right;
text-align: right;
margin-right: 15px;
}
/* Pagination nested */
.paginate_disabled_previous, .paginate_enabled_previous,
.paginate_disabled_next, .paginate_enabled_next {
height: 19px;
float: left;
cursor: pointer;
*cursor: hand;
color: #fff !important;
}
.paginate_disabled_previous:hover, .paginate_enabled_previous:hover,
.paginate_disabled_next:hover, .paginate_enabled_next:hover {
text-decoration: none !important;
}
.paginate_disabled_previous:active, .paginate_enabled_previous:active,
.paginate_disabled_next:active, .paginate_enabled_next:active {
outline: none;
}
.paginate_disabled_previous,
.paginate_disabled_next {
color: #666 !important;
}
.paginate_disabled_previous, .paginate_enabled_previous {
padding-left: 23px;
}
.paginate_disabled_next, .paginate_enabled_next {
padding-right: 23px;
margin-left: 10px;
}
.paginate_disabled_previous {
background: url('../images/back_disabled.png') no-repeat top left;
}
.paginate_enabled_previous {
background: url('../images/back_enabled.png') no-repeat top left;
}
.paginate_enabled_previous:hover {
background: url('../images/back_enabled_hover.png') no-repeat top left;
}
.paginate_disabled_next {
background: url('../images/forward_disabled.png') no-repeat top right;
}
.paginate_enabled_next {
background: url('../images/forward_enabled.png') no-repeat top right;
}
.paginate_enabled_next:hover {
background: url('../images/forward_enabled_hover.png') no-repeat top right;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* DataTables display
@ -171,169 +49,97 @@ table.display {
* then filling in the gaps with other borders.
*/
}
table.display thead th {
white-space:nowrap;
padding: 0px 0px 0px 18px;
cursor: pointer;
color: #999;
background-color: #212121;
font-size: 11px;
white-space:nowrap;
padding: 0px 0px 0px 5px;
cursor: pointer;
color: #999;
background-color: #212121;
font-size: 11px;
}
table.display thead th i {
margin-top: -1px;
margin-top: -1px;
}
table.display thead .sorting,
table.display thead .sorting_asc,
table.display thead .sorting_desc {
cursor: pointer;
*cursor: hand;
height: 35px;
cursor: pointer;
*cursor: hand;
height: 35px;
}
table.display thead .sorting,
table.display thead .sorting_asc,
table.display thead .sorting_desc,
table.display thead .sorting_asc_disabled,
table.display thead .sorting_desc_disabled {
background-repeat: no-repeat;
background-position: left;
background-repeat: no-repeat;
background-position: left;
}
table.display thead .sorting {
background-image: url("../images/sort_both.png");
}
table.display thead .sorting_asc {
background-image: url("../images/sort_asc.png");
}
table.display thead .sorting_desc {
background-image: url("../images/sort_desc.png");
}
table.display thead .sorting_asc_disabled {
background-image: url("../images/sort_asc_disabled.png");
}
table.display thead .sorting_desc_disabled {
background-image: url("../images/sort_desc_disabled.png");
}
table.display tfoot th {
padding: 3px 18px 3px 10px;
border-top: 1px solid black;
font-weight: bold;
}
table.display tr.heading2 td {
border-bottom: 1px solid #aaa;
}
table.display td {
padding: 5px 0 5px 5px;
}
table.display td.title {
padding: 5px;
white-space: normal;
min-width: 400px;
}
table.display td.center {
text-align: center;
}
table.display tr:hover {
background-color: rgba(255,255,255,0.075);
}
table.display tr:hover a {
text-decoration:none;
}
table.display td:hover a {
color: #F9AA03;
}
table.display thead tr:hover {
background-color: #212121;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* DataTables sorting
*/
.sorting_asc {
}
.sorting_desc {
}
.sorting {
}
.sorting_asc_disabled {
}
.sorting_desc_disabled {
}
table.display thead th:active,
table.display thead td:active {
outline: none;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* DataTables row classes
*/
table.display tr.odd.gradeA {
background-color: #ddffdd;
}
table.display tr.even.gradeA {
background-color: #eeffee;
}
table.display tr.odd.gradeC {
background-color: #ddddff;
}
table.display tr.even.gradeC {
background-color: #eeeeff;
}
table.display tr.odd.gradeX {
background-color: #ffdddd;
}
table.display tr.even.gradeX {
background-color: #ffeeee;
}
table.display tr.odd.gradeU {
background-color: #ddd;
}
table.display tr.even.gradeU {
background-color: #eee;
}
tr.odd {
border-top: 0px solid #343434;
border-bottom: 0px solid #343434;
background-color: rgba(255,255,255,0.010);
}
tr.even {
border-top: 0px solid #343434;
border-bottom: 0px solid #343434;
@ -341,140 +147,42 @@ tr.even {
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Misc
*/
.dataTables_scroll {
clear: both;
}
.dataTables_scrollBody {
*margin-top: -1px;
-webkit-overflow-scrolling: touch;
}
.top, .bottom {
}
.top .dataTables_info {
float: none;
}
.clear {
clear: both;
}
.dataTables_empty {
text-align: center;
}
tfoot input {
margin: 0.5em 0;
width: 100%;
color: #444;
}
tfoot input.search_init {
color: #999;
}
td.group {
background-color: #d1cfd0;
border-bottom: 2px solid #A19B9E;
border-top: 2px solid #A19B9E;
}
td.details {
background-color: #d1cfd0;
border: 2px solid #A19B9E;
}
.example_alt_pagination div.dataTables_info {
width: 40%;
}
.paging_full_numbers {
width: 400px;
height: 22px;
line-height: 22px;
}
.paging_full_numbers a:active {
outline: none
}
.paging_full_numbers a:hover {
text-decoration: none;
}
.paging_full_numbers a.paginate_button,
.paging_full_numbers a.paginate_active {
border: 1px solid #aaa;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
padding: 2px 5px;
margin: 0 3px;
cursor: pointer;
*cursor: hand;
color: #333 !important;
}
.paging_full_numbers a.paginate_button {
background-color: #ddd;
}
.paging_full_numbers a.paginate_button:hover {
background-color: #ccc;
text-decoration: none !important;
}
.paging_full_numbers a.paginate_active {
background-color: #99B3FF;
}
table.display tr.even.row_selected td {
background-color: #B0BED9;
}
table.display tr.odd.row_selected td {
background-color: #9FAFD1;
}
/*
* Sorting classes for columns
*/
/* For the standard odd/even */
tr.odd td.sorting_1 {
.dataTables_empty {
text-align: center;
}
tr.odd td.sorting_2 {
}
tr.odd td.sorting_3 {
}
tr.even td.sorting_1 {
}
tr.even td.sorting_2 {
background-color: rgba(255,255,255,0.04);
}
tr.even td.sorting_3 {
background-color: rgba(255,255,255,0.04);
}
/* For the Conditional-CSS grading rows */
/*
Colour calculations (based off the main row colours)
@ -488,95 +196,72 @@ tr.even td.sorting_3 {
tr.odd.gradeA td.sorting_1 {
background-color: #c4ffc4;
}
tr.odd.gradeA td.sorting_2 {
background-color: #d1ffd1;
}
tr.odd.gradeA td.sorting_3 {
background-color: #d1ffd1;
}
tr.even.gradeA td.sorting_1 {
background-color: #d5ffd5;
}
tr.even.gradeA td.sorting_2 {
background-color: #e2ffe2;
}
tr.even.gradeA td.sorting_3 {
background-color: #e2ffe2;
}
tr.odd.gradeC td.sorting_1 {
background-color: #c4c4ff;
}
tr.odd.gradeC td.sorting_2 {
background-color: #d1d1ff;
}
tr.odd.gradeC td.sorting_3 {
background-color: #d1d1ff;
}
tr.even.gradeC td.sorting_1 {
background-color: #d5d5ff;
}
tr.even.gradeC td.sorting_2 {
background-color: #e2e2ff;
}
tr.even.gradeC td.sorting_3 {
background-color: #e2e2ff;
}
tr.odd.gradeX td.sorting_1 {
background-color: #ffc4c4;
}
tr.odd.gradeX td.sorting_2 {
background-color: #ffd1d1;
}
tr.odd.gradeX td.sorting_3 {
background-color: #ffd1d1;
}
tr.even.gradeX td.sorting_1 {
background-color: #ffd5d5;
}
tr.even.gradeX td.sorting_2 {
background-color: #ffe2e2;
}
tr.even.gradeX td.sorting_3 {
background-color: #ffe2e2;
}
tr.odd.gradeU td.sorting_1 {
background-color: #c4c4c4;
}
tr.odd.gradeU td.sorting_2 {
background-color: #d1d1d1;
}
tr.odd.gradeU td.sorting_3 {
background-color: #d1d1d1;
}
tr.even.gradeU td.sorting_1 {
background-color: #d5d5d5;
}
tr.even.gradeU td.sorting_2 {
background-color: #e2e2e2;
}
tr.even.gradeU td.sorting_3 {
background-color: #e2e2e2;
}
@ -588,39 +273,30 @@ tr.even.gradeU td.sorting_3 {
.ex_highlight #example tbody tr.even:hover, #example tbody tr.even td.highlighted {
background-color: #ECFFB3;
}
.ex_highlight #example tbody tr.odd:hover, #example tbody tr.odd td.highlighted {
background-color: #E6FF99;
}
.ex_highlight_row #example tr.even:hover {
background-color: #ECFFB3;
}
.ex_highlight_row #example tr.even:hover td.sorting_1 {
background-color: #DDFF75;
}
.ex_highlight_row #example tr.even:hover td.sorting_2 {
background-color: #E7FF9E;
}
.ex_highlight_row #example tr.even:hover td.sorting_3 {
background-color: #E2FF89;
}
.ex_highlight_row #example tr.odd:hover {
background-color: #E6FF99;
}
.ex_highlight_row #example tr.odd:hover td.sorting_1 {
background-color: #D6FF5C;
}
.ex_highlight_row #example tr.odd:hover td.sorting_2 {
background-color: #E0FF84;
}
.ex_highlight_row #example tr.odd:hover td.sorting_3 {
background-color: #DBFF70;
}
@ -632,27 +308,21 @@ tr.even.gradeU td.sorting_3 {
table.KeyTable td {
border: 3px solid transparent;
}
table.KeyTable td.focus {
border: 3px solid #3366FF;
}
table.display tr.gradeA {
background-color: #eeffee;
}
table.display tr.gradeC {
background-color: #ddddff;
}
table.display tr.gradeX {
background-color: #ffdddd;
}
table.display tr.gradeU {
background-color: #ddd;
}
div.box {
height: 100px;
padding: 10px;
@ -660,34 +330,6 @@ div.box {
border: 1px solid #8080FF;
background-color: #E5E5FF;
}
td.no-wrap, th.no-wrap {
white-space:nowrap;
}
div.colVis {
}
button.ColVis_Button {
display: inline-block;
padding: 4px 12px;
margin-bottom: 0;
font-size: 14px;
font-weight: normal;
line-height: 1.42857143;
text-align: center;
white-space: nowrap;
vertical-align: middle;
-ms-touch-action: manipulation;
touch-action: manipulation;
cursor: pointer;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
background-image: none;
background-color: #444;
border: 1px solid transparent;
border-radius: 14.5px;
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,96 +0,0 @@
.ajaxMsg {
background-color: rgba(255,255,255,0.075);
color: #999999;
display: none;
font-size: 14px;
right: 10px;
padding: 10px 10px;
position: fixed;
text-align: center;
bottom: 10px;
min-height: 32px;
width: 250px;
z-index: 9999;
}
.ajaxMsg .msg {
line-height: normal;
padding-left: 20px;
}
.ajaxMsg .loader {
position: relative;
top: 2px;
}
.ajaxMsg .success {
text-align: left;
}
.ajaxMsg .error {
background-color: rgba(255,0,0,0.5);
font-size: 20px;
text-align: left;
}
.ajaxMsg .ui-icon {
display: inline-block;
margin-left: -20px;
top: 2px;
position: relative;
margin-right: 3px;
}
.dataTables_processing {
background-color: grey;
display: none;
font-size: 14px;
right: 10px;
padding: 10px 10px;
position: fixed;
text-align: center;
bottom: 10px;
min-height: 32px;
width: 250px;
z-index: 9999;
}
#updatebar {
background-color: rgba(255,255,255,0.075);
color: #999999;
display: none;
font-size: 14px;
right: 10px;
padding: 7px 10px;
position: fixed;
text-align: center;
bottom: 10px;
min-height: 22px;
width: 250px;
z-index: 9999;
display: block;
}
#updatebar .msg {
line-height: normal;
padding-left: 20px;
}
#updatebar .loader {
position: relative;
top: 2px;
}
#updatebar.success {
padding: 15px 10px;
text-align: left;
}
#updatebar.error {
padding: 15px 10px;
text-align: left;
}
#updatebar .ui-icon {
display: inline-block;
margin-left: -20px;
top: 2px;
position: relative;
margin-right: 3px;
}
#updatebar a:hover {
color: #F9AA03;
}

File diff suppressed because it is too large Load diff

View file

@ -65,14 +65,14 @@ DOCUMENTATION :: END
<div class="poster">
<div class="dashboard-activity-poster-face">
% if a['type'] == 'movie' and not a['indexes']:
<img src="pms_image_proxy?img=${a['art']}&width=300&height=169"/>
<img src="pms_image_proxy?img=${a['art']}&width=410&height=230"/>
% elif a['indexes']:
<img onload="fadeIn(this)" src="pms_image_proxy?img=${a['bif_thumb']}&width=300&height=169" style="display: none;"/>
% else:
% if a['type'] == 'track':
<div class="dashboard-activity-poster-music-bg" style="background-image: url('pms_image_proxy?img=${a['thumb']}&width=300&height=300');"></div>
<div class="dashboard-activity-poster-music-bg" style="background-image: url('pms_image_proxy?img=${a['thumb']}&width=300&height=300');"></div>
% endif
<img src="pms_image_proxy?img=${a['thumb']}&width=300&height=169&fallback=cover"/>
<img src="pms_image_proxy?img=${a['thumb']}&width=410&height=230&fallback=cover"/>
% endif
<div class="dashboard-activity-poster-info-bar">
<div class="dashboard-activity-poster-info-text">
@ -92,7 +92,7 @@ DOCUMENTATION :: END
<div class='dashboard-activity-metadata-wrapper'>
<div class='dashboard-activity-instance-overlay'>
<div class='dashboard-activity-metadata-progress-minutes'>
<div class='progress progress-warning'>
<div class='activity-progress'>
<div class="bar" style="width: ${a['progress_percent']}%">${a['progress_percent']}%</div>
</div>
</div>
@ -144,9 +144,9 @@ DOCUMENTATION :: END
% endif
<br/>
% if a['audio_decision'] != 'direct play':
Audio: <strong>${a['transcode_audio_codec']} (${a['transcode_audio_channels']}ch)</strong>
Audio: <strong>${a['transcode_audio_codec']} (${a['transcode_audio_channels']}ch)</strong>
% elif a['audio_decision'] == 'direct play':
Audio: <strong>${a['audio_codec']} (${a['audio_channels']}ch)</strong>
Audio: <strong>${a['audio_codec']} (${a['audio_channels']}ch)</strong>
% endif
% elif a['type'] == 'episode' or a['type'] == 'movie' or a['type'] == 'clip':
% if a['video_decision'] == 'direct play':
@ -156,17 +156,17 @@ DOCUMENTATION :: END
% endif
<br/>
% if a['video_decision'] != 'direct play':
Video: <strong>${a['video_decision']} (${a['transcode_video_codec']})
(${a['transcode_width']}x${a['transcode_height']})</strong>
Video: <strong>${a['video_decision']} (${a['transcode_video_codec']})
(${a['transcode_width']}x${a['transcode_height']})</strong>
% elif a['audio_decision'] == 'direct play':
Video: <strong>${a['video_decision']} (${a['video_codec']})
(${a['width']}x${a['height']})</strong>
Video: <strong>${a['video_decision']} (${a['video_codec']})
(${a['width']}x${a['height']})</strong>
% endif
<br/>
% if a['audio_decision'] != 'direct play':
Audio: <strong>${a['audio_decision']} ${a['transcode_audio_codec']} (${a['transcode_audio_channels']}ch)</strong>
Audio: <strong>${a['audio_decision']} ${a['transcode_audio_codec']} (${a['transcode_audio_channels']}ch)</strong>
% elif a['audio_decision'] == 'direct play':
Audio: <strong>${a['audio_codec']} (${a['audio_channels']}ch)</strong>
Audio: <strong>${a['audio_codec']} (${a['audio_channels']}ch)</strong>
% endif
% endif
<br>
@ -176,8 +176,8 @@ DOCUMENTATION :: END
</div>
</div>
<div class="dashboard-activity-button-info">
<button type="button" class="btn btn-warning" data-toggle="collapse" data-target="#stream-${a['session_key']}">
<i class='icon-info-sign icon-white'></i>
<button type="button" class="btn btn-activity-info btn-sm" data-toggle="collapse" data-target="#stream-${a['session_key']}">
<i class='fa fa-info-circle'></i>
</button>
</div>
</div>
@ -201,18 +201,18 @@ DOCUMENTATION :: END
// When mouse over the activity pane, show an info bar with extra info.
$('.dashboard-activity-poster-face').mouseenter(function() {
$('.dashboard-activity-poster-info-bar', this).slideDown();
$('.dashboard-activity-poster-info-bar', this).slideDown('fast');
});
$('.dashboard-activity-poster-face').mouseleave(function() {
$('.dashboard-activity-poster-info-bar', this).slideUp();
$('.dashboard-activity-poster-info-bar', this).slideUp('fast');
});
</script>
% else:
<div class="muted">Nothing is currently being watched.</div><br>
<div class="text-muted">Nothing is currently being watched.</div><br>
% endif
% else:
<div class="muted">There was an error communicating with your Plex Server. Please check your <a
href="config">settings</a>.
<div class="text-muted">There was an error communicating with your Plex Server. Please check your <a
href="settings">settings</a>.
</div><br>
% endif

View file

@ -18,7 +18,7 @@ DOCUMENTATION :: END
% if data == '0':
<h3>Activity</h3>
% else:
<h3>Activity <strong>${data}</strong> stream(s)</h3>
<h3>Activity <small>${data} stream(s)</small></h3>
% endif
% else:
<h3>Activity</h3>

View file

@ -19,27 +19,37 @@ DOCUMENTATION :: END
</%doc>
% if data is not None:
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true"><i class="fa fa-remove"></i></button>
<h3>Edit user <strong>${data['user']}</strong></h3>
</div>
<div class="modal-body" id="modal-text">
<fieldset>
<div class="form-group">
<label for="friendly_name">Friendly Name</label>
<input type="text" id="friendly_name" name="friendly_name" value="${data['friendly_name']}" size="30">
<p class="help-block">Replace all occurances of the username with this name.</p>
<div class="modal-dialog" role="document">
<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>Edit user <strong>${data['user']}</strong></h4>
</div>
<div class="checkbox">
<input type="checkbox" id="do_notify" name="do_notify" value="1" ${data['do_notify']}> Enable notifications
<p class="help-block">Uncheck this if you do not want to receive notifications for this user's activity.</p>
<div class="modal-body" id="modal-text">
<fieldset>
<div class="form-group">
<label for="friendly_name">Friendly Name</label>
<div class="row">
<div class="col-xs-6">
<input type="text" class="form-control" id="friendly_name" name="friendly_name" value="${data['friendly_name']}" size="30">
</div>
</div>
<p class="help-block">Replace all occurances of the username with this name.</p>
</div>
<div class="checkbox">
<label>
<input type="checkbox" id="do_notify" name="do_notify" value="1" ${data['do_notify']}> Enable notifications
</label>
<p class="help-block">Uncheck this if you do not want to receive notifications for this user's activity.</p>
</div>
</fieldset>
</div>
<div class="modal-footer">
<div>
<input type="button" id="save_user_name" class="squared squared-primary" value="Save">
<span id="edit-user-status-message"></span>
</div>
</div>
</fieldset>
</div>
<div class="modal-footer">
<div>
<input type="button" id="save_user_name" class="squared squared-primary" value="Save">
<span id="edit-user-status-message"></span>
</div>
</div>
<script>

View file

@ -1,83 +1,60 @@
<%inherit file="base.html"/>
<%!
from plexpy import helpers
%>
<%def name="headIncludes()">
</%def>
<%def name="body()">
<div class="container-fluid">
<div class="row-fluid">
<div class="span12">
<div class="wellheader-bg">
<div class="dashboard-wellheader-no-chevron">
<h2><i class="fa fa-bar-chart"></i> Graphs</h2>
<div class="row">
<div class="col-md-12">
<div class='card-back-full'>
<div class="header-bar">
<span><i class="fa fa-bar-chart"></i> Graphs</span>
</div>
</div>
</div>
</div>
</div>
<div class="container-fluid">
<div class="row-fluid">
<div class="span12">
<div class="wellbg">
<div class="wellheader">
<div class="dashboard-wellheader">
<div class="span12">
<div class="span8"><h4>Daily Watch History (Past <span class="days">30</span> days)</h4>
</div>
<div class="span4" style="text-align: right; padding-right: 30px;">
<h5>
<a href="javascript:void(0)" id="graph-30"> 30 days</a> |
<a href="javascript:void(0)" id="graph-90"> 90 days</a> |
<a href="javascript:void(0)" id="graph-365"> 1 year</a>
</h5>
</div>
</div>
</div>
<div class="row">
<div class="col-md-8"><h4>Daily Watch History (Past <span class="days">30</span> days)</h4>
</div>
<div class="col-md-4" style="text-align: right; padding-right: 30px;">
<h5>
<a href="javascript:void(0)" id="graph-30"> 30 days</a> |
<a href="javascript:void(0)" id="graph-90"> 90 days</a> |
<a href="javascript:void(0)" id="graph-365"> 1 year</a>
</h5>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="graphs-instance">
<div class="watch-chart" id="chart_div_plays_by_day">
<div class="graphs-load"><i class="fa fa-refresh fa-spin"></i> Loading chart...</div>
<br>
</div>
<div>
<div class="graphs-instance">
<div class="watch-chart" id="chart_div_plays_by_day">
<div class="graphs-load"><i class="fa fa-refresh fa-spin"></i> Loading chart...</div>
<br>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<h4>Watches by day of week (Past <span class="days">30</span> days)</h4>
<div class="graphs-instance">
<div class="watch-chart" id="chart_div_plays_by_dayofweek" style="float: left;">
<div class="graphs-load"><i class="fa fa-refresh fa-spin"></i> Loading chart...
</div>
<br>
</div>
<div class="container-fluid">
<div class="row-fluid">
<div class="span6">
<div class="wellheader">
<div class="dashboard-wellheader">
<h4>Watches by day of week (Past <span class="days">30</span> days)</h4>
</div>
</div>
<div class="graphs-instance">
<div class="watch-chart" id="chart_div_plays_by_dayofweek" style="float: left;">
<div class="graphs-load"><i class="fa fa-refresh fa-spin"></i> Loading chart...
</div>
<br>
</div>
</div>
</div>
<div class="span6">
<div class="wellheader">
<div class="dashboard-wellheader">
<h4>Watches by hour of day (Past <span class="days">30</span> days)</h4>
</div>
</div>
<div class="graphs-instance">
<div class="watch-chart" id="chart_div_plays_by_hourofday">
<div class="graphs-load"><i class="fa fa-refresh fa-spin"></i> Loading chart...
</div>
<br>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-6">
<h4>Watches by hour of day (Past <span class="days">30</span> days)</h4>
<div class="graphs-instance">
<div class="watch-chart" id="chart_div_plays_by_hourofday">
<div class="graphs-load"><i class="fa fa-refresh fa-spin"></i> Loading chart...
</div>
<br>
</div>
</div>
</div>
@ -165,6 +142,5 @@ from plexpy import helpers
});
});
</script>
</%def>

View file

@ -1,61 +1,51 @@
<%inherit file="base.html"/>
<%!
from plexpy import helpers
%>
<%def name="headIncludes()">
<link rel="stylesheet" href="interfaces/default/css/plexwatch-tables.css">
<link rel="stylesheet" href="interfaces/default/css/dataTables.bootstrap.css">
<link rel="stylesheet" href="interfaces/default/css/dataTables.colVis.css">
<link rel="stylesheet" href="interfaces/default/css/plexpy-dataTables.css">
</%def>
<%def name="body()">
<div class='container-fluid'>
<div class='row-fluid'>
<div class='span12'>
<div class='table-card-back'>
<div class="header-bar">
<h2><i class="fa fa-history"></i> History</h2>
</div>
<div class="colvis-button-bar hidden-phone">
</div>
</div>
<div class='table-card-back'>
<table class="display" id="history_table" width="100%">
<thead>
<tr>
<th align='left' id="time">Time</th>
<th align='left' id="friendly_name">User</th>
<th align='left' id="platform">Platform</th>
<th align='left' id="ip_address">IP Address</th>
<th align='left' id="title">Title</th>
<th align='left' id="started">Started</th>
<th align='left' id="paused_counter">Paused</th>
<th align='left' id="stopped">Stopped</th>
<th align='left' id="duration">Duration</th>
<th align='left' id="percent_complete"></th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<div id="info-modal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="info-modal"
aria-hidden="true">
</div>
</div>
<div class='table-card-back'>
<div class="header-bar">
<span><i class="fa fa-history"></i> History</span>
</div>
<div class="colvis-button-bar hidden-phone">
</div>
</div>
<div class='table-card-back'>
<table class="display" id="history_table" width="100%">
<thead>
<tr>
<th align='left' id="time">Time</th>
<th align='left' id="friendly_name">User</th>
<th align='left' id="platform">Platform</th>
<th align='left' id="ip_address">IP Address</th>
<th align='left' id="title">Title</th>
<th align='left' id="started">Started</th>
<th align='left' id="paused_counter">Paused</th>
<th align='left' id="stopped">Stopped</th>
<th align='left' id="duration">Duration</th>
<th align='left' id="percent_complete"></th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<div class="modal fade" id="info-modal" tabindex="-1" role="dialog" aria-labelledby="info-modal">
</div>
</div>
</div>
</div>
</%def>
<%def name="javascriptIncludes()">
<script src="interfaces/default/js/jquery.dataTables.min.js"></script>
<script src="interfaces/default/js/dataTables.colVis.js"></script>
<script src="interfaces/default/js/jquery.dataTables.bootstrap.pagination.integration.js"></script>
<script src="interfaces/default/js/dataTables.bootstrap.min.js"></script>
<script src="interfaces/default/js/dataTables.bootstrap.pagination.js"></script>
<script src="interfaces/default/js/moment-with-locale.js"></script>
<script src="interfaces/default/js/tables/history_table.js"></script>
<script>
@ -73,5 +63,4 @@ from plexpy import helpers
});
</script>
</%def>

View file

@ -41,72 +41,67 @@ DOCUMENTATION :: END
% if data != None:
% if data[0]['rows']:
<div class="user-platforms">
<ul>
% for a in data:
% if a['stat_id'] == 'top_tv':
<div class="home-platforms-instance">
<li>
<span>
<a href="info?item_id=${a['rows'][0]['rating_key']}">
% if a['rows'][0]['grandparent_thumb']:
<img class="home-platforms-instance-poster"
src="pms_image_proxy?img=${a['rows'][0]['grandparent_thumb']}&width=162&height=240&fallback=poster">
% else:
<img class="home-platforms-instance-poster" src="interfaces/default/images/poster.png">
% endif
</a>
</span>
<div class="home-platforms-instance-name">
<h4>Most Watched TV</h4>
<a href="info?item_id=${a['rows'][0]['rating_key']}">
<h5>${a['rows'][0]['title']}</h5>
</a>
</div>
<div class="user-platforms-instance-playcount">
<h3>${a['rows'][0]['total_plays']}</h3>
<p> plays</p>
</div>
</li>
</div>
% elif a['stat_id'] == 'popular_tv':
<div class="home-platforms-instance">
<li>
<span>
<a href="info?item_id=${a['rows'][0]['rating_key']}">
% if a['rows'][0]['grandparent_thumb'] != '':
<img class="home-platforms-instance-poster"
src="pms_image_proxy?img=${a['rows'][0]['grandparent_thumb']}&width=162&height=240&fallback=poster">
% else:
<img class="home-platforms-instance-poster" src="interfaces/default/images/poster.png">
% endif
</a>
</span>
<div class="home-platforms-instance-name">
<h4>Most Popular TV</h4>
<a href="info?item_id=${a['rows'][0]['rating_key']}">
<h5>${a['rows'][0]['title']}</h5>
</a>
</div>
<div class="user-platforms-instance-playcount">
<h3>${a['rows'][0]['users_watched']}</h3>
<p> users</p>
</div>
</li>
</div>
% elif a['stat_id'] == 'top_users':
<div class="home-platforms-instance">
<li>
<span>
% if a['rows'][0]['user_id']:
<a href="user?user_id=${a['rows'][0]['user_id']}">
<ul class="list-unstyled">
% for a in data:
% if a['stat_id'] == 'top_tv':
<div class="home-platforms-instance">
<li>
<span>
<a href="info?item_id=${a['rows'][0]['rating_key']}">
% if a['rows'][0]['grandparent_thumb']:
<img class="home-platforms-instance-poster"
src="pms_image_proxy?img=${a['rows'][0]['grandparent_thumb']}&width=162&height=240&fallback=poster">
% else:
<img class="home-platforms-instance-poster" src="interfaces/default/images/poster.png">
% endif
</a>
</span>
<div class="home-platforms-instance-name">
<h4>Most Watched TV</h4>
<h5><a href="info?item_id=${a['rows'][0]['rating_key']}">
${a['rows'][0]['title']}
</a></h5>
</div>
<div class="user-platforms-instance-playcount">
<h3>${a['rows'][0]['total_plays']}</h3>
<p> plays</p>
</div>
</li>
</div>
% elif a['stat_id'] == 'popular_tv':
<div class="home-platforms-instance">
<li>
<span>
<a href="info?item_id=${a['rows'][0]['rating_key']}">
% if a['rows'][0]['grandparent_thumb'] != '':
<img class="home-platforms-instance-poster"
src="pms_image_proxy?img=${a['rows'][0]['grandparent_thumb']}&width=162&height=240&fallback=poster">
% else:
<img class="home-platforms-instance-poster" src="interfaces/default/images/poster.png">
% endif
</a>
</span>
<div class="home-platforms-instance-name">
<h4>Most Popular TV</h4>
<h5><a href="info?item_id=${a['rows'][0]['rating_key']}">
${a['rows'][0]['title']}
</a></h5>
</div>
<div class="user-platforms-instance-playcount">
<h3>${a['rows'][0]['users_watched']}</h3>
<p> users</p>
</div>
</li>
</div>
% elif a['stat_id'] == 'top_users':
<div class="home-platforms-instance">
<li>
<span>
% if a['rows'][0]['user_id']:
<a href="user?user_id=${a['rows'][0]['user_id']}">
% else:
<a href="user?user=${a['rows'][0]['user']}">
% endif
% endif
% if a['rows'][0]['thumb'] != '':
<img class="home-platforms-instance-oval" src="${a['rows'][0]['thumb']}"
class="poster-face">
@ -115,53 +110,51 @@ DOCUMENTATION :: END
src="interfaces/default/images/gravatar-default.png">
% endif
</a>
</span>
<div class="home-platforms-instance-name">
<h4>Most Active User</h4>
</span>
<div class="home-platforms-instance-name">
<h4>Most Active User</h4>
<h5>
% if a['rows'][0]['user_id']:
<a href="user?user_id=${a['rows'][0]['user_id']}">
% else:
<a href="user?user=${a['rows'][0]['user']}">
% endif
<h5>${a['rows'][0]['friendly_name']}</h5>
% endif
${a['rows'][0]['friendly_name']}
</a>
</div>
<div class="user-platforms-instance-playcount">
<h3>${a['rows'][0]['total_plays']}</h3>
<p> plays</p>
</div>
</li>
</div>
% elif a['stat_id'] == 'top_platforms':
<div class="home-platforms-instance">
<li>
<div id="platform-stat">
<img class="home-platforms-instance-box" src="interfaces/default/images/platforms/default.png">
</div>
<div class="home-platforms-instance-name">
<h4>Most Active Platform</h4>
<h5>${a['rows'][0]['platform_type']}</h5>
</div>
<div class="user-platforms-instance-playcount">
<h3>${a['rows'][0]['total_plays']}</h3>
<p> plays</p>
</div>
</li>
</div>
<script>
$("#platform-stat").html("<img class='home-platforms-instance-box' src='" + getPlatformImagePath('${a['rows'][0]['platform_type']}') + "'>");
</script>
% endif
% endfor
</ul>
</div>
</h5>
</div>
<div class="user-platforms-instance-playcount">
<h3>${a['rows'][0]['total_plays']}</h3>
<p> plays</p>
</div>
</li>
</div>
% elif a['stat_id'] == 'top_platforms':
<div class="home-platforms-instance">
<li>
<div id="platform-stat">
<img class="home-platforms-instance-box" src="interfaces/default/images/platforms/default.png">
</div>
<div class="home-platforms-instance-name">
<h4>Most Active Platform</h4>
<h5>${a['rows'][0]['platform_type']}</h5>
</div>
<div class="user-platforms-instance-playcount">
<h3>${a['rows'][0]['total_plays']}</h3>
<p> plays</p>
</div>
</li>
</div>
<script>
$("#platform-stat").html("<img class='home-platforms-instance-box' src='" + getPlatformImagePath('${a['rows'][0]['platform_type']}') + "'>");
</script>
% endif
% endfor
</ul>
% else:
<div class="muted">No stats for selected period.</div><br>
<div class="text-muted">No stats for selected period.</div><br>
% endif
% else:
<div class="muted">Unable to retrieve data from database. Please check your <a href="settings">settings</a>.
<div class="text-muted">Unable to retrieve data from database. Please check your <a href="settings">settings</a>.
</div><br>
% endif

Binary file not shown.

Before

Width:  |  Height:  |  Size: 160 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 148 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 201 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 158 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 146 B

View file

@ -1,61 +1,43 @@
<%inherit file="base.html"/>
<%!
from plexpy import helpers
%>
<%def name="headIncludes()">
</%def>
<%def name="body()">
<div class="container-fluid">
<div class="row-fluid">
<div class="span12">
<div class="wellbg">
<div class="wellheader">
<div class="dashboard-wellheader">
<div id="currentActivityHeader">
<h3>Activity</h3>
</div>
</div>
</div>
<div id="currentActivity">
<div class="muted"><i class="fa fa-refresh fa-spin"></i> Checking for activity...</div>
<br>
</div>
<div class="row">
<div class="col-md-12">
<div class="padded-header" id="current-activity-header">
<h3>Activity</h3>
</div>
</div>
</div>
<div class="row-fluid">
<div class="span12">
<div class="wellbg">
<div class="wellheader">
<div class="dashboard-wellheader">
<h3>Statistics (Past 30 days)</h3>
</div>
</div>
<div id="home-stats" class="user-platforms">
<div class='muted'><i class="fa fa-refresh fa-spin"></i> Loading stats...</div>
<br>
</div>
</div>
</div>
</div>
<div class='row-fluid'>
<div class='wellbg'>
<div class='wellheader'>
<div class='dashboard-wellheader'>
<h3>Recently Added</h3>
</div>
</div>
<div id='recentlyAdded'>
<div class='muted'><i class="fa fa-refresh fa-spin"></i> Looking for new items...</div>
<div id="currentActivity">
<div class="text-muted"><i class="fa fa-refresh fa-spin"></i> Checking for activity...</div>
<br>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="padded-header">
<h3>Statistics (Past 30 days)</h3>
</div>
<div id="home-stats" class="user-platforms">
<div class='text-muted'><i class="fa fa-refresh fa-spin"></i> Loading stats...</div>
<br>
</div>
</div>
</div>
<div class='row'>
<div class="col-md-12">
<div class="padded-header">
<h3>Recently Added</h3>
</div>
<div id='recentlyAdded'>
<div class='text-muted'><i class="fa fa-refresh fa-spin"></i> Looking for new items...</div>
<br>
</div>
</div>
</div>
<footer></footer>
</div>
</%def>
@ -94,7 +76,7 @@ from plexpy import helpers
cache: false,
async: true,
complete: function(xhr, status) {
$("#currentActivityHeader").html(xhr.responseText);
$("#current-activity-header").html(xhr.responseText);
}
});
}

View file

@ -35,28 +35,24 @@ DOCUMENTATION :: END
</%doc>
<%inherit file="base.html"/>
<%!
from plexpy import helpers
%>
<%def name="headIncludes()">
<link rel="stylesheet" href="interfaces/default/css/plexwatch-tables.css">
<link rel="stylesheet" href="interfaces/default/css/dataTables.bootstrap.css">
<link rel="stylesheet" href="interfaces/default/css/dataTables.colVis.css">
<link rel="stylesheet" href="interfaces/default/css/plexpy-dataTables.css">
</%def>
<%def name="body()">
% if data:
<div class="clear"></div>
<div class="container-fluid">
<div class="row-fluid">
<div class="span12">
<div class="art-face"
style="background-image:url(pms_image_proxy?img=${data['art']}&width=1920&height=1080)">
<div class="row">
<div>
<div class="art-face" style="background-image:url(pms_image_proxy?img=${data['art']}&width=1920&height=1080)">
<div class="summary-wrapper">
<div class="summary-overlay">
<div class="row-fluid">
<div class="span9">
<div class="summary-content-poster hidden-phone hidden-tablet">
<div class="row">
<div class="col-md-9">
<div class="summary-content-poster hidden-xs hidden-sm">
% if data['type'] == 'episode':
<img src="pms_image_proxy?img=${data['parent_thumb']}&width=300&height=450&fallback=poster">
% else:
@ -77,7 +73,7 @@ from plexpy import helpers
% endif
</div>
% if data['type'] == 'movie':
<div id="stars" class="rateit hidden-phone hidden-tablet" data-rateit-value=""
<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-details-wrapper">
@ -105,10 +101,10 @@ from plexpy import helpers
</div>
</div>
% if data['type'] == 'episode':
<div class="span3">
<div class="summary-content-people-wrapper hidden-phone hidden-tablet">
<div class="col-md-3">
<div class="summary-content-people-wrapper hidden-xs hidden-sm">
<div class="summary-content-writers">
<h6><strong>Written by</strong></h6>
<strong>Written by</strong>
<ul>
% for writer in data['writers']:
% if loop.index < 5:
@ -122,8 +118,8 @@ from plexpy import helpers
</div>
</div>
% elif data['type'] == 'movie' or data['type'] == 'show':
<div class="span3">
<div class="summary-content-people-wrapper hidden-phone hidden-tablet">
<div class="col-md-3">
<div class="summary-content-people-wrapper hidden-xs hidden-sm">
<div class="summary-content-actors">
<h6><strong>Genres</strong></h6>
<ul>
@ -136,7 +132,7 @@ from plexpy import helpers
% endfor
</ul>
</div>
<div class="summary-content-people-wrapper hidden-phone hidden-tablet">
<div class="summary-content-people-wrapper hidden-xs hidden-sm">
<div class="summary-content-actors">
<h6><strong>Starring</strong></h6>
<ul>
@ -153,7 +149,7 @@ from plexpy import helpers
</div>
</div>
% elif data['type'] == 'season':
<div class="span3"></div>
<div class="col-md-3"></div>
% endif
</div>
</div>
@ -162,15 +158,15 @@ from plexpy import helpers
</div>
</div>
</div>
% if data['type'] == 'movie' or data['type'] == 'episode' or data['type'] == 'show':
<div class='container-fluid'>
<div class='row-fluid'>
<div class='span12'>
<div class='row'>
<div class='col-md-12'>
<div class='table-card-back'>
<div class="header-bar">
% if data['type'] == 'movie' or data['type'] == 'episode' or data['type'] == 'show':
<h3>Watch history for <strong>${data['title']}</strong></h3>
<span>Watch history for <strong>${data['title']}</strong></span>
</div>
<div class="colvis-button-bar hidden-phone">
<div class="colvis-button-bar hidden-xs">
</div>
</div>
<div class="table-card-back">
@ -196,23 +192,29 @@ from plexpy import helpers
<div id="info-modal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="info-modal"
aria-hidden="true">
</div>
% elif data['type'] == 'season':
<div class="wellheader">
<div class="dashboard-wellheader">
<h3>Episode list for <strong>${data['title']}</strong></h3>
</div>
</div>
</div>
% elif data['type'] == 'season':
<div class='container-fluid'>
<div class='row'>
<div class='col-md-12'>
<div class='table-card-back'>
<div class="header-bar">
<span>Episode list for <strong>${data['title']}</strong></span>
</div>
</div>
<div id="episode-list">
<div class='table-card-back'>
<div id="episode-list"></div>
</div>
% endif
</div>
</div>
</div>
% else:
<div class="clear"></div>
<div class="container-fluid">
<div class="row-fluid">
<div class="span10 offset1">
<div class="row">
<div class="col-md-10">
<h3>Error retrieving item data. This media may not be available in the Plex Media Server database
anymore.</h3>
</div>
@ -225,7 +227,8 @@ from plexpy import helpers
<script src="interfaces/default/js/jquery.rateit.min.js"></script>
<script src="interfaces/default/js/jquery.dataTables.min.js"></script>
<script src="interfaces/default/js/dataTables.colVis.js"></script>
<script src="interfaces/default/js/jquery.dataTables.bootstrap.pagination.integration.js"></script>
<script src="interfaces/default/js/dataTables.bootstrap.min.js"></script>
<script src="interfaces/default/js/dataTables.bootstrap.pagination.js"></script>
<script src="interfaces/default/js/moment-with-locale.js"></script>
% if data:
@ -234,7 +237,6 @@ from plexpy import helpers
// Convert rating to 5 star rating type
var starRating = Math.round(${data['rating']} / 2)
$('#stars').attr('data-rateit-value', starRating)
</script>
% endif
% if data['type'] == 'movie' or data['type'] == 'episode':
@ -288,8 +290,6 @@ from plexpy import helpers
$("#episode-list").html(xhr.responseText);
}
});
</script>
% endif
<script>

View file

@ -27,14 +27,13 @@ DOCUMENTATION :: END
% if data != None:
% if data['episode_count'] > 0:
<div class="season-episodes-wrapper">
<ul class="season-episodes-instance">
<ul class="season-episodes-instance list-unstyled">
% for a in data['episode_list']:
<li>
<div class="season-episodes-poster">
<div class="season-episodes-poster-face">
<a href="info?item_id=${a['rating_key']}">
<img src="pms_image_proxy?img=${a['thumb']}&width=205&height=115"
class="season-episodes-poster-face">
<img src="pms_image_proxy?img=${a['thumb']}&width=410&height=230" class="season-episodes-poster-face">
</a>
</div>
<div class="season-episodes-card-overlay">

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

View file

@ -1,66 +0,0 @@
// check if browser supports session storage, if not log error in console.
if(sessionStorage === null) console.log("Session storage not supported by this browser.");
// get cache object
var temp = sessionStorage.getItem('cacheObj');
var cacheObj = $.parseJSON(temp);
// create cache object if it doesn't exist
if (cacheObj === null) {
var cacheObj = new Object();
}
// setCache function
// usage: setCache(unique_identifier, data_to_be_cached, minutes_to_remain_cached [optional, default = 60] )
function setCache(postId, postData, validityTime) {
validityTime = typeof validityTime !== 'undefined' ? validityTime : 60;
// get the current time
var milliseconds = new Date().getTime();
if (cacheObj.length > 0) {
var objectExists = false;
//check if we already have this data stored and is current
for (var i = 0; i < cacheObj.length; i++) {
if (cacheObj[i].postId === postId) {
objectExists = true;
}
}
// add the data to the object if it's not there already
if (!objectExists) {
cacheObj.push( { postId: postId, data: postData, expire: (milliseconds + (validityTime * 60 * 1000)) } );
sessionStorage.setItem('cacheObj', JSON.stringify(cacheObj));
}
} else {
cacheObj = [ { postId: postId, data: postData, expire: (milliseconds + (validityTime * 60 * 1000)) } ];
sessionStorage.setItem('cacheObj', JSON.stringify(cacheObj));
}
};
// getCache function
// usage: getCache(unique_identifier)
function getCache(postId) {
// get the current time
var milliseconds = new Date().getTime();
if (cacheObj.length > 0) {
for (var i = 0; i < cacheObj.length; i++) {
if (cacheObj[i].postId === postId) {
// check if item has expired
if (milliseconds < cacheObj[i].expire) {
return cacheObj[i].data;
} else {
// if item expired then remove from cache object
console.log('Object expired, destroying.');
cacheObj.splice(i, 1);
}
}
}
}
return false;
};

View file

@ -1,17 +0,0 @@
window.log = function(){
log.history = log.history || [];
log.history.push(arguments);
arguments.callee = arguments.callee.caller;
if (this.console) {
console.log(Array.prototype.slice.call(arguments));
}
};
function toggle(source) {
checkboxes = document.getElementsByClassName('checkbox');
for (var i in checkboxes) {
checkboxes[i].checked = source.checked;
}
}

View file

@ -1,162 +0,0 @@
/*! DataTables Bootstrap 2 integration
* ©2011-2014 SpryMedia Ltd - datatables.net/license
*/
/**
* DataTables integration for Bootstrap 2. This requires Bootstrap 2 and
* DataTables 1.10 or newer.
*
* This file sets the defaults and adds options to DataTables to style its
* controls using Bootstrap. See http://datatables.net/manual/styling/bootstrap
* for further information.
*/
(function(window, document, $, DataTable, undefined){
$.extend( true, DataTable.defaults, {
"dom":
"<'row-fluid'<'span6'l><'span6'f>r>" +
"<'row-fluid'<'span12't>>" +
"<'row-fluid'<'span6'i><'span6'p>>",
renderer: 'bootstrap'
} );
/* Default class modification */
$.extend( DataTable.ext.classes, {
sWrapper: "dataTables_wrapper form-inline dt-bootstrap"
} );
/* Bootstrap paging button renderer */
DataTable.ext.renderer.pageButton.bootstrap = function ( settings, host, idx, buttons, page, pages ) {
var api = new DataTable.Api( settings );
var classes = settings.oClasses;
var lang = settings.oLanguage.oPaginate;
var btnDisplay, btnClass;
var attach = function( container, buttons ) {
var i, ien, node, button;
var clickHandler = function ( e ) {
e.preventDefault();
if ( !$(e.currentTarget).hasClass('disabled') ) {
api.page( e.data.action ).draw( false );
}
};
for ( i=0, ien=buttons.length ; i<ien ; i++ ) {
button = buttons[i];
if ( $.isArray( button ) ) {
attach( container, button );
}
else {
btnDisplay = '';
btnClass = '';
switch ( button ) {
case 'ellipsis':
btnDisplay = '&hellip;';
btnClass = 'disabled';
break;
case 'first':
btnDisplay = lang.sFirst;
btnClass = button + (page > 0 ?
'' : ' disabled');
break;
case 'previous':
btnDisplay = lang.sPrevious;
btnClass = button + (page > 0 ?
'' : ' disabled');
break;
case 'next':
btnDisplay = lang.sNext;
btnClass = button + (page < pages-1 ?
'' : ' disabled');
break;
case 'last':
btnDisplay = lang.sLast;
btnClass = button + (page < pages-1 ?
'' : ' disabled');
break;
default:
btnDisplay = button + 1;
btnClass = page === button ?
'active' : '';
break;
}
if ( btnDisplay ) {
node = $('<li>', {
'class': classes.sPageButton+' '+btnClass,
'aria-controls': settings.sTableId,
'tabindex': settings.iTabIndex,
'id': idx === 0 && typeof button === 'string' ?
settings.sTableId +'_'+ button :
null
} )
.append( $('<a>', {
'href': '#'
} )
.html( btnDisplay )
)
.appendTo( container );
settings.oApi._fnBindAction(
node, {action: button}, clickHandler
);
}
}
}
};
attach(
$(host).empty().html('<div class="pagination"><ul/></div>').find('ul'),
buttons
);
};
/*
* TableTools Bootstrap compatibility
* Required TableTools 2.1+
*/
if ( DataTable.TableTools ) {
// Set the classes that TableTools uses to something suitable for Bootstrap
$.extend( true, DataTable.TableTools.classes, {
"container": "DTTT btn-group",
"buttons": {
"normal": "btn",
"disabled": "disabled"
},
"collection": {
"container": "DTTT_dropdown dropdown-menu",
"buttons": {
"normal": "",
"disabled": "disabled"
}
},
"print": {
"info": "DTTT_print_info modal"
},
"select": {
"row": "active"
}
} );
// Have the collection use a bootstrap compatible dropdown
$.extend( true, DataTable.TableTools.DEFAULTS.oTags, {
"collection": {
"container": "ul",
"button": "li",
"liner": "a"
}
} );
}
})(window, document, jQuery, jQuery.fn.dataTable);

View file

@ -0,0 +1,8 @@
/*!
DataTables Bootstrap 3 integration
©2011-2014 SpryMedia Ltd - datatables.net/license
*/
(function(l,q){var e=function(b,c){b.extend(!0,c.defaults,{dom:"<'row'<'col-sm-6'l><'col-sm-6'f>><'row'<'col-sm-12'tr>><'row'<'col-sm-5'i><'col-sm-7'p>>",renderer:"bootstrap"});b.extend(c.ext.classes,{sWrapper:"dataTables_wrapper form-inline dt-bootstrap",sFilterInput:"form-control input-sm",sLengthSelect:"form-control input-sm"});c.ext.renderer.pageButton.bootstrap=function(g,e,r,s,i,m){var t=new c.Api(g),u=g.oClasses,j=g.oLanguage.oPaginate,d,f,n=0,p=function(c,e){var k,h,o,a,l=function(a){a.preventDefault();
b(a.currentTarget).hasClass("disabled")||t.page(a.data.action).draw(!1)};k=0;for(h=e.length;k<h;k++)if(a=e[k],b.isArray(a))p(c,a);else{f=d="";switch(a){case "ellipsis":d="&hellip;";f="disabled";break;case "first":d=j.sFirst;f=a+(0<i?"":" disabled");break;case "previous":d=j.sPrevious;f=a+(0<i?"":" disabled");break;case "next":d=j.sNext;f=a+(i<m-1?"":" disabled");break;case "last":d=j.sLast;f=a+(i<m-1?"":" disabled");break;default:d=a+1,f=i===a?"active":""}d&&(o=b("<li>",{"class":u.sPageButton+" "+
f,id:0===r&&"string"===typeof a?g.sTableId+"_"+a:null}).append(b("<a>",{href:"#","aria-controls":g.sTableId,"data-dt-idx":n,tabindex:g.iTabIndex}).html(d)).appendTo(c),g.oApi._fnBindAction(o,{action:a},l),n++)}},h;try{h=b(q.activeElement).data("dt-idx")}catch(l){}p(b(e).empty().html('<ul class="pagination"/>').children("ul"),s);h&&b(e).find("[data-dt-idx="+h+"]").focus()};c.TableTools&&(b.extend(!0,c.TableTools.classes,{container:"DTTT btn-group",buttons:{normal:"btn btn-default",disabled:"disabled"},
collection:{container:"DTTT_dropdown dropdown-menu",buttons:{normal:"",disabled:"disabled"}},print:{info:"DTTT_print_info"},select:{row:"active"}}),b.extend(!0,c.TableTools.DEFAULTS.oTags,{collection:{container:"ul",button:"li",liner:"a"}}))};"function"===typeof define&&define.amd?define(["jquery","datatables"],e):"object"===typeof exports?e(require("jquery"),require("datatables")):jQuery&&e(jQuery,jQuery.fn.dataTable)})(window,document);

View file

@ -26,10 +26,10 @@ $.extend( $.fn.dataTableExt.oPagination, {
}
};
$(nPaging).addClass('pagination').append(
'<ul>'+
'<li class="prev disabled"><a href="#">&larr; '+oLang.sPrevious+'</a></li>'+
'<li class="next disabled"><a href="#">'+oLang.sNext+' &rarr; </a></li>'+
$(nPaging).append(
'<ul class="pagination">'+
'<li class="prev disabled"><a href="#"><i class="icon-double-angle-left"></i> '+oLang.sPrevious+'</a></li>'+
'<li class="next disabled"><a href="#">'+oLang.sNext+' <i class="icon-double-angle-right"></i></a></li>'+
'</ul>'
);
var els = $('a', nPaging);
@ -65,7 +65,7 @@ $.extend( $.fn.dataTableExt.oPagination, {
// Add the new list items and their event handlers
for ( j=iStart ; j<=iEnd ; j++ ) {
sClass = (j==oPaging.iPage+1) ? 'class="active"' : '';
$('<li '+sClass+'><a class="hidden-phone" href="#">'+j+'</a></li>')
$('<li '+sClass+'><a href="#">'+j+'</a></li>')
.insertBefore( $('li:last', an[i])[0] )
.bind('click', function (e) {
e.preventDefault();
@ -89,4 +89,29 @@ $.extend( $.fn.dataTableExt.oPagination, {
}
}
}
} );
} );
$(function(){
$('.datatable').each(function(){
var datatable = $(this);
// SEARCH - Add the placeholder for Search and Turn this into in-line formcontrol
var search_input = datatable.closest('.dataTables_wrapper').find('div[id$=_filter] input');
search_input.attr('placeholder', 'Search')
search_input.addClass('form-control input-small')
search_input.css('width', '250px')
// SEARCH CLEAR - Use an Icon
var clear_input = datatable.closest('.dataTables_wrapper').find('div[id$=_filter] a');
clear_input.html('<i class="icon-remove-circle icon-large"></i>')
clear_input.css('margin-left', '5px')
// LENGTH - Inline-Form control
var length_sel = datatable.closest('.dataTables_wrapper').find('div[id$=_length] select');
length_sel.addClass('form-control input-small')
length_sel.css('width', '75px')
// LENGTH - Info adjust location
var length_sel = datatable.closest('.dataTables_wrapper').find('div[id$=_info]');
length_sel.css('margin-top', '18px')
});
});

View file

@ -240,16 +240,16 @@ function isPrivateIP(ip_address) {
function humanTime(seconds) {
if (seconds >= 86400) {
text = '<h1> / </h1><h3>' + Math.floor(moment.duration(seconds, 'seconds').asDays()) +
text = '<h3>' + Math.floor(moment.duration(seconds, 'seconds').asDays()) +
'</h3><p> days </p><h3>' + Math.floor(moment.duration((seconds % 86400), 'seconds').asHours()) +
'</h3><p> hrs</p><h3>' + Math.floor(moment.duration(((seconds % 86400) % 3600), 'seconds').asMinutes()) + '</h3><p> mins</p>';
return text;
} else if (seconds >= 3600) {
text = '<h1> / </h1><h3>' + Math.floor(moment.duration((seconds % 86400), 'seconds').asHours()) +
text = '<h3>' + Math.floor(moment.duration((seconds % 86400), 'seconds').asHours()) +
'</h3><p>hrs</p><h3>' + Math.floor(moment.duration(((seconds % 86400) % 3600), 'seconds').asMinutes()) + '</h3><p> mins</p>';
return text;
} else if (seconds >= 60) {
text = '<h1> / </h1><h3>' + Math.floor(moment.duration(((seconds % 86400) % 3600), 'seconds').asMinutes()) + '</h3><p> mins</p>';
text = '<h3>' + Math.floor(moment.duration(((seconds % 86400) % 3600), 'seconds').asMinutes()) + '</h3><p> mins</p>';
return text;
}
}

View file

@ -1,2 +0,0 @@
//fgnass.github.com/spin.js#v2.0.1
!function(a,b){"object"==typeof exports?module.exports=b():"function"==typeof define&&define.amd?define(b):a.Spinner=b()}(this,function(){"use strict";function a(a,b){var c,d=document.createElement(a||"div");for(c in b)d[c]=b[c];return d}function b(a){for(var b=1,c=arguments.length;c>b;b++)a.appendChild(arguments[b]);return a}function c(a,b,c,d){var e=["opacity",b,~~(100*a),c,d].join("-"),f=.01+c/d*100,g=Math.max(1-(1-a)/b*(100-f),a),h=j.substring(0,j.indexOf("Animation")).toLowerCase(),i=h&&"-"+h+"-"||"";return l[e]||(m.insertRule("@"+i+"keyframes "+e+"{0%{opacity:"+g+"}"+f+"%{opacity:"+a+"}"+(f+.01)+"%{opacity:1}"+(f+b)%100+"%{opacity:"+a+"}100%{opacity:"+g+"}}",m.cssRules.length),l[e]=1),e}function d(a,b){var c,d,e=a.style;for(b=b.charAt(0).toUpperCase()+b.slice(1),d=0;d<k.length;d++)if(c=k[d]+b,void 0!==e[c])return c;return void 0!==e[b]?b:void 0}function e(a,b){for(var c in b)a.style[d(a,c)||c]=b[c];return a}function f(a){for(var b=1;b<arguments.length;b++){var c=arguments[b];for(var d in c)void 0===a[d]&&(a[d]=c[d])}return a}function g(a,b){return"string"==typeof a?a:a[b%a.length]}function h(a){this.opts=f(a||{},h.defaults,n)}function i(){function c(b,c){return a("<"+b+' xmlns="urn:schemas-microsoft.com:vml" class="spin-vml">',c)}m.addRule(".spin-vml","behavior:url(#default#VML)"),h.prototype.lines=function(a,d){function f(){return e(c("group",{coordsize:k+" "+k,coordorigin:-j+" "+-j}),{width:k,height:k})}function h(a,h,i){b(m,b(e(f(),{rotation:360/d.lines*a+"deg",left:~~h}),b(e(c("roundrect",{arcsize:d.corners}),{width:j,height:d.width,left:d.radius,top:-d.width>>1,filter:i}),c("fill",{color:g(d.color,a),opacity:d.opacity}),c("stroke",{opacity:0}))))}var i,j=d.length+d.width,k=2*j,l=2*-(d.width+d.length)+"px",m=e(f(),{position:"absolute",top:l,left:l});if(d.shadow)for(i=1;i<=d.lines;i++)h(i,-2,"progid:DXImageTransform.Microsoft.Blur(pixelradius=2,makeshadow=1,shadowopacity=.3)");for(i=1;i<=d.lines;i++)h(i);return b(a,m)},h.prototype.opacity=function(a,b,c,d){var e=a.firstChild;d=d.shadow&&d.lines||0,e&&b+d<e.childNodes.length&&(e=e.childNodes[b+d],e=e&&e.firstChild,e=e&&e.firstChild,e&&(e.opacity=c))}}var j,k=["webkit","Moz","ms","O"],l={},m=function(){var c=a("style",{type:"text/css"});return b(document.getElementsByTagName("head")[0],c),c.sheet||c.styleSheet}(),n={lines:12,length:7,width:5,radius:10,rotate:0,corners:1,color:"#000",direction:1,speed:1,trail:100,opacity:.25,fps:20,zIndex:2e9,className:"spinner",top:"50%",left:"50%",position:"absolute"};h.defaults={},f(h.prototype,{spin:function(b){this.stop();{var c=this,d=c.opts,f=c.el=e(a(0,{className:d.className}),{position:d.position,width:0,zIndex:d.zIndex});d.radius+d.length+d.width}if(e(f,{left:d.left,top:d.top}),b&&b.insertBefore(f,b.firstChild||null),f.setAttribute("role","progressbar"),c.lines(f,c.opts),!j){var g,h=0,i=(d.lines-1)*(1-d.direction)/2,k=d.fps,l=k/d.speed,m=(1-d.opacity)/(l*d.trail/100),n=l/d.lines;!function o(){h++;for(var a=0;a<d.lines;a++)g=Math.max(1-(h+(d.lines-a)*n)%l*m,d.opacity),c.opacity(f,a*d.direction+i,g,d);c.timeout=c.el&&setTimeout(o,~~(1e3/k))}()}return c},stop:function(){var a=this.el;return a&&(clearTimeout(this.timeout),a.parentNode&&a.parentNode.removeChild(a),this.el=void 0),this},lines:function(d,f){function h(b,c){return e(a(),{position:"absolute",width:f.length+f.width+"px",height:f.width+"px",background:b,boxShadow:c,transformOrigin:"left",transform:"rotate("+~~(360/f.lines*k+f.rotate)+"deg) translate("+f.radius+"px,0)",borderRadius:(f.corners*f.width>>1)+"px"})}for(var i,k=0,l=(f.lines-1)*(1-f.direction)/2;k<f.lines;k++)i=e(a(),{position:"absolute",top:1+~(f.width/2)+"px",transform:f.hwaccel?"translate3d(0,0,0)":"",opacity:f.opacity,animation:j&&c(f.opacity,f.trail,l+k*f.direction,f.lines)+" "+1/f.speed+"s linear infinite"}),f.shadow&&b(i,e(h("#000","0 0 4px #000"),{top:"2px"})),b(d,b(i,h(g(f.color,k),"0 0 1px rgba(0,0,0,.1)")));return d},opacity:function(a,b,c){b<a.childNodes.length&&(a.childNodes[b].style.opacity=c)}});var o=e(a("group"),{behavior:"url(#default#VML)"});return!d(o,"transform")&&o.adj?i():j=d(o,"animation"),h});

View file

@ -20,7 +20,7 @@ history_table_options = {
"infoFiltered":"(filtered from _MAX_ total entries)",
"emptyTable": "No data in table",
},
"sPaginationType": "bootstrap",
"pagingType": "bootstrap",
"stateSave": true,
"processing": false,
"serverSide": true,
@ -55,17 +55,17 @@ history_table_options = {
$(td).html(cellData);
}
},
"className": "no-wrap hidden-phone"
"className": "no-wrap hidden-xs"
},
{
"targets": [2],
"data":"player",
"createdCell": function (td, cellData, rowData, row, col) {
if (cellData !== '') {
$(td).html('<a href="#info-modal" data-toggle="modal"><span data-toggle="tooltip" data-placement="left" title="Stream Info" id="stream-info"><i class="fa fa-lg fa-info-circle"></i></span></a>&nbsp'+cellData);
$(td).html('<a href="#" data-target="#info-modal" data-toggle="modal"><i class="fa fa-lg fa-info-circle"></i></a>&nbsp'+cellData);
}
},
"className": "modal-control no-wrap hidden-tablet hidden-phone"
"className": "modal-control no-wrap hidden-sm hidden-xs"
},
{
"targets": [3],
@ -75,7 +75,7 @@ history_table_options = {
$(td).html('n/a');
}
},
"className": "no-wrap hidden-phone"
"className": "no-wrap hidden-xs"
},
{
"targets": [4],
@ -103,7 +103,7 @@ history_table_options = {
return moment(data, "X").format(time_format);
},
"searchable": false,
"className": "no-wrap hidden-tablet hidden-phone"
"className": "no-wrap hidden-sm hidden-xs"
},
{
"targets": [6],
@ -116,7 +116,7 @@ history_table_options = {
}
},
"searchable": false,
"className": "no-wrap hidden-phone"
"className": "no-wrap hidden-xs"
},
{
"targets": [7],
@ -129,7 +129,7 @@ history_table_options = {
}
},
"searchable": false,
"className": "no-wrap hidden-tablet hidden-phone"
"className": "no-wrap hidden-md hidden-xs"
},
{
"targets": [8],
@ -142,7 +142,7 @@ history_table_options = {
}
},
"searchable": false,
"className": "no-wrap hidden-phone"
"className": "no-wrap hidden-xs"
},
{
"targets": [9],
@ -157,14 +157,18 @@ history_table_options = {
}
},
"searchable": false,
"orderable": true,
"className": "no-wrap hidden-tablet hidden-phone"
"orderable": false,
"className": "no-wrap hidden-md hidden-xs"
}
],
"drawCallback": function (settings) {
// Jump to top of page
// $('html,body').scrollTop(0);
$('#ajaxMsg').fadeOut();
// Create the tooltips.
$('.info-modal').each(function() {
$(this).tooltip();
});
},
"preDrawCallback": function(settings) {
var msg = "<div class='msg'><i class='fa fa-refresh fa-spin'></i>&nbspFetching rows...</div>";
@ -172,10 +176,6 @@ history_table_options = {
}
}
$('#history_table').on('mouseenter', 'td.modal-control span', function () {
$(this).tooltip();
});
$('#history_table').on('click', 'td.modal-control', function () {
var tr = $(this).parents('tr');
var row = history_table.row( tr );

View file

@ -2,7 +2,7 @@ var log_table_options = {
"destroy": true,
"serverSide": true,
"processing": false,
"sPaginationType": "bootstrap",
"pagingType": "bootstrap",
"order": [ 0, 'desc'],
"pageLength": 10,
"stateSave": true,
@ -17,12 +17,12 @@ var log_table_options = {
{
"targets": [0],
"width": "15%",
"className": "no-wrap hidden-phone"
"className": "no-wrap hidden-xs"
},
{
"targets": [1],
"width": "10%",
"className": "no-wrap hidden-tablet hidden-phone"
"className": "no-wrap hidden-sm hidden-xs"
},
{
"targets": [2],

View file

@ -2,7 +2,7 @@ var plex_log_table_options = {
"destroy": true,
"processing": false,
"serverSide": false,
"sPaginationType": "bootstrap",
"pagingType": "bootstrap",
"order": [ 0, 'desc'],
"pageLength": 10,
"stateSave": true,
@ -17,12 +17,12 @@ var plex_log_table_options = {
{
"targets": [0],
"width": "15%",
"className": "no-wrap hidden-phone"
"className": "no-wrap hidden-xs"
},
{
"targets": [1],
"width": "10%",
"className": "no-wrap hidden-tablet hidden-phone"
"className": "no-wrap hidden-sm hidden-xs"
},
{
"targets": [2],

View file

@ -1,7 +1,7 @@
sync_table_options = {
"processing": false,
"serverSide": false,
"sPaginationType": "bootstrap",
"pagingType": "bootstrap",
"order": [ 0, 'desc'],
"pageLength": 25,
"stateSave": true,
@ -26,7 +26,7 @@ sync_table_options = {
$(td).html(cellData.toProperCase());
}
},
"className": "no-wrap hidden-phone"
"className": "no-wrap hidden-xs"
},
{
"targets": [1],
@ -57,17 +57,17 @@ sync_table_options = {
"render": function ( data, type, full ) {
return data.toProperCase();
},
"className": "no-wrap hidden-tablet hidden-phone"
"className": "no-wrap hidden-sm hidden-xs"
},
{
"targets": [4],
"data": "device_name",
"className": "no-wrap hidden-phone"
"className": "no-wrap hidden-xs"
},
{
"targets": [5],
"data": "platform",
"className": "no-wrap hidden-tablet hidden-phone"
"className": "no-wrap hidden-sm hidden-xs"
},
{
"targets": [6],
@ -80,22 +80,22 @@ sync_table_options = {
$(td).html('0MB');
}
},
"className": "no-wrap hidden-tablet hidden-phone"
"className": "no-wrap hidden-sm hidden-xs"
},
{
"targets": [7],
"data": "item_count",
"className": "no-wrap hidden-phone"
"className": "no-wrap hidden-xs"
},
{
"targets": [8],
"data": "item_complete_count",
"className": "no-wrap hidden-tablet hidden-phone"
"className": "no-wrap hidden-sm hidden-xs"
},
{
"targets": [9],
"data": "item_downloaded_count",
"className": "no-wrap hidden-tablet hidden-phone"
"className": "no-wrap hidden-sm hidden-xs"
},
{
"targets": [10],
@ -107,7 +107,7 @@ sync_table_options = {
$(td).html('<span class="badge">0%</span>');
}
},
"className": "no-wrap hidden-tablet hidden-phone"
"className": "no-wrap hidden-sm hidden-xs"
}
],
"drawCallback": function (settings) {

View file

@ -9,7 +9,7 @@ user_ip_table_options = {
"emptyTable": "No data in table",
},
"stateSave": true,
"sPaginationType": "bootstrap",
"pagingType": "bootstrap",
"processing": false,
"serverSide": true,
"pageLength": 10,
@ -40,7 +40,7 @@ user_ip_table_options = {
$(td).html('n/a');
}
} else {
$(td).html('<a href="#ip-info-modal" data-toggle="modal"><span data-toggle="ip-tooltip" data-placement="left" title="IP Address Info" id="ip-info"><i class="icon-map-marker icon-white"></i></span>&nbsp' + cellData +'</a>');
$(td).html('<a href="javascript:void(0)" data-toggle="modal" data-target="#ip-info-modal"><span data-toggle="ip-tooltip" data-placement="left" title="IP Address Info" id="ip-info"><i class="fa fa-map-marker"></i></span>&nbsp' + cellData +'</a>');
}
} else {
$(td).html('n/a');
@ -52,19 +52,19 @@ user_ip_table_options = {
"targets": [2],
"data":"play_count",
"width": "10%",
"className": "hidden-phone"
"className": "hidden-xs"
},
{
"targets": [3],
"data":"platform",
"width": "15%",
"className": "hidden-phone"
"className": "hidden-xs"
},
{
"targets": [4],
"data":"last_watched",
"width": "30%",
"className": "hidden-tablet hidden-phone"
"className": "hidden-sm hidden-xs"
}
],
"drawCallback": function (settings) {

View file

@ -14,7 +14,7 @@ users_list_table_options = {
"order": [ 1, 'asc'],
"autoWidth": true,
"stateSave": true,
"sPaginationType": "bootstrap",
"pagingType": "bootstrap",
"columnDefs": [
{
"targets": [0],
@ -51,13 +51,13 @@ users_list_table_options = {
"render": function ( data, type, full ) {
return moment(data, "X").fromNow();
},
"className": "hidden-phone",
"className": "hidden-xs",
},
{
"targets": [3],
"data": "ip_address",
"searchable": false,
"className": "hidden-phone",
"className": "hidden-xs",
},
{
"targets": [4],

View file

@ -4,7 +4,8 @@ from plexpy import helpers
%>
<%def name="headIncludes()">
<link rel="stylesheet" href="interfaces/default/css/plexwatch-tables.css">
<link rel="stylesheet" href="interfaces/default/css/dataTables.bootstrap.css">
<link rel="stylesheet" href="interfaces/default/css/plexpy-dataTables.css">
<style>
td {word-break: break-all;}
</style>
@ -15,51 +16,46 @@ from plexpy import helpers
<%def name="body()">
<div class='container-fluid'>
<div class='row-fluid'>
<div class='span12'>
<div class='table-card-back'>
<div class="header-bar">
<h2><i class="fa fa-book"></i> Logs</h2>
<div class='table-card-back'>
<div class="header-bar">
<span><i class="fa fa-book"></i> Logs</span>
</div>
<div class="button-bar">
<button class="squared" id="clear-logs"><i class="fa fa-trash-o"></i> Clear log</button>
</div>
</div>
<div class='table-card-back'>
<div>
<ul class="nav nav-pills" role="tablist">
<li role="presentation" class="active"><a id="plexpy-logs-btn" href="#tabs-1" aria-controls="tabs-1" role="tab" data-toggle="tab">PlexPy Logs</a></li>
<li role="presentation"><a id="plex-logs-btn" href="#tabs-2" aria-controls="tabs-2" role="tab" data-toggle="tab">Plex Media Server Logs</a></li>
</ul>
<div class="tab-content">
<div role="tabpanel" class="tab-pane active" id="tabs-1">
<table class="display" id="log_table" width="100%">
<thead>
<tr>
<th class="min-tablet" align='left' id="timestamp">Timestamp</th>
<th class="desktop" align='left' id="level">Level</th>
<th class="all" align='left' id="message">Message</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
<div class="button-bar">
<button class="squared" id="clear-logs"><i class="fa fa-trash-o"></i> Clear log</button>
</div>
</div>
<div class='table-card-back'>
<div role="tabpanel">
<ul class="nav nav-pills" role="tablist">
<li role="presentation" class="active"><a id="plexpy-logs-btn" href="#tabs-1" aria-controls="tabs-1" role="tab" data-toggle="tab">PlexPy Logs</a></li>
<li role="presentation"><a id="plex-logs-btn" href="#tabs-2" aria-controls="tabs-2" role="tab" data-toggle="tab">Plex Media Server Logs</a></li>
</ul>
<div class="tab-content">
<div role="tabpanel" class="tab-pane active" id="tabs-1">
<table class="display" id="log_table" width="100%">
<thead>
<tr>
<th class="min-tablet" align='left' id="timestamp">Timestamp</th>
<th class="desktop" align='left' id="level">Level</th>
<th class="all" align='left' id="message">Message</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
<div role="tabpanel" class="tab-pane" id="tabs-2">
<table class="display" id="plex_log_table" width="100%">
<thead>
<tr>
<th align='left' id="plex_timestamp">Timestamp</th>
<th align='left' id="plex_level">Level</th>
<th align='left' id="plex_message">Message</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
<div role="tabpanel" class="tab-pane" id="tabs-2">
<table class="display" id="plex_log_table" width="100%">
<thead>
<tr>
<th align='left' id="plex_timestamp">Timestamp</th>
<th align='left' id="plex_level">Level</th>
<th align='left' id="plex_message">Message</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
</div>
@ -78,12 +74,12 @@ from plexpy import helpers
<option value="600">10 Minutes</option>
</select>
</div>
</div>
</%def>
<%def name="javascriptIncludes()">
<script src="interfaces/default/js/jquery.dataTables.min.js"></script>
<script src="interfaces/default/js/jquery.dataTables.bootstrap.pagination.integration.js"></script>
<script src="interfaces/default/js/dataTables.bootstrap.min.js"></script>
<script src="interfaces/default/js/dataTables.bootstrap.pagination.js"></script>
<script src="interfaces/default/js/tables/logs.js"></script>
<script src="interfaces/default/js/tables/plex_logs.js"></script>
<script>

View file

@ -1,39 +1,42 @@
% if data:
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true"><i
class="fa fa-remove"></i></button>
<h3 id="notification-config-modal-header">Set Config</h3>
</div>
<div class="modal-body" id="">
<div class="container-fluid">
<div class="row-fluid">
<form action="set_notification_config" method="post" class="form" id="set_notification_config" data-parsley-validate>
<div class="span6">
% for item in data:
% if item['input_type'] != 'checkbox':
<div class="form-group">
<label for="${item['name']}">${item['label']}</label>
<input type="${item['input_type']}" id="${item['name']}" name="${item['name']}" value="${item['value']}" size="30">
% if item['name'] == 'osx_notify_app':
<input type="button" class="btn btn-link" value="Register" id="osxnotifyregister">
% endif
<p class="help-block">${item['description']}</p>
</div>
% elif item['input_type'] == 'checkbox':
<div class="checkbox">
<input type="checkbox" id="${item['name']}" name="${item['name']}" value="1" ${item['value']}> ${item['label']}
<p class="help-block">${item['description']}</p>
</div>
% endif
% endfor
</div>
</form>
<div class="modal-dialog" role="document">
<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 id="notification-config-modal-header">Set Config</h4>
</div>
<div class="modal-body">
<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">
% for item in data:
% if item['input_type'] != 'checkbox':
<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">
% if item['name'] == 'osx_notify_app':
<a href="javascript:void(0)" id="osxnotifyregister">Register</a>
% endif
<p class="help-block">${item['description']}</p>
</div>
% elif item['input_type'] == 'checkbox':
<div class="checkbox">
<label>
<input type="checkbox" id="${item['name']}" name="${item['name']}" value="1" ${item['value']}> ${item['label']}
</label>
<p class="help-block">${item['description']}</p>
</div>
% endif
% endfor
</div>
</form>
</div>
</div>
</div>
<div class="modal-footer">
<input type="button" id="save-notification-item" class="squared squared-primary" value="Save">
</div>
</div>
</div>
<div class="modal-footer">
<div class="">
<input type="button" id="save-notification-item" class="squared squared-primary" value="Save">
</div>
</div>
% endif

View file

@ -1,31 +1,47 @@
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true"><i class="fa fa-remove"></i></button>
<h3>Import PlexWatch Database</h3>
</div>
<div class="modal-body" id="modal-text">
<div class="form-group">
<label for="db_location">Database Location</label>
<input type="text" class="input-xlarge" id="db_location" name="db_location" value="" required>
<p class="help-block">Enter the path and file name for the PlexWatch database you wish to import.</p>
</div>
<div class="form-group">
<label for="table_name">Table Name</label>
<select id="table_name" name="table_name">
<option value="processed">processed</option>
<option value="processed">grouped</option>
</select>
<p class="help-block">The table name from which you wish to import. Only import one of these, importing both will result in duplicated data.</p>
</div>
<div class="form-group">
<label for="import_ignore_interval">Ignore Interval</label>
<input type="text" class="input-mini" id="import_ignore_interval" name="import_ignore_interval" value="120" required>
<p class="help-block">Enter the minimum duration (in seconds) an item must have been active for. Set to 0 to import all.</p>
</div>
</div>
<div class="modal-footer">
<div>
<input type="button" id="import_db" class="squared squared-primary" value="Import">
<span id="status-message"></span>
<div class="modal-dialog" role="document">
<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>Import PlexWatch Database</h4>
</div>
<div class="modal-body" id="modal-text">
<div class="form-group">
<label for="db_location">Database Location</label>
<div class="row">
<div class="col-xs-8">
<input type="text" class="form-control" id="db_location" name="db_location" value="" required>
</div>
</div>
<p class="help-block">Enter the path and file name for the PlexWatch database you wish to import.</p>
</div>
<div class="form-group">
<label for="table_name">Table Name</label>
<div class="row">
<div class="col-xs-4">
<select id="table_name" class="form-control" name="table_name">
<option value="processed">processed</option>
<option value="processed">grouped</option>
</select>
</div>
</div>
<p class="help-block">The table name from which you wish to import. Only import one of these, importing both will result in duplicated data.</p>
</div>
<div class="form-group">
<label for="import_ignore_interval">Ignore Interval</label>
<div class="row">
<div class="col-xs-2">
<input type="text" class="form-control" id="import_ignore_interval" name="import_ignore_interval" value="120" required>
</div>
</div>
<p class="help-block">Enter the minimum duration (in seconds) an item must have been active for. Set to 0 to import all.</p>
</div>
</div>
<div class="modal-footer">
<div>
<span id="status-message"></span>
<input type="button" id="import_db" class="squared squared-primary" value="Import">
</div>
</div>
</div>
</div>
<script>

View file

@ -24,7 +24,7 @@ DOCUMENTATION :: END
% if data != None:
<div class="dashboard-recent-media-row">
<ul class="dashboard-recent-media">
<ul class="dashboard-recent-media list-unstyled">
% for item in data:
<div class="dashboard-recent-media-instance">
<li>
@ -47,20 +47,17 @@ DOCUMENTATION :: END
% elif item['type'] == 'movie':
<h3>${item['title']} (${item['year']})</h3>
% endif
<div class="muted" id="added_at-${item['rating_key']}">${item['added_at']}</div>
<div class="text-muted" id="added_at-${item['rating_key']}">${item['added_at']}</div>
</div>
</li>
</div>
<script>
$('#added_at-${item['rating_key']}').html('Added ' + moment(${item['added_at']}, "X").fromNow())
</script>
% endfor
</ul>
</div>
% else:
<div class="muted">There was an error communicating with your Plex Server. Please check your <a
href="config">settings</a>.
<div class="muted">There was an error communicating with your Plex Server. Please check your <a href="settings">settings</a>.
</div><br>
% endif

File diff suppressed because it is too large Load diff

View file

@ -6,27 +6,31 @@
<%def name="body()">
<div class="container-fluid">
<div class="row-fluid">
<div class="span12">
<div id="state-change-modal" class="modal hide fade">
<div class="modal-header">
<h3>${message}</h3>
</div>
<div class="modal-body" id="modal-text">
<div align="center">
% if message == "Shutting Down":
<h2><i class="fa fa-refresh fa-spin"></i> PlexPy is ${message}.</h2>
<br/>
% else:
<h2><i class="fa fa-refresh fa-spin"></i> PlexPy is ${message}.</h2>
<br/>
<h3>Restart in <span class="countdown"></span></h3>
% endif
<div class="row">
<div class="col-md-12">
<div id="state-change-modal" class="modal fade">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h4>${message}</h4>
</div>
<div class="modal-body" id="modal-text">
<div align="center">
% if message == "Shutting Down":
<h3><i class="fa fa-refresh fa-spin"></i> PlexPy is ${message}.</h3>
<br/>
% else:
<h3><i class="fa fa-refresh fa-spin"></i> PlexPy is ${message}.</h3>
<br/>
<h4>Restart in <span class="countdown"></span></h4>
% endif
</div>
</div>
<div class="modal-footer">
<div style="float: right;"><span class="text-muted" id="rquote">${quote}</span></div>
</div>
</div>
</div>
<div class="modal-footer">
<div style="float: right;"><span class="muted" id="rquote">${quote}</span></div>
</div>
</div>
</div>
</div>

View file

@ -37,72 +37,84 @@ DOCUMENTATION :: END
</%doc>
% if data is not None:
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true"><i class="fa fa-remove"></i></button>
% if data['media_type'] == 'episode':
<h3 id="myModalLabel">Stream Info: <strong>${data['grandparent_title']} - ${data['title']} (${user})</strong></h3>
% else:
<h3 id="myModalLabel">Stream Info: <strong>${data['title']} (${user})</strong></h3>
% endif
</div>
<div class="modal-body" id="modal-text">
<div class="span4">
<h4>Stream Details</h4>
<ul>
<h5>Video</h5>
% if data['transcode_video_dec'] != 'direct play':
<li>Stream Type: <strong>${data['transcode_video_dec']}</strong></li>
<li>Video Resolution: <strong>${data['transcode_height']}p</strong></li>
<li>Video Codec: <strong>${data['transcode_video_codec']}</strong></li>
<li>Video Width: <strong>${data['transcode_width']}</strong></li>
<li>Video Height: <strong>${data['transcode_height']}</span></strong></li>
% else:
<li>Stream Type: <strong>${data['transcode_video_dec']}</strong></li>
% if data['video_resolution'] != 'sd':
<li>Video Resolution: <strong>${data['video_resolution']}p</strong></li>
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="info-modal-title">
% if data['media_type'] == 'episode':
Stream Info: <strong>${data['grandparent_title']} - ${data['title']} (${user})</strong>
% else:
<li>Video Resolution: <strong>${data['video_resolution']}</strong></li>
Stream Info: <strong>${data['title']} (${user})</strong>
% endif
<li>Video Codec: <strong>${data['video_codec']}</strong></li>
<li>Video Width: <strong>${data['width']}</strong></li>
<li>Video Height: <strong>${data['height']}</span></strong></li>
% endif
</ul>
<ul>
<h5>Audio</h5>
% if data['transcode_audio_dec'] != 'direct play':
<li>Stream Type: <strong>${data['transcode_audio_dec']}</strong></li>
<li>Audio Codec: <strong>${data['transcode_audio_codec']}</strong></li>
<li>Audio Channels: <strong>${data['transcode_audio_channels']}</strong></li>
% else:
<li>Stream Type: <strong>${data['transcode_audio_dec']}</strong></li>
<li>Audio Codec: <strong>${data['audio_codec']}</strong></li>
<li>Audio Channels: <strong>${data['audio_channels']}</strong></li>
% endif
</ul>
</div>
<div class="span4">
<h4>Media Source Details</h4>
<li>Container: <strong>${data['container']}</strong></li>
<li>Resolution: <strong>${data['height']}p</strong></li>
<li>Bitrate: <strong>${data['bitrate']} kbps</strong></li>
</div>
<div class="span4">
<h4>Video Source Details</h4>
<ul>
<li>Width: <strong>${data['width']}</strong></li>
<li>Height: <strong>${data['height']}</strong></li>
<li>Aspect Ratio: <strong>${data['aspect_ratio']}</strong></li>
<li>Video Frame Rate: <strong>${data['video_framerate']}</span></strong></li>
<li>Video Codec: <strong>${data['video_codec']}</strong></li>
</ul>
<ul></ul>
<h4>Audio Source Details</h4>
<ul>
<li>Audio Codec: <strong>${data['audio_codec']}</strong></li>
<li>Audio Channels: <strong>${data['audio_channels']}</strong></li>
</ul>
</h4>
</div>
<div class="modal-body">
<div class="container-fluid">
<div class="row">
<div class="col-md-4">
<h4><strong>Stream Details</strong></h4>
<h5>Video</h5>
<ul>
% if data['transcode_video_dec'] != 'direct play':
<li>Stream Type: <strong>${data['transcode_video_dec']}</strong></li>
<li>Video Resolution: <strong>${data['transcode_height']}p</strong></li>
<li>Video Codec: <strong>${data['transcode_video_codec']}</strong></li>
<li>Video Width: <strong>${data['transcode_width']}</strong></li>
<li>Video Height: <strong>${data['transcode_height']}</strong></li>
% else:
<li>Stream Type: <strong>${data['transcode_video_dec']}</strong></li>
% if data['video_resolution'] != 'sd':
<li>Video Resolution: <strong>${data['video_resolution']}p</strong></li>
% else:
<li>Video Resolution: <strong>${data['video_resolution']}</strong></li>
% endif
<li>Video Codec: <strong>${data['video_codec']}</strong></li>
<li>Video Width: <strong>${data['width']}</strong></li>
<li>Video Height: <strong>${data['height']}</strong></li>
% endif
</ul>
<h5>Audio</h5>
<ul>
% if data['transcode_audio_dec'] != 'direct play':
<li>Stream Type: <strong>${data['transcode_audio_dec']}</strong></li>
<li>Audio Codec: <strong>${data['transcode_audio_codec']}</strong></li>
<li>Audio Channels: <strong>${data['transcode_audio_channels']}</strong></li>
% else:
<li>Stream Type: <strong>${data['transcode_audio_dec']}</strong></li>
<li>Audio Codec: <strong>${data['audio_codec']}</strong></li>
<li>Audio Channels: <strong>${data['audio_channels']}</strong></li>
% endif
</ul>
</div>
<div class="col-md-4">
<h4><strong>Media Source Details</strong></h4>
<ul>
<li>Container: <strong>${data['container']}</strong></li>
<li>Resolution: <strong>${data['height']}p</strong></li>
<li>Bitrate: <strong>${data['bitrate']} kbps</strong></li>
</ul>
</div>
<div class="col-md-4">
<h4><strong>Video Source Details</strong></h4>
<ul>
<li>Width: <strong>${data['width']}</strong></li>
<li>Height: <strong>${data['height']}</strong></li>
<li>Aspect Ratio: <strong>${data['aspect_ratio']}</strong></li>
<li>Video Frame Rate: <strong>${data['video_framerate']}</strong></li>
<li>Video Codec: <strong>${data['video_codec']}</strong></li>
</ul>
<h4><strong>Audio Source Details</strong></h4>
<ul>
<li>Audio Codec: <strong>${data['audio_codec']}</strong></li>
<li>Audio Channels: <strong>${data['audio_channels']}</strong></li>
</ul>
</div>
</div>
</div>
</div>
<div class="modal-footer">
</div>
</div>
</div>
<div class="modal-footer"></div>
% endif

View file

@ -1,10 +1,8 @@
<%inherit file="base.html"/>
<%!
from plexpy import helpers
%>
<%def name="headIncludes()">
<link rel="stylesheet" href="interfaces/default/css/plexwatch-tables.css">
<link rel="stylesheet" href="interfaces/default/css/dataTables.bootstrap.css">
<link rel="stylesheet" href="interfaces/default/css/plexpy-dataTables.css">
<link rel="stylesheet" href="interfaces/default/css/dataTables.colVis.css">
<style>
td {word-wrap: break-word}
@ -16,47 +14,42 @@ from plexpy import helpers
<%def name="body()">
<div class='container-fluid'>
<div class='row-fluid'>
<div class='span12'>
<div class='table-card-back'>
<div class="header-bar">
<h2><i class="fa fa-cloud-download"></i> Synced Items</h2>
</div>
<div class="colvis-button-bar hidden-phone">
</div>
</div>
<div class='table-card-back'>
<table class="display" id="sync_table" width="100%">
<thead>
<tr>
<th align='left' id="state">State</th>
<th align='left' id="username">Username</th>
<th align='left' id="title">Title</th>
<th align='left' id="type">Type</th>
<th align='left' id="device">Device</th>
<th align='left' id="platform">Platform</th>
<th align='left' id="size">Total Size</th>
<th align='left' id="items">Total Items</th>
<th align='left' id="converted">Converted</th>
<th align='left' id="downloaded">Downloaded</th>
<th align='left' id="percent_complete">Complete</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
<div class='table-card-back'>
<div class="header-bar">
<span><i class="fa fa-cloud-download"></i> Synced Items</span>
</div>
<div class="colvis-button-bar hidden-phone">
</div>
</div>
</div>
<div class='table-card-back'>
<table class="display" id="sync_table" width="100%">
<thead>
<tr>
<th align='left' id="state">State</th>
<th align='left' id="username">Username</th>
<th align='left' id="title">Title</th>
<th align='left' id="type">Type</th>
<th align='left' id="device">Device</th>
<th align='left' id="platform">Platform</th>
<th align='left' id="size">Total Size</th>
<th align='left' id="items">Total Items</th>
<th align='left' id="converted">Converted</th>
<th align='left' id="downloaded">Downloaded</th>
<th align='left' id="percent_complete">Complete</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
</%def>
<%def name="javascriptIncludes()">
<script src="interfaces/default/js/jquery.dataTables.min.js"></script>
<script src="interfaces/default/js/dataTables.bootstrap.min.js"></script>
<script src="interfaces/default/js/dataTables.bootstrap.pagination.js"></script>
<script src="interfaces/default/js/dataTables.colVis.js"></script>
<script src="interfaces/default/js/jquery.dataTables.bootstrap.pagination.integration.js"></script>
<script src="interfaces/default/js/tables/sync_table.js"></script>
<script>
$(document).ready(function() {

View file

@ -28,21 +28,22 @@ from plexpy import helpers
%>
<%def name="headIncludes()">
<link rel="stylesheet" href="interfaces/default/css/plexwatch-tables.css">
<link rel="stylesheet" href="interfaces/default/css/dataTables.bootstrap.css">
<link rel="stylesheet" href="interfaces/default/css/dataTables.colVis.css">
<link rel="stylesheet" href="interfaces/default/css/plexpy-dataTables.css">
</%def>
% if user != None:
<%def name="body()">
<div class="container-fluid">
<div class="row-fluid">
<div class="span12">
<div class="row">
<div class="col-md-12">
<div class="user-info-wrapper">
<div class="user-info-poster-face" id="user-gravatar">
<img src="${data['thumb']}" height="80px" width="80px">
</div>
<div class="user-info-username">
<span class="set-username">${data['friendly_name']}</span> <a href="#edit-user-modal" data-toggle="modal" id="toggle-edit-user-modal"><i class="fa fa-pencil"></i></a>
<span class="set-username">${data['friendly_name']}</span> <a href="#" data-toggle="modal" data-target="#edit-user-modal" id="toggle-edit-user-modal"><i class="fa fa-pencil"></i></a>
</div>
<div class="user-info-nav">
<ul class="user-info-nav">
@ -55,59 +56,47 @@ from plexpy import helpers
</div>
</div>
</div>
<div id="edit-user-modal" class="modal hide fade" tabindex="-1" role="dialog"
aria-labelledby="edit-user-modal" aria-hidden="true">
<div id="edit-user-modal" class="modal fade" tabindex="-1" role="dialog"
aria-labelledby="edit-user-modal">
</div>
</div>
<div class="tab-content">
<div class="tab-pane active" id="profile">
<div class="container-fluid">
<div class="row-fluid">
<div class="span12">
<div class="wellbg">
<div class="wellheader">
<div class="dashboard-wellheader">
<h3>Global Stats</h3>
</div>
</div>
<div id="user-time-stats" class="user-overview-stats-wrapper">
<div class='muted'><i class="fa fa-refresh fa-spin"></i> Loading data...</div>
<br>
</div>
<div class="row">
<div class="col-md-12">
<div class="padded-header">
<h3>Global Stats</h3>
</div>
<div id="user-time-stats" class="user-overview-stats-wrapper">
<div class='muted'><i class="fa fa-refresh fa-spin"></i> Loading data...</div>
<br>
</div>
</div>
</div>
</div>
<div class="container-fluid">
<div class="row-fluid">
<div class="span12">
<div class="wellbg">
<div class="wellheader">
<div class="dashboard-wellheader">
<h3>Platform Stats</h3>
</div>
</div>
<div id="user-platform-stats" class="user-platforms">
<div class='muted'><i class="fa fa-refresh fa-spin"></i> Loading data...</div>
<br>
</div>
<div class="row">
<div class="col-md-12">
<div class="padded-header">
<h3>Platform Stats</h3>
</div>
<div id="user-platform-stats" class="user-platforms">
<div class='muted'><i class="fa fa-refresh fa-spin"></i> Loading data...</div>
<br>
</div>
</div>
</div>
</div>
<div class="container-fluid">
<div class="row-fluid">
<div class="span12">
<div class="wellbg">
<div class="wellheader">
<div class="dashboard-wellheader">
<h3>Recently watched</h3>
</div>
</div>
<div id="user-recently-watched">
<div class='muted'><i class="fa fa-refresh fa-spin"></i> Loading data...</div>
<br>
</div>
<div class="row">
<div class="col-md-12">
<div class="padded-header">
<h3>Recently watched</h3>
</div>
<div id="user-recently-watched">
<div class='muted'><i class="fa fa-refresh fa-spin"></i> Loading data...</div>
<br>
</div>
</div>
</div>
@ -115,12 +104,14 @@ from plexpy import helpers
</div>
<div class="tab-pane" id="userAddresses">
<div class="container-fluid">
<div class="row-fluid">
<div class="span12">
<div class="row">
<div class="col-md-12">
<div class="table-card-back">
<h3>IP Addresses for <strong>
<span class="set-username">${data['friendly_name']}</span>
</strong></h3>
<div class="header-bar">
<span>IP Addresses for <strong>
<span class="set-username">${data['friendly_name']}</span>
</strong></span>
</div>
</div>
<div class="table-card-back">
<table id="user_ip_table" class="display" width="100%">
@ -135,35 +126,37 @@ from plexpy import helpers
</thead>
</table>
</div>
<div id="ip-info-modal" class="modal hide fade" tabindex="-1" role="dialog"
aria-labelledby="ip-info-modal" aria-hidden="true">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true"><i
class="fa fa-remove"></i></button>
<h3 id="myModalLabel">IP Address: <strong><span id="modal_header_ip_address"></span></strong></h3>
</div>
<div class="modal-body" id="modal-text">
<div class="span6">
<h4>Location Details</h4>
<ul>
<li>Country: <strong><span id="country"></span></strong></li>
<li>City: <strong><span id="city"></span></strong></li>
<li>Region: <strong><span id="region"></span></strong></li>
<li>Timezone: <strong><span id="timezone"></span></strong></li>
<li>Latitude: <strong><span id="lat"></span></strong></li>
<li>Longitude: <strong><span id="lon"></span></strong></li>
</ul>
</div>
<div class="span6">
<h4>Connection Details</h4>
<ul>
<li>ISP: <strong><span id="isp"></span></strong></li>
<li>Organization: <strong><span id="org"></span></strong></li>
<li>AS: <strong><span id="as"></span></strong></li>
</ul>
<div id="ip-info-modal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="ip-info-modal">
<div class="modal-dialog" role="document">
<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 id="myModalLabel">IP Address: <strong><span id="modal_header_ip_address"></span></strong></h4>
</div>
<div class="modal-body" id="modal-text">
<div class="col-md-6">
<h4><strong>Location Details</strong></h4>
<ul>
<li>Country: <strong><span id="country"></span></strong></li>
<li>City: <strong><span id="city"></span></strong></li>
<li>Region: <strong><span id="region"></span></strong></li>
<li>Timezone: <strong><span id="timezone"></span></strong></li>
<li>Latitude: <strong><span id="lat"></span></strong></li>
<li>Longitude: <strong><span id="lon"></span></strong></li>
</ul>
</div>
<div class="col-md-6">
<h4><strong>Connection Details</strong></h4>
<ul>
<li>ISP: <strong><span id="isp"></span></strong></li>
<li>Organization: <strong><span id="org"></span></strong></li>
<li>AS: <strong><span id="as"></span></strong></li>
</ul>
</div>
</div>
<div class="modal-footer"></div>
</div>
</div>
<div class="modal-footer"></div>
</div>
</div>
</div>
@ -171,15 +164,15 @@ from plexpy import helpers
</div>
<div class="tab-pane" id="userHistory">
<div class="container-fluid">
<div class="row-fluid">
<div class="span12">
<div class="row">
<div class="col-md-12">
<div class='table-card-back'>
<div class="header-bar">
<h3>Watch History for <strong>
<span>Watch History for <strong>
<span class="set-username">${data['friendly_name']}</span>
</strong></h3>
</strong></span>
</div>
<div class="colvis-button-bar hidden-phone" id="button-bar-history">
<div class="colvis-button-bar hidden-xs" id="button-bar-history">
</div>
</div>
<div class="table-card-back">
@ -202,46 +195,44 @@ from plexpy import helpers
</tbody>
</table>
</div>
<div id="info-modal" class="modal hide fade" tabindex="-1" role="dialog"
aria-labelledby="info-modal" aria-hidden="true">
</div>
<div id="info-modal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="info-modal"></div>
</div>
</div>
</div>
</div>
<div class="tab-pane" id="userSyncItems">
<div class="container-fluid">
<div class="row-fluid">
<div class="span12">
<div class="row">
<div class="col-md-12">
<div class='table-card-back'>
<div class="header-bar">
<h3>Synced Items for <strong>
<span class="set-username">${data['friendly_name']}</span>
</strong></h3>
<span>Synced Items for <strong>
<span class="set-username">${data['friendly_name']}</span>
</strong></span>
</div>
<div class="colvis-button-bar hidden-phone" id="button-bar-sync">
<div class="colvis-button-bar hidden-xs" id="button-bar-sync">
</div>
</div>
<div class="table-card-back">
<table class="display" id="sync_table" width="100%">
<thead>
<tr>
<th align='left' id="state">State</th>
<th align='left' id="username">Username</th>
<th align='left' id="sync_title">Title</th>
<th align='left' id="type">Type</th>
<th align='left' id="device">Device</th>
<th align='left' id="sync_platform">Platform</th>
<th align='left' id="size">Total Size</th>
<th align='left' id="items">Total Items</th>
<th align='left' id="converted">Converted</th>
<th align='left' id="downloaded">Downloaded</th>
<th align='left' id="sync_percent_complete">Complete</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<thead>
<tr>
<th align='left' id="state">State</th>
<th align='left' id="username">Username</th>
<th align='left' id="sync_title">Title</th>
<th align='left' id="type">Type</th>
<th align='left' id="device">Device</th>
<th align='left' id="sync_platform">Platform</th>
<th align='left' id="size">Total Size</th>
<th align='left' id="items">Total Items</th>
<th align='left' id="converted">Converted</th>
<th align='left' id="downloaded">Downloaded</th>
<th align='left' id="sync_percent_complete">Complete</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
</div>
@ -254,115 +245,114 @@ from plexpy import helpers
<%def name="javascriptIncludes()">
<script src="interfaces/default/js/jquery.dataTables.min.js"></script>
<script src="interfaces/default/js/dataTables.colVis.js"></script>
<script src="interfaces/default/js/jquery.dataTables.bootstrap.pagination.integration.js"></script>
<script src="interfaces/default/js/dataTables.bootstrap.min.js"></script>
<script src="interfaces/default/js/dataTables.bootstrap.pagination.js"></script>
<script src="interfaces/default/js/moment-with-locale.js"></script>
<script src="interfaces/default/js/tables/history_table.js"></script>
<script src="interfaces/default/js/tables/user_ips.js"></script>
<script src="interfaces/default/js/tables/sync_table.js"></script>
<script>
$(document).ready(function () {
$(document).ready(function () {
% if data['user_id']:
var user_id = ${data['user_id']};
% else:
var user_id = null;
% endif
% if data['user_id']:
var user_id = ${data['user_id']};
% else:
var user_id = null;
% endif
// Populate watch time stats
$.ajax({
url: 'get_user_watch_time_stats',
async: true,
data: { user_id: user_id, user: '${data['username']}' },
complete: function(xhr, status) {
$("#user-time-stats").html(xhr.responseText);
}
});
// Populate watch time stats
$.ajax({
url: 'get_user_watch_time_stats',
async: true,
data: { user_id: user_id, user: '${data['username']}' },
complete: function(xhr, status) {
$("#user-time-stats").html(xhr.responseText);
}
});
// Populate platform stats
$.ajax({
url: 'get_user_platform_stats',
async: true,
data: { user_id: user_id, user: '${data['username']}' },
complete: function(xhr, status) {
$("#user-platform-stats").html(xhr.responseText);
}
});
// Populate platform stats
$.ajax({
url: 'get_user_platform_stats',
async: true,
data: { user_id: user_id, user: '${data['username']}' },
complete: function(xhr, status) {
$("#user-platform-stats").html(xhr.responseText);
}
});
// Populate recently watched
$.ajax({
url: 'get_user_recently_watched',
async: true,
data: { user_id: user_id, user: '${data['username']}' },
complete: function(xhr, status) {
$("#user-recently-watched").html(xhr.responseText);
}
});
// Populate recently watched
$.ajax({
url: 'get_user_recently_watched',
async: true,
data: { user_id: user_id, user: '${data['username']}' },
complete: function(xhr, status) {
$("#user-recently-watched").html(xhr.responseText);
}
});
$( "#history-tab-btn" ).one( "click", function() {
// Build watch history table
history_table_options.ajax = {
"url": "get_history",
type: 'post',
data: function ( d ) {
return { 'json_data': JSON.stringify( d ),
'user_id': user_id,
'user': "${data['username']}"
};
}
}
history_table = $('#history_table').DataTable(history_table_options);
history_table.column(1).visible(false);
$( "#history-tab-btn" ).one( "click", function() {
// Build watch history table
history_table_options.ajax = {
"url": "get_history",
type: 'post',
data: function ( d ) {
return { 'json_data': JSON.stringify( d ),
'user_id': user_id,
'user': "${data['username']}"
};
}
}
history_table = $('#history_table').DataTable(history_table_options);
history_table.column(1).visible(false);
var colvis = new $.fn.dataTable.ColVis(history_table);
$(colvis.button()).appendTo('#button-bar-history');
});
var colvis = new $.fn.dataTable.ColVis(history_table);
$(colvis.button()).appendTo('#button-bar-history');
});
$( "#ip-tab-btn" ).one( "click", function() {
// Build user IP table
user_ip_table_options.ajax = {
"url": "get_user_ips",
type: 'post',
data: function ( d ) {
return { 'json_data': JSON.stringify( d ),
'user_id': user_id,
'user': "${data['username']}"
};
}
}
user_ip_table = $('#user_ip_table').DataTable(user_ip_table_options);
});
$( "#ip-tab-btn" ).one( "click", function() {
// Build user IP table
user_ip_table_options.ajax = {
"url": "get_user_ips",
type: 'post',
data: function ( d ) {
return { 'json_data': JSON.stringify( d ),
'user_id': user_id,
'user': "${data['username']}"
};
}
}
user_ip_table = $('#user_ip_table').DataTable(user_ip_table_options);
});
$( "#sync-tab-btn" ).one( "click", function() {
// Build user sync table
sync_table_options.ajax = {
"url": "get_sync",
"data": function(d) {
d.user_id = user_id;
d.user = "${data['username']}";
}
}
sync_table = $('#sync_table').DataTable(sync_table_options);
history_table.column(1).visible(false);
$( "#sync-tab-btn" ).one( "click", function() {
// Build user sync table
sync_table_options.ajax = {
"url": "get_sync",
"data": function(d) {
d.user_id = user_id;
d.user = "${data['username']}";
}
}
sync_table = $('#sync_table').DataTable(sync_table_options);
history_table.column(1).visible(false);
var colvis_sync = new $.fn.dataTable.ColVis( sync_table );
$( colvis_sync.button() ).appendTo('#button-bar-sync');
});
var colvis_sync = new $.fn.dataTable.ColVis( sync_table );
$( colvis_sync.button() ).appendTo('#button-bar-sync');
});
// Load edit user modal
$("#toggle-edit-user-modal").click(function() {
$.ajax({
url: 'edit_user_dialog',
data: { user_id: user_id, user: '${data['username']}' },
cache: false,
async: true,
complete: function(xhr, status) {
$("#edit-user-modal").html(xhr.responseText);
}
});
});
// Load edit user modal
$("#toggle-edit-user-modal").click(function() {
$.ajax({
url: 'edit_user_dialog',
data: { user_id: user_id, user: '${data['username']}' },
cache: false,
async: true,
complete: function(xhr, status) {
$("#edit-user-modal").html(xhr.responseText);
}
});
});
});
</script>
</%def>
% else:

View file

@ -19,29 +19,25 @@ DOCUMENTATION :: END
% if data != None:
% for a in data:
<ul>
<ul class="list-unstyled">
<div class="user-platforms-instance">
<li>
<span id="user-platform-image-${a['result_id']}"></span>
<div class="user-platforms-instance-name">
${a['platform_name']}
</div>
<div class="user-platforms-instance-playcount">
<h3>${a['total_plays']}</h3>
<p> plays</p>
</div>
</li>
</div>
</ul>
<script>
$("#user-platform-image-${a['result_id']}").html("<img class='user-platforms-instance-poster' src='" + getPlatformImagePath('${a['platform_type']}') + "'>");
$("#user-platform-image-${a['result_id']}").html("<img class='user-platforms-instance-poster' src='" + getPlatformImagePath('${a['platform_type']}') + "'>");
</script>
% endfor
% else:
<div class="muted">Unable to retrieve data from database. Please check your <a href="settings">settings</a>.
<div class="text-muted">Unable to retrieve data from database. Please check your <a href="settings">settings</a>.
</div><br>
% endif

View file

@ -29,7 +29,7 @@ DOCUMENTATION :: END
% if data != None:
<div class="dashboard-recent-media-row">
<ul class="dashboard-recent-media">
<ul class="dashboard-recent-media list-unstyled">
% for item in data:
<div class="dashboard-recent-media-instance">
<li>
@ -51,13 +51,12 @@ DOCUMENTATION :: END
</li>
</div>
<script>
$('#time-${item['time']}').html('Watched ' + moment(${item['time']}, "X").fromNow())
$('#time-${item['time']}').html('Watched ' + moment(${item['time']}, "X").fromNow())
</script>
% endfor
</ul>
</div>
% else:
<div class="muted">Unable to retrieve data from database. Please check your <a href="settings">settings</a>.
<div class="text-muted">Unable to retrieve data from database. Please check your <a href="settings">settings</a>.
</div><br>
% endif

View file

@ -17,7 +17,7 @@ DOCUMENTATION :: END
</%doc>
% if data != None:
<ul>
<ul class="list-unstyled">
% for a in data:
<div class='user-overview-stats-instance'>
<li>
@ -38,12 +38,10 @@ DOCUMENTATION :: END
</div>
<script>
$('#total-time-${a['query_days']}').html(humanTime(${a['total_time']}));
</script>
% endfor
</ul>
% else:
<div class="muted">Unable to retrieve data from database. Please check your <a href="settings">settings</a>.
<div class="text-muted">Unable to retrieve data from database. Please check your <a href="settings">settings</a>.
</div><br>
% endif

View file

@ -1,75 +1,68 @@
<%inherit file="base.html"/>
<%!
from plexpy import helpers
%>
<%def name="headIncludes()">
<link rel="stylesheet" href="interfaces/default/css/plexwatch-tables.css">
<link rel="stylesheet" href="interfaces/default/css/dataTables.bootstrap.css">
<link rel="stylesheet" href="interfaces/default/css/plexpy-dataTables.css">
</%def>
<%def name="body()">
<div class='container-fluid'>
<div class='row-fluid'>
<div class='span12'>
<div class='table-card-back'>
<div class="header-bar">
<h2><i class="fa fa-group"></i> Active Users</h2>
</div>
<div class="button-bar">
<button class="squared" id="refresh-users-list"><i class="fa fa-refresh"></i> Refresh users</button>
</div>
</div>
<div class='table-card-back'>
<table id="users_list_table" class="display" width="100%">
<thead>
<tr>
<th align="right" id="avatar"></th>
<th align="left" id="friendly_name">User</th>
<th align="left" id="last_seen">Last Seen</th>
<th align="left" id="last_known_ip">Last Known IP</th>
<th align="left" id="total_plays">Total Plays</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
<div class='table-card-back'>
<div class="header-bar">
<span><i class="fa fa-group"></i> Active Users</span>
</div>
<div class="button-bar">
<button class="squared" id="refresh-users-list"><i class="fa fa-refresh"></i> Refresh users</button>
</div>
</div>
<footer></footer>
<div class='table-card-back'>
<table id="users_list_table" class="display" width="100%">
<thead>
<tr>
<th align="right" id="avatar"></th>
<th align="left" id="friendly_name">User</th>
<th align="left" id="last_seen">Last Seen</th>
<th align="left" id="last_known_ip">Last Known IP</th>
<th align="left" id="total_plays">Total Plays</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
</%def>
<%def name="javascriptIncludes()">
<script src="interfaces/default/js/jquery.dataTables.min.js"></script>
<script src="interfaces/default/js/jquery.dataTables.bootstrap.pagination.integration.js"></script>
<script src="interfaces/default/js/dataTables.bootstrap.min.js"></script>
<script src="interfaces/default/js/dataTables.bootstrap.pagination.js"></script>
<script src="interfaces/default/js/moment-with-locale.js"></script>
<script src="interfaces/default/js/tables/users.js"></script>
<script>
users_list_table_options.ajax = {
"url": "get_user_list",
type: "post",
data: function ( d ) {
return { 'json_data': JSON.stringify( d ) };
}
users_list_table_options.ajax = {
"url": "get_user_list",
type: "post",
data: function ( d ) {
return { 'json_data': JSON.stringify( d ) };
}
}
var users_list_table = $('#users_list_table').DataTable(users_list_table_options);
var users_list_table = $('#users_list_table').DataTable(users_list_table_options);
$("#refresh-users-list").click(function() {
$.ajax({
url: 'refresh_users_list',
cache: false,
async: true,
success : function(data) {
showMsg('<i class="fa fa-check"></i>&nbspUser list refresh started...',false,true,2000,false)
},
error: function(jqXHR, textStatus, errorThrown) {
showMsg('<i class="fa fa-exclamation-circle"></i>&nbspUnable to refresh user list.',false,true,2000,true)
},
});
$("#refresh-users-list").click(function() {
$.ajax({
url: 'refresh_users_list',
cache: false,
async: true,
success : function(data) {
showMsg('<i class="fa fa-check"></i>&nbspUser list refresh started...',false,true,2000,false)
},
error: function(jqXHR, textStatus, errorThrown) {
showMsg('<i class="fa fa-exclamation-circle"></i>&nbspUnable to refresh user list.',false,true,2000,true)
},
});
});
</script>
</%def>

View file

@ -14,16 +14,16 @@ from plexpy import version
<meta name="author" content="">
<link href="interfaces/default/css/bootstrap3/bootstrap.css" rel="stylesheet">
<link href="interfaces/default/css/bootstrap-wizard.css" rel="stylesheet">
<link href="interfaces/default/css/plexpy.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Open+Sans" rel="stylesheet" type="text/css">
<link href="interfaces/default/css/font-awesome.css" rel="stylesheet">
<link href="interfaces/default/css/font-awesome.min.css" rel="stylesheet">
<link rel="icon" type="image/x-icon" href="interfaces/default/images/favicon.ico"/>
<link rel="shortcut icon" href="interfaces/default/images/favicon.ico">
</head>
<body>
<div class="container-fluid">
<div class="row-fluid">
<div class="row">
<div class="wizard" id="some-wizard" data-title="PlexPy Setup Wizard">
<div class="wizard-card" data-cardname="card1">
<div style="float: right;">
@ -57,17 +57,25 @@ from plexpy import version
<div class="col-xs-3">
<input type="text" class="form-control pms-settings" name="pms_port" id="pms_port" placeholder="32400" value="${config['pms_port']}" required>
</div>
<div class="col-xs-4" style="padding-top: 8px;">
<input type="checkbox" id="pms_ssl" name="pms_ssl" value="1" ${config['pms_ssl']}> Server uses SSL
<div class="col-xs-4">
<div class="checkbox">
<label>
<input type="checkbox" id="pms_ssl" name="pms_ssl" value="1" ${config['pms_ssl']}> Force SSL
</label>
</div>
</div>
<div class="col-xs-4" style="padding-top: 8px;">
<input type="checkbox" id="pms_is_remote" name="pms_is_remote" value="1" ${config['pms_is_remote']}> Remote Server
<div class="col-xs-4">
<div class="checkbox">
<label>
<input type="checkbox" id="pms_is_remote" name="pms_is_remote" value="1" ${config['pms_is_remote']}> Remote Server
</label>
</div>
</div>
</div>
</div>
<input type="hidden" class="form-control pms-settings" id="pms_valid" data-validate="validatePMSip" value="">
<input type="hidden" class="form-control pms-settings" id="pms_identifier" name="pms_identifier" value="${config['pms_identifier']}">
<a class="btn btn-default btn-sm" id="verify-plex-server" href="#" role="button">Verify</a><span style="margin-left: 10px; display: none;" id="pms-verify-status"></span>
<a class="squared" id="verify-plex-server" href="#" role="button">Verify</a><span style="margin-left: 10px; display: none;" id="pms-verify-status"></span>
</div>
<div class="wizard-card" data-cardname="card3">
@ -90,7 +98,7 @@ from plexpy import version
</div>
</div>
<input type="hidden" class="form-control pms-auth" name="pms_token" id="pms_token" value="${config['pms_token']}" data-validate="validatePMStoken">
<a class="btn btn-default btn-sm" id="pms-authenticate" href="#" role="button">Authenticate</a><span style="margin-left: 10px; display: none;" id="pms-token-status"></span>
<a class="squared" id="pms-authenticate" href="#" role="button">Authenticate</a><span style="margin-left: 10px; display: none;" id="pms-token-status"></span>
</div>
<div class="wizard-card" data-cardname="card4">
<h3>Monitoring</h3>
@ -167,7 +175,7 @@ from plexpy import version
<br/>
<p>Setup is now complete. For more configuration options please visit the Settings menu on the home page.</p>
<br/>
<i class="fa fa-refresh fa-spin"></i> Just configuring a few things, please wait...
<i class="fa fa-refresh fa-spin"></i>&nbspJust configuring a few things, please wait...
</div>
</div>

View file

@ -168,47 +168,40 @@ def build_notify_text(session, state):
logger.error(u"PlexPy Notifier :: Unable to retrieve metadata for rating_key %s" % str(session['rating_key']))
return []
# TODO: There must be a better way to do this. Laziness.
# Check for exclusion tags
if session['media_type'] == 'episode':
on_start_subject = strip_tag(re.sub('<movie>[^>]+.</movie>|<music>[^>]+.</music>', '',
plexpy.CONFIG.NOTIFY_ON_START_SUBJECT_TEXT))
on_start_body = strip_tag(re.sub('<movie>[^>]+.</movie>|<music>[^>]+.</music>', '',
plexpy.CONFIG.NOTIFY_ON_START_BODY_TEXT))
on_stop_subject = strip_tag(re.sub('<movie>[^>]+.</movie>|<music>[^>]+.</music>', '',
plexpy.CONFIG.NOTIFY_ON_STOP_SUBJECT_TEXT))
on_stop_body = strip_tag(re.sub('<movie>[^>]+.</movie>|<music>[^>]+.</music>', '',
plexpy.CONFIG.NOTIFY_ON_STOP_BODY_TEXT))
on_watched_subject = strip_tag(re.sub('<movie>[^>]+.</movie>|<music>[^>]+.</music>', '',
plexpy.CONFIG.NOTIFY_ON_WATCHED_SUBJECT_TEXT))
on_watched_body = strip_tag(re.sub('<movie>[^>]+.</movie>|<music>[^>]+.</music>', '',
plexpy.CONFIG.NOTIFY_ON_WATCHED_BODY_TEXT))
# Regex pattern to remove the text in the tags we don't want
pattern = re.compile('<movie>[^>]+.</movie>|<music>[^>]+.</music>', re.IGNORECASE)
# Remove the unwanted tags and strip any unmatch tags too.
on_start_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_START_SUBJECT_TEXT))
on_start_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_START_BODY_TEXT))
on_stop_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_STOP_SUBJECT_TEXT))
on_stop_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_STOP_BODY_TEXT))
on_watched_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_WATCHED_SUBJECT_TEXT))
on_watched_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_WATCHED_BODY_TEXT))
elif session['media_type'] == 'movie':
on_start_subject = strip_tag(re.sub('<tv>[^>]+.</tv>|<music>[^>]+.</music>', '',
plexpy.CONFIG.NOTIFY_ON_START_SUBJECT_TEXT))
on_start_body = strip_tag(re.sub('<tv>[^>]+.</tv>|<music>[^>]+.</music>', '',
plexpy.CONFIG.NOTIFY_ON_START_BODY_TEXT))
on_stop_subject = strip_tag(re.sub('<tv>[^>]+.</tv>|<music>[^>]+.</music>', '',
plexpy.CONFIG.NOTIFY_ON_STOP_SUBJECT_TEXT))
on_stop_body = strip_tag(re.sub('<tv>[^>]+.</tv>|<music>[^>]+.</music>', '',
plexpy.CONFIG.NOTIFY_ON_STOP_BODY_TEXT))
on_watched_subject = strip_tag(re.sub('<tv>[^>]+.</tv>|<music>[^>]+.</music>', '',
plexpy.CONFIG.NOTIFY_ON_WATCHED_SUBJECT_TEXT))
on_watched_body = strip_tag(re.sub('<tv>[^>]+.</tv>|<music>[^>]+.</music>', '',
plexpy.CONFIG.NOTIFY_ON_WATCHED_BODY_TEXT))
# Regex pattern to remove the text in the tags we don't want
pattern = re.compile('<tv>[^>]+.</tv>|<music>[^>]+.</music>', re.IGNORECASE)
# Remove the unwanted tags and strip any unmatch tags too.
on_start_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_START_SUBJECT_TEXT))
on_start_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_START_BODY_TEXT))
on_stop_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_STOP_SUBJECT_TEXT))
on_stop_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_STOP_BODY_TEXT))
on_watched_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_WATCHED_SUBJECT_TEXT))
on_watched_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_WATCHED_BODY_TEXT))
elif session['media_type'] == 'track':
on_start_subject = strip_tag(re.sub('<tv>[^>]+.</tv>|<movie>[^>]+.</movie>', '',
plexpy.CONFIG.NOTIFY_ON_START_SUBJECT_TEXT))
on_start_body = strip_tag(re.sub('<tv>[^>]+.</tv>|<movie>[^>]+.</movie>', '',
plexpy.CONFIG.NOTIFY_ON_START_BODY_TEXT))
on_stop_subject = strip_tag(re.sub('<tv>[^>]+.</tv>|<movie>[^>]+.</movie>', '',
plexpy.CONFIG.NOTIFY_ON_STOP_SUBJECT_TEXT))
on_stop_body = strip_tag(re.sub('<tv>[^>]+.</tv>|<movie>[^>]+.</movie>', '',
plexpy.CONFIG.NOTIFY_ON_STOP_BODY_TEXT))
on_watched_subject = strip_tag(re.sub('<tv>[^>]+.</tv>|<movie>[^>]+.</movie>', '',
plexpy.CONFIG.NOTIFY_ON_WATCHED_SUBJECT_TEXT))
on_watched_body = strip_tag(re.sub('<tv>[^>]+.</tv>|<movie>[^>]+.</movie>', '',
plexpy.CONFIG.NOTIFY_ON_WATCHED_BODY_TEXT))
# Regex pattern to remove the text in the tags we don't want
pattern = re.compile('<tv>[^>]+.</tv>|<movie>[^>]+.</movie>', re.IGNORECASE)
# Remove the unwanted tags and strip any unmatch tags too.
on_start_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_START_SUBJECT_TEXT))
on_start_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_START_BODY_TEXT))
on_stop_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_STOP_SUBJECT_TEXT))
on_stop_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_STOP_BODY_TEXT))
on_watched_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_WATCHED_SUBJECT_TEXT))
on_watched_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_WATCHED_BODY_TEXT))
else:
on_start_subject = plexpy.CONFIG.NOTIFY_ON_START_SUBJECT_TEXT
on_start_body = plexpy.CONFIG.NOTIFY_ON_START_BODY_TEXT