mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-08-14 02:26:58 -07:00
v1.1.4
This commit is contained in:
commit
6d5e7135ae
21 changed files with 778 additions and 150 deletions
36
CHANGELOG.md
36
CHANGELOG.md
|
@ -1,21 +1,33 @@
|
|||
# Changelog
|
||||
|
||||
## v1.1.4 (2015-08-26)
|
||||
|
||||
* User info is now editable from the users table. Thanks @JonnyWong.
|
||||
* Improved delete mode for history pages - able to multi-select now. Thanks @JonnyWong.
|
||||
* Improved image quality on tooltip images.
|
||||
* More styling improvements and fixes on user and info pages. Thanks @JonnyWong.
|
||||
* Added some user submitted systemd init scripts. Thanks @malle-pietje and @artbird309.
|
||||
* Fixed some background operations when saving settings.
|
||||
* Fix max width restricting home stats to 1600px.
|
||||
* Fix stream duration parameter for notifications when paused counter is null.
|
||||
|
||||
|
||||
## v1.1.3 (2015-08-22)
|
||||
|
||||
* Show human readable version info and this cool changelog in Settings -> General.
|
||||
* Add a "delete" mode to the history tables. Toggle it to show a delete button next to each history item.
|
||||
* Two digit season and episode numbers for custom notification messages. Thanks @JohnnyWong.
|
||||
* New FreeNAS init script. Thanks @JohnnyWong.
|
||||
* Lots of styling improvements! Thanks @JohnnyWong.
|
||||
* Graph page remembers last selected options. Thanks @JohnnyWong.
|
||||
* New Popular movie homepage stats. Thanks @JohnnyWong.
|
||||
* Add option for duration vs play count on home stats. (Settings -> Extra Settings). Thanks @JohnnyWong.
|
||||
* Clean up media info pages. Don't show metadata that is missing. Thanks @JohnnyWong.
|
||||
* Add clear button to search inputs. Thanks @JohnnyWong.
|
||||
* New columns on Users list. Thanks @JohnnyWong.
|
||||
* New stream duration option for custom notification messages. Thanks @JohnnyWong.
|
||||
* Rad new tooltips on the history pages. Thanks @JohnnyWong.
|
||||
* And a lot of small visual changes and fixes. Thanks @JohnnyWong.
|
||||
* Two digit season and episode numbers for custom notification messages. Thanks @JonnyWong.
|
||||
* New FreeNAS init script. Thanks @JonnyWong.
|
||||
* Lots of styling improvements! Thanks @JonnyWong.
|
||||
* Graph page remembers last selected options. Thanks @JonnyWong.
|
||||
* New Popular movie homepage stats. Thanks @JonnyWong.
|
||||
* Add option for duration vs play count on home stats. (Settings -> Extra Settings). Thanks @JonnyWong.
|
||||
* Clean up media info pages. Don't show metadata that is missing. Thanks @JonnyWong.
|
||||
* Add clear button to search inputs. Thanks @JonnyWong.
|
||||
* New columns on Users list. Thanks @JonnyWong.
|
||||
* New stream duration option for custom notification messages. Thanks @JonnyWong.
|
||||
* Rad new tooltips on the history pages. Thanks @JonnyWong.
|
||||
* And a lot of small visual changes and fixes. Thanks @JonnyWong.
|
||||
* Fixed IP address modal on user history page.
|
||||
* Fixed "invalid date" showing on monthly plays graph.
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ select {
|
|||
outline: none;
|
||||
}
|
||||
select.input-sm {
|
||||
margin: 5px 0 5px 0;
|
||||
margin: 5px 0 5px 0;
|
||||
border: 2px solid #444;
|
||||
background: #333;
|
||||
-webkit-border-radius: 2px;
|
||||
|
@ -34,8 +34,8 @@ select.input-sm {
|
|||
}
|
||||
img {
|
||||
-webkit-box-sizing: content-box;
|
||||
-moz-box-sizing: content-box;
|
||||
box-sizing: content-box;
|
||||
-moz-box-sizing: content-box;
|
||||
box-sizing: content-box;
|
||||
}
|
||||
.navbar {
|
||||
background: #000;
|
||||
|
@ -237,6 +237,35 @@ fieldset[disabled] .btn-bright.active {
|
|||
color: #fff;
|
||||
background-color: #eb8600;
|
||||
}
|
||||
.btn-danger.btn-edit {
|
||||
color: #d7d7d7;
|
||||
background-color: #3B3B3B;
|
||||
border-color: transparent;
|
||||
float: right;
|
||||
margin-right: 5px;
|
||||
}
|
||||
.btn-danger.btn-edit:hover {
|
||||
color: #fff;
|
||||
background-color: #c9302c;
|
||||
border-color: #ac2925;
|
||||
}
|
||||
.btn-danger.btn-edit.active {
|
||||
color: #fff;
|
||||
background-color: #c9302c;
|
||||
border-color: #ac2925;
|
||||
}
|
||||
.btn-danger.btn-edit.active:hover {
|
||||
color: #fff;
|
||||
background-color: #ac2925;
|
||||
border-color: #761c19;
|
||||
}
|
||||
.alert-edit {
|
||||
display: none;
|
||||
float: right;
|
||||
margin-bottom: 0;
|
||||
margin-right: 5px;
|
||||
padding: 6px 15px;
|
||||
}
|
||||
.modal-header {
|
||||
padding: 15px 20px;
|
||||
background-color: #323232;
|
||||
|
@ -418,6 +447,12 @@ input[type="color"],
|
|||
webkit-box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1);
|
||||
-moz-box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1);
|
||||
box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1);
|
||||
overflow: hidden;
|
||||
}
|
||||
a .poster-face:hover {
|
||||
webkit-box-shadow: inset 0 0 0 2px #e9a049;
|
||||
-moz-box-shadow: inset 0 0 0 2px #e9a049;
|
||||
box-shadow: inset 0 0 0 2px #e9a049;
|
||||
}
|
||||
.cover-face {
|
||||
background-position: center;
|
||||
|
@ -430,6 +465,29 @@ input[type="color"],
|
|||
-moz-box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1);
|
||||
box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1);
|
||||
}
|
||||
a .cover-face:hover {
|
||||
webkit-box-shadow: inset 0 0 0 2px #e9a049;
|
||||
-moz-box-shadow: inset 0 0 0 2px #e9a049;
|
||||
box-shadow: inset 0 0 0 2px #e9a049;
|
||||
}
|
||||
a .users-poster-face:hover {
|
||||
webkit-box-shadow: inset 0 0 0 2px #e9a049;
|
||||
-moz-box-shadow: inset 0 0 0 2px #e9a049;
|
||||
box-shadow: inset 0 0 0 2px #e9a049;
|
||||
}
|
||||
.users-poster-face {
|
||||
overflow: hidden;
|
||||
float: left;
|
||||
background-size: contain;
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
-webkit-border-radius: 50%;
|
||||
-moz-border-radius: 50%;
|
||||
border-radius: 50%;
|
||||
webkit-box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1);
|
||||
-moz-box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1);
|
||||
box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1);
|
||||
}
|
||||
.users-poster-face img {
|
||||
bottom: 0;
|
||||
overflow: hidden;
|
||||
|
@ -619,11 +677,6 @@ input[type="color"],
|
|||
}
|
||||
.dashboard-recent-media-instance {
|
||||
}
|
||||
.dashboard-recent-media-instance a:hover .poster-face {
|
||||
webkit-box-shadow: inset 0 0 0 2px #e9a049;
|
||||
-moz-box-shadow: inset 0 0 0 2px #e9a049;
|
||||
box-shadow: inset 0 0 0 2px #e9a049;
|
||||
}
|
||||
.dashboard-recent-media li {
|
||||
margin-right: 27px;
|
||||
position: relative;
|
||||
|
@ -788,9 +841,9 @@ input[type="color"],
|
|||
position: relative;
|
||||
top: -10px;
|
||||
float: left;
|
||||
margin-left: 20px;
|
||||
width: 174px;
|
||||
height: 260px;
|
||||
margin-left: 25px;
|
||||
width: 150px;
|
||||
height: 225px;
|
||||
}
|
||||
.summary-content-poster img {
|
||||
bottom: 0;
|
||||
|
@ -821,9 +874,6 @@ input[type="color"],
|
|||
-ms-backface-visibility: hidden;
|
||||
-o-backface-visibility: hidden;
|
||||
backface-visibility: hidden;
|
||||
width: auto;
|
||||
height: 260px;
|
||||
border: 1px solid rgba(128, 128, 128, 0.3);
|
||||
}
|
||||
.summary-content {
|
||||
position: relative;
|
||||
|
@ -843,6 +893,13 @@ input[type="color"],
|
|||
line-height: 32px;
|
||||
float: left;
|
||||
}
|
||||
.summary-content-title h1 a{
|
||||
color: #F9AA03;
|
||||
}
|
||||
.summary-content-title h1 a:hover{
|
||||
color: #F9AA03;
|
||||
text-decoration: underline;
|
||||
}
|
||||
.summary-content-details-wrapper {
|
||||
width: 100%;
|
||||
padding-bottom: 15px;
|
||||
|
@ -909,6 +966,8 @@ input[type="color"],
|
|||
}
|
||||
.summary-content-people-wrapper {
|
||||
margin-top: 25px;
|
||||
margin-right: 25px;
|
||||
float: left;
|
||||
}
|
||||
.summary-content-people-wrapper hidden-phone hidden-tablet {
|
||||
overflow: hidden;
|
||||
|
@ -1011,7 +1070,7 @@ input[type="color"],
|
|||
left: 0px;
|
||||
margin-right: 25px;
|
||||
}
|
||||
.season-episodes-instance a:hover .season-episodes-card-overlay {
|
||||
a .season-episodes-card-overlay:hover {
|
||||
webkit-box-shadow: inset 0 0 0 2px #e9a049;
|
||||
-moz-box-shadow: inset 0 0 0 2px #e9a049;
|
||||
box-shadow: inset 0 0 0 2px #e9a049;
|
||||
|
@ -1034,10 +1093,10 @@ input[type="color"],
|
|||
.season-episodes-poster-face img {
|
||||
bottom: 0;
|
||||
overflow: hidden;
|
||||
width: 205px;
|
||||
height: 115px;
|
||||
width: 250px;
|
||||
height: 140px;
|
||||
}
|
||||
.season-episodes-poster-face img:hover {
|
||||
.season-episodes-poster-face img:hover {
|
||||
webkit-box-shadow: 0 0 0 2px #F9AA03;
|
||||
-moz-box-shadow: 0 0 0 2px #F9AA03;
|
||||
box-shadow: 0 0 0 2px #F9AA03;
|
||||
|
@ -1114,6 +1173,16 @@ input[type="color"],
|
|||
.user-info-poster-face {
|
||||
float: left;
|
||||
margin-top: 15px;
|
||||
margin-right: 15px;
|
||||
background-size: contain;
|
||||
height: 80px;
|
||||
width: 80px;
|
||||
-webkit-border-radius: 50%;
|
||||
-moz-border-radius: 50%;
|
||||
border-radius: 50%;
|
||||
webkit-box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1);
|
||||
-moz-box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1);
|
||||
box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1);
|
||||
}
|
||||
.user-info-poster-face img {
|
||||
bottom: 0;
|
||||
|
@ -1232,13 +1301,13 @@ input[type="color"],
|
|||
}
|
||||
.user-platforms-instance li {
|
||||
}
|
||||
.user-platforms-instance-poster {
|
||||
.user-platforms-instance-box {
|
||||
float: left;
|
||||
width: 75px;
|
||||
border-radius: 3px;
|
||||
-webkit-box-shadow: 0 0 5px rgba(0,0,0,0.5);
|
||||
-moz-box-shadow: 0 0 5px rgba(0,0,0,0.5);
|
||||
box-shadow: 0 0 5px rgba(0,0,0,0.5);
|
||||
webkit-box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1);
|
||||
-moz-box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1);
|
||||
box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1);
|
||||
background-size: contain;
|
||||
position: relative;
|
||||
height: 80px;
|
||||
|
@ -1276,7 +1345,6 @@ input[type="color"],
|
|||
left: 0px;
|
||||
}
|
||||
.home-platforms {
|
||||
max-width: 1600px;
|
||||
}
|
||||
.home-platforms ul {
|
||||
list-style: none;
|
||||
|
@ -1296,7 +1364,12 @@ input[type="color"],
|
|||
bottom: 35px;
|
||||
height: 80px;
|
||||
width: 80px;
|
||||
-webkit-border-radius: 3px;
|
||||
-moz-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
webkit-box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1);
|
||||
-moz-box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1);
|
||||
box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1);
|
||||
}
|
||||
.home-platforms-instance-oval {
|
||||
background-size: contain;
|
||||
|
@ -1308,6 +1381,9 @@ input[type="color"],
|
|||
-webkit-border-radius: 50%;
|
||||
-moz-border-radius: 50%;
|
||||
border-radius: 50%;
|
||||
webkit-box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1);
|
||||
-moz-box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1);
|
||||
box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1);
|
||||
}
|
||||
.home-platforms-instance-name {
|
||||
float: left;
|
||||
|
@ -1368,7 +1444,12 @@ input[type="color"],
|
|||
webkit-box-sizing: content-box;
|
||||
box-sizing: content-box;
|
||||
}
|
||||
.home-platforms-instance a:hover .poster-face {
|
||||
a .home-platforms-instance-oval:hover {
|
||||
webkit-box-shadow: inset 0 0 0 2px #e9a049;
|
||||
-moz-box-shadow: inset 0 0 0 2px #e9a049;
|
||||
box-shadow: inset 0 0 0 2px #e9a049;
|
||||
}
|
||||
a .home-platforms-instance-box:hover {
|
||||
webkit-box-shadow: inset 0 0 0 2px #e9a049;
|
||||
-moz-box-shadow: inset 0 0 0 2px #e9a049;
|
||||
box-shadow: inset 0 0 0 2px #e9a049;
|
||||
|
@ -1670,6 +1751,41 @@ input[type="color"],
|
|||
.history-title .popover.right .popover-content {
|
||||
padding: 5px 8px;
|
||||
}
|
||||
.history-thumbnail {
|
||||
background-position: center;
|
||||
background-size: cover;
|
||||
width: 80px;
|
||||
}
|
||||
.edit-user-toggles {
|
||||
padding-right: 10px;
|
||||
}
|
||||
.edit-user-toggles > input[type='checkbox'] {
|
||||
display: none;
|
||||
}
|
||||
.edit-user-toggles > input[type='checkbox'] + label {
|
||||
color: #444;
|
||||
cursor: pointer;
|
||||
}
|
||||
.edit-user-toggles > input[type='checkbox']:checked + label {
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
}
|
||||
.popover {
|
||||
z-index: 2;
|
||||
}
|
||||
.popover .popover-content {
|
||||
color: #000;
|
||||
}
|
||||
.noTransition
|
||||
{
|
||||
-moz-transition: none !important;
|
||||
-webkit-transition: none !important;
|
||||
-o-transition: none !important;
|
||||
transition: none !important;
|
||||
}
|
||||
#users-to-delete > li {
|
||||
color: #e9a049;
|
||||
}
|
||||
#updatebar {
|
||||
background-color: #444;
|
||||
color: #999999;
|
||||
|
|
|
@ -74,6 +74,24 @@ DOCUMENTATION :: END
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="confirm-modal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="confirm-modal">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true"><i class="fa fa-remove"></i></button>
|
||||
<h4 class="modal-title" id="myModalLabel">Confirm Purge</h4>
|
||||
</div>
|
||||
<div class="modal-body" style="text-align: center;">
|
||||
<p>Are you REALLY sure you want to purge all history for this user?</p>
|
||||
<p>This is permanent and cannot be undone!</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-dark" data-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-danger btn-ok" data-dismiss="modal" id="confirm-purge">Purge</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
// Set new friendly name
|
||||
$("#save_user_name").click(function() {
|
||||
|
@ -119,9 +137,9 @@ DOCUMENTATION :: END
|
|||
% endif
|
||||
});
|
||||
|
||||
$("#delete-all-history").click(function() {
|
||||
var r = confirm("Are you REALLY REALLY REALLY sure you want to delete all history for this user?");
|
||||
if (r == true) {
|
||||
$("#delete-all-history").on('click', function() {
|
||||
$('#confirm-modal').modal();
|
||||
$('#confirm-modal').one('click', '#confirm-purge', function () {
|
||||
$.ajax({
|
||||
url: 'delete_all_user_history',
|
||||
data: {user_id: '${data['user_id']}'},
|
||||
|
@ -131,7 +149,34 @@ DOCUMENTATION :: END
|
|||
location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$(document).ready(function() {
|
||||
// Move #confirm-modal to parent container
|
||||
if(!($('#edit-user-modal').next().is('#confirm-modal'))) {
|
||||
$('#confirm-modal').appendTo($('#edit-user-modal').parent()); }
|
||||
$('#edit-user-modal > #confirm-modal').remove();
|
||||
|
||||
$('#edit-user-modal').css('z-index', '1050');
|
||||
$('.modal-backdrop').not('.modal-backdrop-stack').css('z-index', '1049');
|
||||
$('.modal-backdrop').not('.modal-backdrop-stack').addClass('modal-backdrop-stack');
|
||||
|
||||
$('#confirm-modal').on('show.bs.modal', function () {
|
||||
// Fix position to match parent modal
|
||||
var currentPadding = parseInt($('body').css('padding-right'));
|
||||
$(this).children('.modal-dialog').css('left', -currentPadding/2);
|
||||
$('#edit-user-modal').css('overflow-y', 'hidden');
|
||||
});
|
||||
$('#confirm-modal').on('shown.bs.modal', function () {
|
||||
$(this).css('z-index', '1060');
|
||||
$('.modal-backdrop').not('.modal-backdrop-stack').css('z-index', '1059');
|
||||
$('.modal-backdrop').not('.modal-backdrop-stack').addClass('modal-backdrop-stack');
|
||||
});
|
||||
$('#confirm-modal').on('hidden.bs.modal', function() {
|
||||
$('body').addClass('modal-open');
|
||||
$('#edit-user-modal').css('overflow-y', 'auto');
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
|
|
|
@ -14,8 +14,11 @@
|
|||
<span><i class="fa fa-history"></i> History</span>
|
||||
</div>
|
||||
<div class="button-bar">
|
||||
<button class="btn btn-danger" data-toggle="button" aria-pressed="false" autocomplete="off" id="row-edit-mode"><i class="fa fa-trash-o"></i> Delete mode</button> 
|
||||
<div class="colvis-button-bar hidden-xs"></div>
|
||||
<button class="btn btn-danger btn-edit" data-toggle="button" aria-pressed="false" autocomplete="off" id="row-edit-mode">
|
||||
<i class="fa fa-trash-o"></i> Delete mode
|
||||
</button>
|
||||
<div class="alert alert-danger alert-edit" role="alert" id="row-edit-mode-alert"><i class="fa fa-exclamation-triangle"></i> Select rows to delete. Data is deleted upon exiting delete mode.</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class='table-card-back'>
|
||||
|
@ -42,6 +45,24 @@
|
|||
</div>
|
||||
<div class="modal fade" id="ip-info-modal" tabindex="-1" role="dialog" aria-labelledby="ip-info-modal">
|
||||
</div>
|
||||
<div class="modal fade" id="confirm-modal" tabindex="-1" role="dialog" aria-labelledby="confirm-modal">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true"><i class="fa fa-remove"></i></button>
|
||||
<h4 class="modal-title" id="myModalLabel">Confirm Delete</h4>
|
||||
</div>
|
||||
<div class="modal-body" style="text-align: center;">
|
||||
<p>Are you REALLY sure you want to delete <strong><span id="deleteCount"></span></strong> history item(s)?</p>
|
||||
<p>This is permanent and cannot be undone!</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-dark" data-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-danger btn-ok" data-dismiss="modal" id="confirm-delete">Delete</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</%def>
|
||||
|
@ -68,18 +89,42 @@
|
|||
|
||||
clearSearchButton('history_table', history_table);
|
||||
|
||||
$('#row-edit-mode').click(function() {
|
||||
$('#row-edit-mode').on('click', function() {
|
||||
$('#row-edit-mode-alert').fadeIn(200);
|
||||
|
||||
if ($(this).hasClass('active')) {
|
||||
$('.delete-control').each(function() {
|
||||
if (history_to_delete.length > 0) {
|
||||
$('#deleteCount').text(history_to_delete.length);
|
||||
$('#confirm-modal').modal();
|
||||
$('#confirm-modal').one('click', '#confirm-delete', function () {
|
||||
for (var i = 0; i < history_to_delete.length; i++) {
|
||||
$.ajax({
|
||||
url: 'delete_history_rows',
|
||||
data: { row_id: history_to_delete[i] },
|
||||
async: true,
|
||||
success: function (data) {
|
||||
var msg = "User history purged";
|
||||
showMsg(msg, false, true, 2000);
|
||||
}
|
||||
});
|
||||
}
|
||||
history_table.draw();
|
||||
});
|
||||
}
|
||||
|
||||
$('.delete-control').each(function () {
|
||||
$(this).find('button.btn-danger').toggleClass('btn-warning').toggleClass('btn-danger');
|
||||
$(this).addClass('hidden');
|
||||
$('#row-edit-mode-alert').fadeOut(200);
|
||||
});
|
||||
|
||||
} else {
|
||||
history_to_delete = [];
|
||||
$('.delete-control').each(function() {
|
||||
$(this).removeClass('hidden');
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
</%def>
|
||||
|
|
|
@ -175,7 +175,11 @@ DOCUMENTATION :: END
|
|||
<span>Watch History for <strong>${data['title']}</strong></span>
|
||||
</div>
|
||||
<div class="button-bar">
|
||||
<button class="btn btn-danger" data-toggle="button" aria-pressed="false" autocomplete="off" id="row-edit-mode"><i class="fa fa-trash-o"></i> Delete mode</button> 
|
||||
<span data-toggle="popover" data-placement="left" data-content="Select rows to delete. Data is deleted upon exiting delete mode." id="delete-message">
|
||||
<button class="btn btn-danger" data-toggle="button" aria-pressed="false" autocomplete="off" id="row-edit-mode">
|
||||
<i class="fa fa-trash-o"></i> Delete mode
|
||||
</button> 
|
||||
</span>
|
||||
<div class="colvis-button-bar hidden-xs"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -204,6 +208,24 @@ DOCUMENTATION :: END
|
|||
</div>
|
||||
<div class="modal fade" id="ip-info-modal" tabindex="-1" role="dialog" aria-labelledby="ip-info-modal">
|
||||
</div>
|
||||
<div class="modal fade" id="confirm-modal" tabindex="-1" role="dialog" aria-labelledby="confirm-modal">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true"><i class="fa fa-remove"></i></button>
|
||||
<h4 class="modal-title" id="myModalLabel">Confirm Delete</h4>
|
||||
</div>
|
||||
<div class="modal-body" style="text-align: center;">
|
||||
<p>Are you REALLY sure you want to delete <strong><span id="deleteCount"></span></strong> history item(s)?</p>
|
||||
<p>This is permanent and cannot be undone!</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-dark" data-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-danger btn-ok" data-dismiss="modal" id="confirm-delete">Delete</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -271,12 +293,36 @@ DOCUMENTATION :: END
|
|||
|
||||
clearSearchButton('history_table', history_table);
|
||||
|
||||
$('#row-edit-mode').click(function() {
|
||||
$('#row-edit-mode').on('click', function() {
|
||||
$('#delete-message').popover();
|
||||
|
||||
if ($(this).hasClass('active')) {
|
||||
$('.delete-control').each(function() {
|
||||
if (history_to_delete.length > 0) {
|
||||
$('#deleteCount').text(history_to_delete.length);
|
||||
$('#confirm-modal').modal();
|
||||
$('#confirm-modal').one('click', '#confirm-delete', function () {
|
||||
for (var i = 0; i < history_to_delete.length; i++) {
|
||||
$.ajax({
|
||||
url: 'delete_history_rows',
|
||||
data: { row_id: history_to_delete[i] },
|
||||
async: true,
|
||||
success: function (data) {
|
||||
var msg = "User history purged";
|
||||
showMsg(msg, false, true, 2000);
|
||||
}
|
||||
});
|
||||
}
|
||||
history_table.draw();
|
||||
});
|
||||
}
|
||||
|
||||
$('.delete-control').each(function () {
|
||||
$(this).find('button.btn-danger').toggleClass('btn-warning').toggleClass('btn-danger');
|
||||
$(this).addClass('hidden');
|
||||
});
|
||||
|
||||
} else {
|
||||
history_to_delete = [];
|
||||
$('.delete-control').each(function() {
|
||||
$(this).removeClass('hidden');
|
||||
});
|
||||
|
|
|
@ -32,7 +32,7 @@ DOCUMENTATION :: END
|
|||
<li>
|
||||
<a href="info?item_id=${a['rating_key']}">
|
||||
<div class="season-episodes-poster">
|
||||
<div class="season-episodes-poster-face" style="background-image: url(pms_image_proxy?img=${a['thumb']}&width=410&height=230);">
|
||||
<div class="season-episodes-poster-face" style="background-image: url(pms_image_proxy?img=${a['thumb']}&width=500&height=280);">
|
||||
<div class="season-episodes-card-overlay">
|
||||
<div class="season-episodes-season">
|
||||
Episode ${a['index']}
|
||||
|
|
|
@ -25,11 +25,7 @@ var hc_plays_by_month_options = {
|
|||
},
|
||||
colors: ['#F9AA03', '#FFFFFF'],
|
||||
xAxis: {
|
||||
type: 'datetime',
|
||||
labels: {
|
||||
formatter: function() {
|
||||
return moment(this.value).format("MMM YYYY");
|
||||
},
|
||||
style: {
|
||||
color: '#aaa'
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
var date_format = 'YYYY-MM-DD';
|
||||
var time_format = 'hh:mm a';
|
||||
var history_to_delete = [];
|
||||
|
||||
$.ajax({
|
||||
url: 'get_date_formats',
|
||||
|
@ -18,7 +19,7 @@ history_table_options = {
|
|||
"info":"Showing _START_ to _END_ of _TOTAL_ history items",
|
||||
"infoEmpty":"Showing 0 to 0 of 0 entries",
|
||||
"infoFiltered":"(filtered from _MAX_ total entries)",
|
||||
"emptyTable": "No data in table",
|
||||
"emptyTable": "No data in table"
|
||||
},
|
||||
"pagingType": "bootstrap",
|
||||
"stateSave": true,
|
||||
|
@ -32,7 +33,7 @@ history_table_options = {
|
|||
"targets": [0],
|
||||
"data": null,
|
||||
"createdCell": function (td, cellData, rowData, row, col) {
|
||||
$(td).html('<button class="btn btn-xs btn-danger" data-id="' + rowData['id'] + '"><i class="fa fa-trash-o"></i> Delete</button>');
|
||||
$(td).html('<button class="btn btn-xs btn-warning" data-id="' + rowData['id'] + '"><i class="fa fa-trash-o fa-fw"></i> Delete</button>');
|
||||
},
|
||||
"width": "5%",
|
||||
"className": "delete-control no-wrap hidden",
|
||||
|
@ -98,11 +99,11 @@ history_table_options = {
|
|||
if (cellData !== '') {
|
||||
var transcode_dec = '';
|
||||
if (rowData['video_decision'] === 'transcode') {
|
||||
transcode_dec = '<span class="transcode-tooltip" data-toggle="tooltip" title="Transcode"><i class="fa fa-server fa-fw"></i></span> ';
|
||||
transcode_dec = '<span class="transcode-tooltip" data-toggle="tooltip" title="Transcode"><i class="fa fa-server fa-fw"></i></span>';
|
||||
} else if (rowData['video_decision'] === 'copy') {
|
||||
transcode_dec = '<span class="transcode-tooltip" data-toggle="tooltip" title="Direct Stream"><i class="fa fa-video-camera fa-fw"></i></span> ';
|
||||
transcode_dec = '<span class="transcode-tooltip" data-toggle="tooltip" title="Direct Stream"><i class="fa fa-video-camera fa-fw"></i></span>';
|
||||
} else if (rowData['video_decision'] === 'direct play' || rowData['video_decision'] === '') {
|
||||
transcode_dec = '<span class="transcode-tooltip" data-toggle="tooltip" title="Direct Play"><i class="fa fa-play-circle fa-fw"></i></span> ';
|
||||
transcode_dec = '<span class="transcode-tooltip" data-toggle="tooltip" title="Direct Play"><i class="fa fa-play-circle fa-fw"></i></span>';
|
||||
}
|
||||
$(td).html('<div><a href="#" data-target="#info-modal" data-toggle="modal"><div style="float: left;">' + transcode_dec + ' ' + cellData + '</div></a></div>');
|
||||
}
|
||||
|
@ -119,16 +120,16 @@ history_table_options = {
|
|||
var thumb_popover = '';
|
||||
if (rowData['media_type'] === 'movie') {
|
||||
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Movie"><i class="fa fa-film fa-fw"></i></span>';
|
||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=80&height=120&fallback=poster" data-height="120">' + cellData + ' (' + rowData['year'] + ')</span>'
|
||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=450&fallback=poster" data-height="120">' + cellData + ' (' + rowData['year'] + ')</span>'
|
||||
$(td).html('<div class="history-title"><a href="info?source=history&item_id=' + rowData['id'] + '"><div style="float: left;">' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||
} else if (rowData['media_type'] === 'episode') {
|
||||
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Episode"><i class="fa fa-television fa-fw"></i></span>';
|
||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=80&height=120&fallback=poster" data-height="120">' + cellData + ' \
|
||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=450&fallback=poster" data-height="120">' + cellData + ' \
|
||||
(S' + ('00' + rowData['parent_media_index']).slice(-2) + 'E' + ('00' + rowData['media_index']).slice(-2) + ')</span>'
|
||||
$(td).html('<div class="history-title"><a href="info?source=history&item_id=' + rowData['id'] + '"><div style="float: left;" >' + media_type + ' ' + thumb_popover + '</div></a></div>');
|
||||
} else if (rowData['media_type'] === 'track') {
|
||||
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Track"><i class="fa fa-music fa-fw"></i></span>';
|
||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=80&height=80&fallback=poster" data-height="80">' + cellData + ' (' + rowData['parent_title'] + ')</span>'
|
||||
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=300&fallback=poster" data-height="80">' + cellData + ' (' + rowData['parent_title'] + ')</span>'
|
||||
$(td).html('<div class="history-title"><div style="float: left;">' + media_type + ' ' + thumb_popover + '</div></div>');
|
||||
} else {
|
||||
$(td).html('<a href="info?item_id=' + rowData['id'] + '">' + cellData + '</a>');
|
||||
|
@ -225,7 +226,7 @@ history_table_options = {
|
|||
trigger: 'hover',
|
||||
placement: 'right',
|
||||
content: function () {
|
||||
return '<div style="background-image: url(' + $(this).data('img') + '); width: 80px; height: ' + $(this).data('height') + 'px;" />';
|
||||
return '<div class="history-thumbnail" style="background-image: url(' + $(this).data('img') + '); height: ' + $(this).data('height') + 'px;" />';
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -238,6 +239,11 @@ history_table_options = {
|
|||
"preDrawCallback": function(settings) {
|
||||
var msg = "<div class='msg'><i class='fa fa-refresh fa-spin'></i> Fetching rows...</div>";
|
||||
showMsg(msg, false, false, 0)
|
||||
},
|
||||
"rowCallback": function (row, rowData) {
|
||||
if ($.inArray(rowData['id'], history_to_delete) !== -1) {
|
||||
$(row).find('button[data-id="' + rowData['id'] + '"]').toggleClass('btn-warning').toggleClass('btn-danger');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -287,16 +293,11 @@ $('#history_table').on('click', 'td.delete-control > button', function () {
|
|||
var row = history_table.row( tr );
|
||||
var rowData = row.data();
|
||||
|
||||
$(this).prop('disabled', true);
|
||||
$(this).html('<i class="fa fa-spin fa-refresh"></i> Delete');
|
||||
|
||||
$.ajax({
|
||||
url: 'delete_history_rows',
|
||||
data: {row_id: rowData['id']},
|
||||
async: true,
|
||||
success: function(data) {
|
||||
history_table.ajax.reload(null, false);
|
||||
}
|
||||
});
|
||||
|
||||
var index = $.inArray(rowData['id'], history_to_delete);
|
||||
if (index === -1) {
|
||||
history_to_delete.push(rowData['id']);
|
||||
} else {
|
||||
history_to_delete.splice(index, 1);
|
||||
}
|
||||
$(this).toggleClass('btn-warning').toggleClass('btn-danger');
|
||||
});
|
|
@ -11,44 +11,62 @@ users_list_table_options = {
|
|||
"processing": false,
|
||||
"serverSide": true,
|
||||
"pageLength": 10,
|
||||
"order": [ 1, 'asc'],
|
||||
"order": [ 2, 'asc'],
|
||||
"autoWidth": true,
|
||||
"stateSave": true,
|
||||
"pagingType": "bootstrap",
|
||||
"columnDefs": [
|
||||
{
|
||||
"targets": [0],
|
||||
"data": null,
|
||||
"createdCell": function (td, cellData, rowData, row, col) {
|
||||
$(td).html('<div class="edit-user-toggles"><button class="btn btn-xs btn-warning" data-id="' + rowData['user_id'] + '" data-toggle="button"><i class="fa fa-eraser fa-fw"></i> Purge</button>   ' +
|
||||
'<input type="checkbox" id="do_notify-' + rowData['user_id'] + '" name="do_notify" value="1" ' + rowData['do_notify'] + '><label class="edit-tooltip" for="do_notify-' + rowData['user_id'] + '" data-toggle="tooltip" title="Toggle Notifications"><i class="fa fa-bell fa-lg fa-fw"></i></label> ' +
|
||||
'<input type="checkbox" id="keep_history-' + rowData['user_id'] + '" name="keep_history" value="1" ' + rowData['keep_history'] + '><label class="edit-tooltip" for="keep_history-' + rowData['user_id'] + '" data-toggle="tooltip" title="Toggle History"><i class="fa fa-history fa-lg fa-fw"></i></label> ');
|
||||
// Show/hide user currently doesn't work
|
||||
//'<input type="checkbox" id="show_hide-' + rowData['user_id'] + '" name="show_hide" value="1" checked><label class="edit-tooltip" for="show_hide-' + rowData['user_id'] + '" data-toggle="tooltip" title="Show/Hide User"><i class="fa fa-eye fa-lg fa-fw"></i></label>');
|
||||
},
|
||||
"width": "7%",
|
||||
"className": "edit-control no-wrap hidden",
|
||||
"searchable": false,
|
||||
"orderable": false
|
||||
},
|
||||
{
|
||||
"targets": [1],
|
||||
"data": "user_thumb",
|
||||
"createdCell": function (td, cellData, rowData, row, col) {
|
||||
if (cellData === '') {
|
||||
$(td).html('<img src="interfaces/default/images/gravatar-default-80x80.png" alt="User Logo"/>');
|
||||
$(td).html('<a href="user?user_id=' + rowData['user_id'] + '"><div class="users-poster-face" style="background-image: url(interfaces/default/images/gravatar-default-80x80.png);"></div></a>');
|
||||
} else {
|
||||
$(td).html('<img src="' + cellData + '" alt="User Logo"/>');
|
||||
$(td).html('<a href="user?user_id=' + rowData['user_id'] + '"><div class="users-poster-face" style="background-image: url(' + cellData + ');"></div></a>');
|
||||
}
|
||||
},
|
||||
"orderable": false,
|
||||
"searchable": false,
|
||||
"width": "5%",
|
||||
"className": "users-poster-face"
|
||||
"className": "users-thumbs"
|
||||
},
|
||||
{
|
||||
"targets": [1],
|
||||
"targets": [2],
|
||||
"data": "friendly_name",
|
||||
"createdCell": function (td, cellData, rowData, row, col) {
|
||||
if (cellData !== '') {
|
||||
if (rowData['user_id'] > 0) {
|
||||
$(td).html('<a href="user?user_id=' + rowData['user_id'] + '">' + cellData + '</a>');
|
||||
$(td).html('<div class="edit-user-name" data-id="' + rowData['user_id'] + '"><a href="user?user_id=' + rowData['user_id'] + '">' + cellData + '</a>' +
|
||||
'<input type="text" class="hidden" value="' + cellData + '"></div>');
|
||||
} else {
|
||||
$(td).html('<a href="user?user=' + rowData['user'] + '">' + cellData + '</a>');
|
||||
$(td).html('<div class="edit-user-name" data-id="' + rowData['user_id'] + '"><a href="user?user=' + rowData['user'] + '">' + cellData + '</a>' +
|
||||
'<input type="text" class="hidden" value="' + cellData + '"></div>');
|
||||
}
|
||||
} else {
|
||||
$(td).html(cellData);
|
||||
}
|
||||
},
|
||||
"width": "15%"
|
||||
"width": "12%",
|
||||
"className": "edit-user-control no-wrap"
|
||||
},
|
||||
{
|
||||
"targets": [2],
|
||||
"targets": [3],
|
||||
"data": "last_seen",
|
||||
"render": function ( data, type, full ) {
|
||||
if (data) {
|
||||
|
@ -58,11 +76,11 @@ users_list_table_options = {
|
|||
}
|
||||
},
|
||||
"searchable": false,
|
||||
"width": "15%",
|
||||
"width": "12%",
|
||||
"className": "no-wrap hidden-xs"
|
||||
},
|
||||
{
|
||||
"targets": [3],
|
||||
"targets": [4],
|
||||
"data": "ip_address",
|
||||
"createdCell": function (td, cellData, rowData, row, col) {
|
||||
if (cellData) {
|
||||
|
@ -79,32 +97,32 @@ users_list_table_options = {
|
|||
$(td).html('n/a');
|
||||
}
|
||||
},
|
||||
"width": "15%",
|
||||
"width": "12%",
|
||||
"className": "no-wrap hidden-md hidden-sm hidden-xs modal-control-ip"
|
||||
},
|
||||
{
|
||||
"targets": [4],
|
||||
"targets": [5],
|
||||
"data":"platform",
|
||||
"createdCell": function (td, cellData, rowData, row, col) {
|
||||
if (cellData) {
|
||||
var transcode_dec = '';
|
||||
if (rowData['video_decision'] === 'transcode') {
|
||||
transcode_dec = '<span class="transcode-tooltip" data-toggle="tooltip" title="Transcode"><i class="fa fa-server fa-fw"></i></span> ';
|
||||
transcode_dec = '<span class="transcode-tooltip" data-toggle="tooltip" title="Transcode"><i class="fa fa-server fa-fw"></i></span>';
|
||||
} else if (rowData['video_decision'] === 'copy') {
|
||||
transcode_dec = '<span class="transcode-tooltip" data-toggle="tooltip" title="Direct Stream"><i class="fa fa-video-camera fa-fw"></i></span> ';
|
||||
transcode_dec = '<span class="transcode-tooltip" data-toggle="tooltip" title="Direct Stream"><i class="fa fa-video-camera fa-fw"></i></span>';
|
||||
} else if (rowData['video_decision'] === 'direct play' || rowData['video_decision'] === '') {
|
||||
transcode_dec = '<span class="transcode-tooltip" data-toggle="tooltip" title="Direct Play"><i class="fa fa-play-circle fa-fw"></i></span> ';
|
||||
transcode_dec = '<span class="transcode-tooltip" data-toggle="tooltip" title="Direct Play"><i class="fa fa-play-circle fa-fw"></i></span>';
|
||||
}
|
||||
$(td).html('<div><a href="#" data-target="#info-modal" data-toggle="modal"><div style="float: left;">' + transcode_dec + ' ' + cellData + '</div></a></div>');
|
||||
} else {
|
||||
$(td).html('n/a');
|
||||
}
|
||||
},
|
||||
"width": "15%",
|
||||
"width": "12%",
|
||||
"className": "no-wrap hidden-md hidden-sm hidden-xs modal-control"
|
||||
},
|
||||
{
|
||||
"targets": [5],
|
||||
"targets": [6],
|
||||
"data":"last_watched",
|
||||
"createdCell": function (td, cellData, rowData, row, col) {
|
||||
if (cellData !== '') {
|
||||
|
@ -129,14 +147,15 @@ users_list_table_options = {
|
|||
}
|
||||
}
|
||||
},
|
||||
"width": "30%",
|
||||
"className": "hidden-sm hidden-xs"
|
||||
},
|
||||
{
|
||||
"targets": [6],
|
||||
"targets": [7],
|
||||
"data": "plays",
|
||||
"searchable": false,
|
||||
"width": "10%"
|
||||
}
|
||||
}
|
||||
|
||||
],
|
||||
"drawCallback": function (settings) {
|
||||
|
@ -145,6 +164,8 @@ users_list_table_options = {
|
|||
$('#ajaxMsg').fadeOut();
|
||||
|
||||
// Create the tooltips.
|
||||
$('.purge-tooltip').tooltip();
|
||||
$('.edit-tooltip').tooltip();
|
||||
$('.transcode-tooltip').tooltip();
|
||||
$('.media-type-tooltip').tooltip();
|
||||
$('.watched-tooltip').tooltip();
|
||||
|
@ -157,6 +178,11 @@ users_list_table_options = {
|
|||
}
|
||||
});
|
||||
|
||||
if ($('#row-edit-mode').hasClass('active')) {
|
||||
$('.edit-control').each(function () {
|
||||
$(this).removeClass('hidden');
|
||||
});
|
||||
}
|
||||
},
|
||||
"preDrawCallback": function(settings) {
|
||||
var msg = "<div class='msg'><i class='fa fa-refresh fa-spin'></i> Fetching rows...</div>";
|
||||
|
@ -204,4 +230,50 @@ $('#users_list_table').on('click', 'td.modal-control-ip', function () {
|
|||
}
|
||||
|
||||
getUserLocation(rowData['ip_address']);
|
||||
});
|
||||
|
||||
$('#users_list_table').on('change', 'td.edit-control > .edit-user-toggles > input, td.edit-user-control > .edit-user-name > input', function () {
|
||||
var tr = $(this).parents('tr');
|
||||
var row = users_list_table.row(tr);
|
||||
var rowData = row.data();
|
||||
|
||||
var do_notify = 0;
|
||||
var keep_history = 0;
|
||||
if ($('#do_notify-' + rowData['user_id']).is(':checked')) {
|
||||
do_notify = 1;
|
||||
}
|
||||
if ($('#keep_history-' + rowData['user_id']).is(':checked')) {
|
||||
keep_history = 1;
|
||||
}
|
||||
|
||||
friendly_name = tr.find('td.edit-user-control > .edit-user-name > input').val();
|
||||
|
||||
$.ajax({
|
||||
url: 'edit_user',
|
||||
data: {
|
||||
user_id: rowData['user_id'],
|
||||
friendly_name: friendly_name,
|
||||
do_notify: do_notify,
|
||||
keep_history: keep_history,
|
||||
thumb: rowData['user_thumb']
|
||||
},
|
||||
cache: false,
|
||||
async: true,
|
||||
success: function (data) {
|
||||
var msg = "User updated";
|
||||
showMsg(msg, false, true, 2000);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$('#users_list_table').on('click', 'td.edit-control > .edit-user-toggles > button', function () {
|
||||
var tr = $(this).parents('tr');
|
||||
var row = users_list_table.row(tr);
|
||||
var rowData = row.data();
|
||||
|
||||
if ($(this).hasClass('active')) {
|
||||
$(this).toggleClass('btn-warning').toggleClass('btn-danger');
|
||||
} else {
|
||||
$(this).toggleClass('btn-danger').toggleClass('btn-warning');
|
||||
}
|
||||
});
|
|
@ -83,6 +83,25 @@ available_notification_agents = notifiers.available_notification_agents()
|
|||
</div>
|
||||
<p class="help-block">Set your preferred time format. <a href="javascript:void(0)" data-target="#dateTimeOptionsModal" data-toggle="modal">Click here</a> to see the parameter list.</p>
|
||||
</div>
|
||||
<div class="padded-header">
|
||||
<h3>Homepage Statistics</h3>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="home_stats_length">Time Frame</label>
|
||||
<div class="row">
|
||||
<div class="col-md-2">
|
||||
<input type="text" class="form-control" data-parsley-type="integer" id="home_stats_length" name="home_stats_length" value="${config['home_stats_length']}" size="3" data-parsley-min="0" data-parsley-trigger="change" required>
|
||||
</div>
|
||||
</div>
|
||||
<p class="help-block">Specify the number of days for the statistics on the home page. Default is 30 days.</p>
|
||||
</div>
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" id="home_stats_type" name="home_stats_type" value="1" ${config['home_stats_type']}> Use play duration
|
||||
</label>
|
||||
<p class="help-block">Use play duration instead of play count to generate statistics.</p>
|
||||
</div>
|
||||
<p><input type="button" class="btn btn-bright save-button" value="Save" data-success="Changes saved successfully"></p>
|
||||
</div>
|
||||
<div role="tabpanel" class="tab-pane" id="tabs-2">
|
||||
|
@ -221,9 +240,24 @@ available_notification_agents = notifiers.available_notification_agents()
|
|||
</label>
|
||||
<p class="help-block">Force PlexPy to connect to your Plex Server via SSL. Your server needs to have remote access enabled.</p>
|
||||
</div>
|
||||
<div class="padded-header">
|
||||
<h3>Plex Logs</h3>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="pms_logs_folder">Logs Folder</label>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<input type="text" class="form-control" id="pms_logs_folder" name="pms_logs_folder" value="${config['pms_logs_folder']}" size="30" data-parsley-trigger="change">
|
||||
</div>
|
||||
</div>
|
||||
<p class="help-block">Set the folder where your Plex Server logs are. This is required if you enable IP logging.<br /><a href="https://support.plex.tv/hc/en-us/articles/200250417-Plex-Media-Server-Log-Files" target="_blank">Click here</a> for help.</p>
|
||||
</div>
|
||||
|
||||
<input type="hidden" id="pms_identifier" name="pms_identifier" value="${config['pms_identifier']}">
|
||||
|
||||
<input type="button" class="btn btn-bright save-button" value="Save" data-success="Changes saved successfully">
|
||||
|
||||
</div>
|
||||
<div role="tabpanel" class="tab-pane" id="tabs-5">
|
||||
|
||||
|
@ -278,41 +312,6 @@ available_notification_agents = notifiers.available_notification_agents()
|
|||
<p class="help-block">If you have media indexing enabled on your server, use these on the activity pane.</p>
|
||||
</div>
|
||||
|
||||
<div class="padded-header">
|
||||
<h3>Homepage Statistics</h3>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="home_stats_length">Time Frame</label>
|
||||
<div class="row">
|
||||
<div class="col-md-2">
|
||||
<input type="text" class="form-control" data-parsley-type="integer" id="home_stats_length" name="home_stats_length" value="${config['home_stats_length']}" size="3" data-parsley-min="0" data-parsley-trigger="change" required>
|
||||
</div>
|
||||
</div>
|
||||
<p class="help-block">Specify the number of days for the statistics on the home page. Default is 30 days.</p>
|
||||
</div>
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" id="home_stats_type" name="home_stats_type" value="1" ${config['home_stats_type']}> Use play duration
|
||||
</label>
|
||||
<p class="help-block">Use play duration instead of play count to generate statistics.</p>
|
||||
</div>
|
||||
|
||||
<div class="padded-header">
|
||||
<h3>Plex Logs</h3>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="pms_logs_folder">Logs Folder</label>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<input type="text" class="form-control" id="pms_logs_folder" name="pms_logs_folder" value="${config['pms_logs_folder']}" size="30" data-parsley-trigger="change">
|
||||
</div>
|
||||
</div>
|
||||
<p class="help-block">Set the folder where your Plex Server logs are. This is required if you enable IP logging.<br/><a href="https://support.plex.tv/hc/en-us/articles/200250417-Plex-Media-Server-Log-Files" target="_blank">Click here</a> for help.</p>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="padded-header">
|
||||
<h3>PlexWatch Import Tool</h3>
|
||||
</div>
|
||||
|
|
|
@ -40,8 +40,7 @@ from plexpy import helpers
|
|||
<div class="col-md-12">
|
||||
<div class="table-card-back">
|
||||
<div class="user-info-wrapper">
|
||||
<div class="user-info-poster-face" id="user-gravatar">
|
||||
<img id="user-profile-thumb" src="${data['thumb']}" height="80px" width="80px">
|
||||
<div class="user-info-poster-face" id="user-gravatar" style="background-image: url(${data['thumb']});">
|
||||
</div>
|
||||
<div class="user-info-username">
|
||||
<span class="set-username">${data['friendly_name']}</span> <span id="edit-user-tooltip" data-target="tooltip" title="Edit user details"><a href="#" data-toggle="modal" data-target="#edit-user-modal" id="toggle-edit-user-modal"><i class="fa fa-pencil"></i></a></span>
|
||||
|
@ -155,7 +154,11 @@ from plexpy import helpers
|
|||
</strong></span>
|
||||
</div>
|
||||
<div class="button-bar">
|
||||
<button class="btn btn-danger" data-toggle="button" aria-pressed="false" autocomplete="off" id="row-edit-mode"><i class="fa fa-trash-o"></i> Delete Mode</button> 
|
||||
<span data-toggle="popover" data-placement="left" data-content="Select rows to delete. Data is deleted upon exiting delete mode." id="delete-message">
|
||||
<button class="btn btn-danger" data-toggle="button" aria-pressed="false" autocomplete="off" id="row-edit-mode">
|
||||
<i class="fa fa-trash-o"></i> Delete mode
|
||||
</button> 
|
||||
</span>
|
||||
<div class="colvis-button-bar hidden-xs" id="button-bar-history">
|
||||
</div>
|
||||
</div>
|
||||
|
@ -227,6 +230,24 @@ from plexpy import helpers
|
|||
</div>
|
||||
<div class="modal fade" id="ip-info-modal" tabindex="-1" role="dialog" aria-labelledby="ip-info-modal">
|
||||
</div>
|
||||
<div class="modal fade" id="confirm-modal" tabindex="-1" role="dialog" aria-labelledby="confirm-modal">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true"><i class="fa fa-remove"></i></button>
|
||||
<h4 class="modal-title" id="myModalLabel">Confirm Delete</h4>
|
||||
</div>
|
||||
<div class="modal-body" style="text-align: center;">
|
||||
<p>Are you REALLY sure you want to delete <strong><span id="deleteCount"></span></strong> history item(s)?</p>
|
||||
<p>This is permanent and cannot be undone!</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-dark" data-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-danger btn-ok" data-dismiss="modal" id="confirm-delete">Delete</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<footer></footer>
|
||||
</%def>
|
||||
|
@ -368,13 +389,36 @@ from plexpy import helpers
|
|||
});
|
||||
});
|
||||
|
||||
// Delete mode button
|
||||
$('#row-edit-mode').click(function() {
|
||||
$('#row-edit-mode').on('click', function() {
|
||||
$('#delete-message').popover();
|
||||
|
||||
if ($(this).hasClass('active')) {
|
||||
$('.delete-control').each(function() {
|
||||
if (history_to_delete.length > 0) {
|
||||
$('#deleteCount').text(history_to_delete.length);
|
||||
$('#confirm-modal').modal();
|
||||
$('#confirm-modal').one('click', '#confirm-delete', function () {
|
||||
for (var i = 0; i < history_to_delete.length; i++) {
|
||||
$.ajax({
|
||||
url: 'delete_history_rows',
|
||||
data: { row_id: history_to_delete[i] },
|
||||
async: true,
|
||||
success: function (data) {
|
||||
var msg = "User history purged";
|
||||
showMsg(msg, false, true, 2000);
|
||||
}
|
||||
});
|
||||
}
|
||||
history_table.draw();
|
||||
});
|
||||
}
|
||||
|
||||
$('.delete-control').each(function () {
|
||||
$(this).find('button.btn-danger').toggleClass('btn-warning').toggleClass('btn-danger');
|
||||
$(this).addClass('hidden');
|
||||
});
|
||||
|
||||
} else {
|
||||
history_to_delete = [];
|
||||
$('.delete-control').each(function() {
|
||||
$(this).removeClass('hidden');
|
||||
});
|
||||
|
|
|
@ -34,7 +34,7 @@ DOCUMENTATION :: END
|
|||
</div>
|
||||
</ul>
|
||||
<script>
|
||||
$("#user-platform-image-${a['result_id']}").html("<div class='user-platforms-instance-poster' style='background-image: url(" + getPlatformImagePath('${a['platform_type']}') + ");'>");
|
||||
$("#user-platform-image-${a['result_id']}").html("<div class='user-platforms-instance-box' style='background-image: url(" + getPlatformImagePath('${a['platform_type']}') + ");'>");
|
||||
</script>
|
||||
% endfor
|
||||
% else:
|
||||
|
|
|
@ -12,6 +12,11 @@
|
|||
<span><i class="fa fa-group"></i> All Users</span>
|
||||
</div>
|
||||
<div class="button-bar">
|
||||
<span data-toggle="popover" data-placement="left" data-content="Data purging does not occur until after exiting edit mode." id="purge-message">
|
||||
<button class="btn btn-dark" data-toggle="button" aria-pressed="false" autocomplete="off" id="row-edit-mode">
|
||||
<i class="fa fa-pencil"></i> Edit mode
|
||||
</button> 
|
||||
</span>
|
||||
<button class="btn btn-dark" id="refresh-users-list"><i class="fa fa-refresh"></i> Refresh users</button>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -19,6 +24,7 @@
|
|||
<table id="users_list_table" class="display" width="100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<th align="left" id="edit_row">Edit</th>
|
||||
<th align="right" id="avatar"></th>
|
||||
<th align="left" id="friendly_name">User</th>
|
||||
<th align="left" id="last_seen">Last Seen</th>
|
||||
|
@ -35,6 +41,25 @@
|
|||
</div>
|
||||
<div class="modal fade" id="ip-info-modal" tabindex="-1" role="dialog" aria-labelledby="ip-info-modal">
|
||||
</div>
|
||||
<div class="modal fade" id="confirm-modal" tabindex="-1" role="dialog" aria-labelledby="confirm-modal">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true"><i class="fa fa-remove"></i></button>
|
||||
<h4 class="modal-title" id="myModalLabel">Confirm Purge</h4>
|
||||
</div>
|
||||
<div class="modal-body" style="text-align: center;">
|
||||
<p>Are you REALLY sure you want to purge all history for the following users:</p>
|
||||
<ul id="users-to-delete" class="list-unstyled"></ul>
|
||||
<p>This is permanent and cannot be undone!</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-dark" data-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-danger btn-ok" data-dismiss="modal" id="confirm-purge">Purge</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -47,7 +72,7 @@
|
|||
<script src="interfaces/default/js/moment-with-locale.js"></script>
|
||||
<script src="interfaces/default/js/tables/users.js"></script>
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$(document).ready(function () {
|
||||
users_list_table_options.ajax = {
|
||||
"url": "get_user_list",
|
||||
type: "post",
|
||||
|
@ -59,8 +84,72 @@
|
|||
users_list_table = $('#users_list_table').DataTable(users_list_table_options);
|
||||
|
||||
clearSearchButton('users_list_table', users_list_table);
|
||||
});
|
||||
|
||||
var users_to_purge = [];
|
||||
$('#row-edit-mode').on('click', function () {
|
||||
$('#purge-message').popover();
|
||||
|
||||
if ($(this).hasClass('active')) {
|
||||
users_to_purge = [];
|
||||
ul = $('#users-to-delete');
|
||||
ul.html('');
|
||||
$('.edit-control button.btn-danger').map(function () {
|
||||
users_to_purge.push($(this).attr('data-id'));
|
||||
ul.append('<li>' + $('div[data-id=' + $(this).attr('data-id') + '] > input').val() + '</li>')
|
||||
});
|
||||
if (users_to_purge.length > 0) {
|
||||
$('#users-to-delete').append
|
||||
$('#confirm-modal').modal();
|
||||
$('#confirm-modal').one('click', '#confirm-purge', function () {
|
||||
for (var i = 0; i < users_to_purge.length; i++) {
|
||||
$.ajax({
|
||||
url: 'delete_all_user_history',
|
||||
data: { user_id: users_to_purge[i] },
|
||||
cache: false,
|
||||
async: true,
|
||||
success: function (data) {
|
||||
var msg = "User history purged";
|
||||
showMsg(msg, false, true, 2000);
|
||||
}
|
||||
});
|
||||
}
|
||||
users_list_table.draw();
|
||||
});
|
||||
}
|
||||
|
||||
$('.edit-control').each(function () {
|
||||
$(this).find('button.btn-danger').toggleClass('btn-warning').toggleClass('btn-danger');
|
||||
$(this).addClass('hidden');
|
||||
});
|
||||
$('.edit-user-control > .edit-user-name').each(function () {
|
||||
a = $(this).children('a');
|
||||
input = $(this).children('input');
|
||||
a.text(input.val());
|
||||
a.removeClass('hidden');
|
||||
input.addClass('hidden');
|
||||
});
|
||||
|
||||
} else {
|
||||
$('.edit-control').each(function () {
|
||||
$(this).removeClass('hidden');
|
||||
});
|
||||
$('.edit-user-control > .edit-user-name').each(function () {
|
||||
$(this).children('a').addClass('hidden');
|
||||
$(this).children('input').removeClass('hidden');
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
$(window).resize(function () {
|
||||
if ($('.popover').popover().is(':visible')) {
|
||||
var popover = $('.popover');
|
||||
popover.addClass("noTransition");
|
||||
$('#purge-message').popover('show');
|
||||
popover.removeClass("noTransition");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$("#refresh-users-list").click(function() {
|
||||
$.ajax({
|
||||
|
@ -76,4 +165,4 @@
|
|||
});
|
||||
});
|
||||
</script>
|
||||
</%def>
|
||||
</%def>
|
|
@ -1,4 +1,4 @@
|
|||
# PlexPy
|
||||
# PlexPy - Stats for Plex Media Server usage
|
||||
#
|
||||
# Service Unit file for systemd system manager
|
||||
#
|
||||
|
@ -53,7 +53,7 @@
|
|||
# graphical.target equates to runlevel 5 (multi-user X11 graphical mode)
|
||||
|
||||
[Unit]
|
||||
Description=PlexPy
|
||||
Description=PlexPy - Stats for Plex Media Server usage
|
||||
|
||||
[Service]
|
||||
ExecStart=/home/sabnzbd/plexpy/PlexPy.py --daemon --config /etc/plexpy/plexpy.ini --datadir /home/sabnzbd/.plexpy --nolaunch --quiet
|
||||
|
|
67
init-scripts/init.opensuse.systemd
Normal file
67
init-scripts/init.opensuse.systemd
Normal file
|
@ -0,0 +1,67 @@
|
|||
# PlexPy - Stats for Plex Media Server usage
|
||||
#
|
||||
# Service Unit file for systemd system manager
|
||||
#
|
||||
# INSTALLATION NOTES
|
||||
#
|
||||
# 1. Rename this file as you want, ensuring that it ends in .service
|
||||
# e.g. 'plexpy.service'
|
||||
#
|
||||
# 2. Adjust configuration settings as required. More details in the
|
||||
# "CONFIGURATION NOTES" section shown below.
|
||||
#
|
||||
# 3. Copy this file into your systemd service unit directory, which is
|
||||
# often '/lib/systemd/system'.
|
||||
#
|
||||
# 4. Create any files/directories that you specified back in step #2.
|
||||
# e.g. '/opt/plexpy.ini'
|
||||
# '/opt/plexpy'
|
||||
#
|
||||
# 5. Enable boot-time autostart with the following commands:
|
||||
# systemctl daemon-reload
|
||||
# systemctl enable plexpy.service
|
||||
#
|
||||
# 6. Start now with the following command:
|
||||
# systemctl start plexpy.service
|
||||
#
|
||||
# 7. If troubleshooting startup-errors, start by checking permissions
|
||||
# and ownership on the files/directories that you created in step #4.
|
||||
#
|
||||
#
|
||||
# CONFIGURATION NOTES
|
||||
#
|
||||
# - The example settings in this file assume that:
|
||||
# 1. You will run PlexPy as user/group: plex.users
|
||||
# 2. You will either have PlexPy installed as a subdirectory
|
||||
# under '/opt', or that you will have a symlink under
|
||||
# '/opt' pointing to your PlexPy install dir.
|
||||
# 3. Your PlexPy data directory and configuration file can be
|
||||
# in separate locations from your PlexPy install dir, to
|
||||
# simplify updates. However, in the example below they are in the
|
||||
# PlexPy install dir.
|
||||
#
|
||||
# - Option names (e.g. ExecStart=, Type=) appear to be case-sensitive)
|
||||
#
|
||||
# - Adjust ExecStart= to point to:
|
||||
# 1. Your PlexPy executable,
|
||||
# 2. Your config file (recommended is to put it somewhere in /etc)
|
||||
# 3. Your datadir (recommended is to NOT put it in your PlexPy exec dir)
|
||||
#
|
||||
# - Adjust User= and Group= to the user/group you want PlexPy to run as.
|
||||
#
|
||||
# - WantedBy= specifies which target (i.e. runlevel) to start PlexPy for.
|
||||
# multi-user.target equates to runlevel 3 (multi-user text mode)
|
||||
# graphical.target equates to runlevel 5 (multi-user X11 graphical mode)
|
||||
|
||||
[Unit]
|
||||
Description=PlexPy - Stats for Plex Media Server usage
|
||||
|
||||
[Service]
|
||||
ExecStart=/opt/plexpy/PlexPy.py --daemon --config /opt/plexpy/config.ini --datadir /opt/plexpy --nolaunch --quiet
|
||||
GuessMainPID=no
|
||||
Type=forking
|
||||
User=plex
|
||||
Group=users
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
66
init-scripts/init.ubuntu.systemd
Normal file
66
init-scripts/init.ubuntu.systemd
Normal file
|
@ -0,0 +1,66 @@
|
|||
# PlexPy - Stats for Plex Media Server usage
|
||||
#
|
||||
# Service Unit file for systemd system manager
|
||||
#
|
||||
# INSTALLATION NOTES
|
||||
#
|
||||
# 1. Rename this file as you want, ensuring that it ends in .service
|
||||
# e.g. 'plexpy.service'
|
||||
#
|
||||
# 2. Adjust configuration settings as required. More details in the
|
||||
# "CONFIGURATION NOTES" section shown below.
|
||||
#
|
||||
# 3. Copy this file into your systemd service unit directory, which is
|
||||
# often '/lib/systemd/system'.
|
||||
#
|
||||
# 4. Create any files/directories that you specified back in step #2.
|
||||
# e.g. '/etc/plexpy/plexpy.ini'
|
||||
# '/home/sabnzbd/.plexpy'
|
||||
#
|
||||
# 5. Enable boot-time autostart with the following commands:
|
||||
# systemctl daemon-reload
|
||||
# systemctl enable plexpy.service
|
||||
#
|
||||
# 6. Start now with the following command:
|
||||
# systemctl start plexpy.service
|
||||
#
|
||||
# 7. If troubleshooting startup-errors, start by checking permissions
|
||||
# and ownership on the files/directories that you created in step #4.
|
||||
#
|
||||
#
|
||||
# CONFIGURATION NOTES
|
||||
#
|
||||
# - The example settings in this file assume that:
|
||||
# 1. You will run PlexPy as user/group: sabnzbd.sabnzbd
|
||||
# 2. You will either have PlexPy installed as a subdirectory
|
||||
# under '~sabnzbd', or that you will have a symlink under
|
||||
# '~/sabnzbd' pointing to your PlexPy install dir.
|
||||
# 3. Your PlexPy data directory and configuration file will be
|
||||
# in separate locations from your PlexPy install dir, to
|
||||
# simplify updates.
|
||||
#
|
||||
# - Option names (e.g. ExecStart=, Type=) appear to be case-sensitive)
|
||||
#
|
||||
# - Adjust ExecStart= to point to:
|
||||
# 1. Your PlexPy executable,
|
||||
# 2. Your config file (recommended is to put it somewhere in /etc)
|
||||
# 3. Your datadir (recommended is to NOT put it in your PlexPy exec dir)
|
||||
#
|
||||
# - Adjust User= and Group= to the user/group you want PlexPy to run as.
|
||||
#
|
||||
# - WantedBy= specifies which target (i.e. runlevel) to start PlexPy for.
|
||||
# multi-user.target equates to runlevel 3 (multi-user text mode)
|
||||
# graphical.target equates to runlevel 5 (multi-user X11 graphical mode)
|
||||
|
||||
[Unit]
|
||||
Description=PlexPy - Stats for Plex Media Server usage
|
||||
|
||||
[Service]
|
||||
ExecStart=/opt/plexpy/PlexPy.py --quiet --daemon --nolaunch --config /opt/plexpy/config.ini --datadir /opt/plexpy
|
||||
GuessMainPID=no
|
||||
Type=forking
|
||||
User=plexpy
|
||||
Group=nogroup
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
|
@ -259,7 +259,7 @@ class Graphs(object):
|
|||
dt = datetime.datetime(*month_item[:6])
|
||||
date_string = dt.strftime('%Y-%m')
|
||||
|
||||
categories.append(date_string)
|
||||
categories.append(dt.strftime('%b %Y'))
|
||||
series_1_value = 0
|
||||
series_2_value = 0
|
||||
for item in result:
|
||||
|
|
|
@ -162,6 +162,7 @@ def notify(stream_data=None, notify_action=None):
|
|||
else:
|
||||
logger.debug(u"PlexPy Notifier :: Notify called but incomplete data received.")
|
||||
|
||||
|
||||
def get_notify_state(session):
|
||||
monitor_db = database.MonitorDatabase()
|
||||
result = monitor_db.select('SELECT on_play, on_stop, on_pause, on_resume, on_buffer, on_watched, agent_id '
|
||||
|
@ -184,6 +185,7 @@ def get_notify_state(session):
|
|||
|
||||
return notify_states
|
||||
|
||||
|
||||
def set_notify_state(session, state, agent_info):
|
||||
|
||||
if session and state and agent_info:
|
||||
|
@ -215,6 +217,7 @@ def set_notify_state(session, state, agent_info):
|
|||
else:
|
||||
logger.error('PlexPy Notifier :: Unable to set notify state.')
|
||||
|
||||
|
||||
def build_notify_text(session, state):
|
||||
from plexpy import pmsconnect, helpers
|
||||
import re
|
||||
|
@ -300,7 +303,13 @@ def build_notify_text(session, state):
|
|||
|
||||
duration = helpers.convert_milliseconds_to_minutes(item_metadata['duration'])
|
||||
view_offset = helpers.convert_milliseconds_to_minutes(session['view_offset'])
|
||||
stream_duration = 0 if state == 'play' else int((time.time() - helpers.cast_to_float(session['started']) - helpers.cast_to_float(session['paused_counter'])) / 60)
|
||||
stream_duration = 0
|
||||
if state != 'play':
|
||||
if session['paused_counter']:
|
||||
stream_duration = int((time.time() - helpers.cast_to_float(session['started']) -
|
||||
helpers.cast_to_float(session['paused_counter'])) / 60)
|
||||
else:
|
||||
stream_duration = int((time.time() - helpers.cast_to_float(session['started'])) / 60)
|
||||
|
||||
progress_percent = helpers.get_percent(view_offset, duration)
|
||||
|
||||
|
@ -479,6 +488,7 @@ def build_notify_text(session, state):
|
|||
else:
|
||||
return None
|
||||
|
||||
|
||||
def strip_tag(data):
|
||||
import re
|
||||
|
||||
|
|
|
@ -40,7 +40,9 @@ class Users(object):
|
|||
'session_history_metadata.media_type',
|
||||
'session_history.rating_key as rating_key',
|
||||
'session_history_media_info.video_decision',
|
||||
'users.username as user'
|
||||
'users.username as user',
|
||||
'users.do_notify as do_notify',
|
||||
'users.keep_history as keep_history'
|
||||
]
|
||||
try:
|
||||
query = data_tables.ssp_query(table_name='users',
|
||||
|
@ -94,7 +96,9 @@ class Users(object):
|
|||
"video_decision": item['video_decision'],
|
||||
"user_thumb": user_thumb,
|
||||
"user": item["user"],
|
||||
"user_id": item['user_id']
|
||||
"user_id": item['user_id'],
|
||||
"do_notify": helpers.checked(item['do_notify']),
|
||||
"keep_history": helpers.checked(item['keep_history'])
|
||||
}
|
||||
|
||||
rows.append(row)
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
PLEXPY_VERSION = "master"
|
||||
PLEXPY_RELEASE_VERSION = "1.1.3"
|
||||
PLEXPY_RELEASE_VERSION = "1.1.4"
|
||||
|
|
|
@ -492,18 +492,34 @@ class WebInterface(object):
|
|||
kwargs[plain_config] = kwargs[use_config]
|
||||
del kwargs[use_config]
|
||||
|
||||
# Check if we should refresh our data
|
||||
refresh_users = False
|
||||
reschedule = False
|
||||
|
||||
if 'monitoring_interval' in kwargs and 'refresh_users_interval' in kwargs:
|
||||
if (kwargs['monitoring_interval'] != str(plexpy.CONFIG.MONITORING_INTERVAL)) or \
|
||||
(kwargs['refresh_users_interval'] != str(plexpy.CONFIG.REFRESH_USERS_INTERVAL)):
|
||||
reschedule = True
|
||||
|
||||
if 'pms_ip' in kwargs:
|
||||
if kwargs['pms_ip'] != plexpy.CONFIG.PMS_IP:
|
||||
refresh_users = True
|
||||
|
||||
plexpy.CONFIG.process_kwargs(kwargs)
|
||||
|
||||
# Write the config
|
||||
plexpy.CONFIG.write()
|
||||
|
||||
# Reconfigure scheduler
|
||||
plexpy.initialize_scheduler()
|
||||
|
||||
# Get new server URLs for SSL communications.
|
||||
plextv.get_real_pms_url()
|
||||
|
||||
# Refresh users table. Probably shouldn't do this on every config save, will improve this later.
|
||||
threading.Thread(target=plextv.refresh_users).start()
|
||||
# Reconfigure scheduler if intervals changed
|
||||
if reschedule:
|
||||
plexpy.initialize_scheduler()
|
||||
|
||||
# Refresh users table if our server IP changes.
|
||||
if refresh_users:
|
||||
threading.Thread(target=plextv.refresh_users).start()
|
||||
|
||||
raise cherrypy.HTTPRedirect("settings")
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue