Compare commits
29 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
ea41d06023 | ||
![]() |
5147baab05 | ||
![]() |
ed2d34e979 | ||
![]() |
c404016700 | ||
![]() |
14b0353ba4 | ||
![]() |
fbe136a350 | ||
![]() |
4fcfea943e | ||
![]() |
279d27d081 | ||
![]() |
651125ef2c | ||
![]() |
a5eb0e7faa | ||
![]() |
e85cdd5609 | ||
![]() |
83f80b9288 | ||
![]() |
76fe771d8c | ||
![]() |
c6ad09fe8f | ||
![]() |
a3014638c8 | ||
![]() |
8b15c63b0d | ||
![]() |
589adf4df9 | ||
![]() |
b07d85f233 | ||
![]() |
f0e5855a8e | ||
![]() |
5997aa5cd9 | ||
![]() |
cb2a38addc | ||
![]() |
873f857c82 | ||
![]() |
b9a22461c1 | ||
![]() |
85a02771a7 | ||
![]() |
6a0b0327c3 | ||
![]() |
3742f33d08 | ||
![]() |
82ac33dd75 | ||
![]() |
8c7c0101cd | ||
![]() |
4d6179dfdd |
29
CHANGELOG.md
@@ -1,5 +1,34 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## v1.4.19 (2017-05-31)
|
||||||
|
|
||||||
|
* Fix: Video resolution not showing up for transcoded streams on PMS 1.7.x.
|
||||||
|
|
||||||
|
|
||||||
|
## v1.4.18 (2017-04-22)
|
||||||
|
|
||||||
|
* New: Added some new Arnold quotes. (Thanks @senepa)
|
||||||
|
* Fix: Text wrapping in datatable footers.
|
||||||
|
* Fix: API command get_apikey. (Thanks @Hellowlol)
|
||||||
|
|
||||||
|
|
||||||
|
## v1.4.17 (2017-03-04)
|
||||||
|
|
||||||
|
* New: Configurable month range for the Plays by month graph. (Thanks @Pbaboe)
|
||||||
|
* New: Option to chanage the week to start on Monday for the the Plays by day of week graph. (Thanks @Pbaboe)
|
||||||
|
* Fix: Invalid iOS icon file paths. (Thanks @demonbane)
|
||||||
|
* Fix: Plex Web 3.0 URLs on info pages and notifications.
|
||||||
|
* Fix: Update bitcoin donation link to Coinbase.
|
||||||
|
* Fix: Update init scripts. (Thanks @ampsonic)
|
||||||
|
|
||||||
|
|
||||||
|
## v1.4.16 (2016-11-25)
|
||||||
|
|
||||||
|
* Fix: Websocket for new json response on PMS 1.3.0.
|
||||||
|
* Fix: Update stream and transcoder tooltip percent.
|
||||||
|
* Fix: Typo in the edit user modal.
|
||||||
|
|
||||||
|
|
||||||
## v1.4.15 (2016-11-11)
|
## v1.4.15 (2016-11-11)
|
||||||
|
|
||||||
* New: Add stream and transcoder progress percent to the current activity tooltip.
|
* New: Add stream and transcoder progress percent to the current activity tooltip.
|
||||||
|
@@ -1,15 +1,13 @@
|
|||||||
# PlexPy
|
# PlexPy
|
||||||
|
|
||||||
[](https://gitter.im/plexpy/general?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
[](https://discord.gg/36ggawe)
|
||||||
|
[](https://gitter.im/plexpy/general)
|
||||||
|
[](https://forums.plex.tv/discussion/169591/plexpy-another-plex-monitoring-program)
|
||||||
|
|
||||||
A python based web application for monitoring, analytics and notifications for [Plex Media Server](https://plex.tv).
|
A python based web application for monitoring, analytics and notifications for [Plex Media Server](https://plex.tv).
|
||||||
|
|
||||||
This project is based on code from [Headphones](https://github.com/rembo10/headphones) and [PlexWatchWeb](https://github.com/ecleese/plexWatchWeb).
|
This project is based on code from [Headphones](https://github.com/rembo10/headphones) and [PlexWatchWeb](https://github.com/ecleese/plexWatchWeb).
|
||||||
|
|
||||||
* [Plex forum thread](https://forums.plex.tv/discussion/169591/plexpy-another-plex-monitoring-program)
|
|
||||||
* [Gitter chat](https://gitter.im/plexpy/general)
|
|
||||||
* [/r/Plex Discord server](https://discord.gg/011TFFWSuNFI02EKr) | [PlexPy Discord server](https://discord.gg/36ggawe)
|
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
* Responsive web design viewable on desktop, tablet and mobile web browsers.
|
* Responsive web design viewable on desktop, tablet and mobile web browsers.
|
||||||
|
@@ -66,67 +66,67 @@
|
|||||||
|
|
||||||
<!-- STARTUP IMAGES -->
|
<!-- STARTUP IMAGES -->
|
||||||
<!-- iPad retina portrait startup image -->
|
<!-- iPad retina portrait startup image -->
|
||||||
<link href="${http_root}images/res/screen/ios/Default-Portrait@2x~ipad.png"
|
<link href="${http_root}images/res/ios/Default-Portrait@2x~ipad.png"
|
||||||
media="(device-width: 768px) and (device-height: 1024px)
|
media="(device-width: 768px) and (device-height: 1024px)
|
||||||
and (-webkit-device-pixel-ratio: 2)
|
and (-webkit-device-pixel-ratio: 2)
|
||||||
and (orientation: portrait)"
|
and (orientation: portrait)"
|
||||||
rel="apple-touch-startup-image">
|
rel="apple-touch-startup-image">
|
||||||
|
|
||||||
<!-- iPad retina landscape startup image -->
|
<!-- iPad retina landscape startup image -->
|
||||||
<link href="${http_root}images/res/screen/ios/Default-Landscape@2x~ipad.png"
|
<link href="${http_root}images/res/ios/Default-Landscape@2x~ipad.png"
|
||||||
media="(device-width: 768px) and (device-height: 1024px)
|
media="(device-width: 768px) and (device-height: 1024px)
|
||||||
and (-webkit-device-pixel-ratio: 2)
|
and (-webkit-device-pixel-ratio: 2)
|
||||||
and (orientation: landscape)"
|
and (orientation: landscape)"
|
||||||
rel="apple-touch-startup-image">
|
rel="apple-touch-startup-image">
|
||||||
|
|
||||||
<!-- iPad non-retina portrait startup image -->
|
<!-- iPad non-retina portrait startup image -->
|
||||||
<link href="${http_root}images/res/screen/ios/Default-Portrait~ipad.png"
|
<link href="${http_root}images/res/ios/Default-Portrait~ipad.png"
|
||||||
media="(device-width: 768px) and (device-height: 1024px)
|
media="(device-width: 768px) and (device-height: 1024px)
|
||||||
and (-webkit-device-pixel-ratio: 1)
|
and (-webkit-device-pixel-ratio: 1)
|
||||||
and (orientation: portrait)"
|
and (orientation: portrait)"
|
||||||
rel="apple-touch-startup-image">
|
rel="apple-touch-startup-image">
|
||||||
|
|
||||||
<!-- iPad non-retina landscape startup image -->
|
<!-- iPad non-retina landscape startup image -->
|
||||||
<link href="${http_root}images/res/screen/ios/Default-Landscape~ipad.png"
|
<link href="${http_root}images/res/ios/Default-Landscape~ipad.png"
|
||||||
media="(device-width: 768px) and (device-height: 1024px)
|
media="(device-width: 768px) and (device-height: 1024px)
|
||||||
and (-webkit-device-pixel-ratio: 1)
|
and (-webkit-device-pixel-ratio: 1)
|
||||||
and (orientation: landscape)"
|
and (orientation: landscape)"
|
||||||
rel="apple-touch-startup-image">
|
rel="apple-touch-startup-image">
|
||||||
|
|
||||||
<!-- iPhone 6 Plus portrait startup image -->
|
<!-- iPhone 6 Plus portrait startup image -->
|
||||||
<link href="${http_root}images/res/screen/ios/Default-736h.png"
|
<link href="${http_root}images/res/ios/Default-736h.png"
|
||||||
media="(device-width: 414px) and (device-height: 736px)
|
media="(device-width: 414px) and (device-height: 736px)
|
||||||
and (-webkit-device-pixel-ratio: 3)
|
and (-webkit-device-pixel-ratio: 3)
|
||||||
and (orientation: portrait)"
|
and (orientation: portrait)"
|
||||||
rel="apple-touch-startup-image">
|
rel="apple-touch-startup-image">
|
||||||
|
|
||||||
<!-- iPhone 6 Plus landscape startup image -->
|
<!-- iPhone 6 Plus landscape startup image -->
|
||||||
<link href="${http_root}images/res/screen/ios/Default-Landscape-736h.png"
|
<link href="${http_root}images/res/ios/Default-Landscape-736h.png"
|
||||||
media="(device-width: 414px) and (device-height: 736px)
|
media="(device-width: 414px) and (device-height: 736px)
|
||||||
and (-webkit-device-pixel-ratio: 3)
|
and (-webkit-device-pixel-ratio: 3)
|
||||||
and (orientation: landscape)"
|
and (orientation: landscape)"
|
||||||
rel="apple-touch-startup-image">
|
rel="apple-touch-startup-image">
|
||||||
|
|
||||||
<!-- iPhone 6 startup image -->
|
<!-- iPhone 6 startup image -->
|
||||||
<link href="${http_root}images/res/screen/ios/Default-667h.png"
|
<link href="${http_root}images/res/ios/Default-667h.png"
|
||||||
media="(device-width: 375px) and (device-height: 667px)
|
media="(device-width: 375px) and (device-height: 667px)
|
||||||
and (-webkit-device-pixel-ratio: 2)"
|
and (-webkit-device-pixel-ratio: 2)"
|
||||||
rel="apple-touch-startup-image">
|
rel="apple-touch-startup-image">
|
||||||
|
|
||||||
<!-- iPhone 5 startup image -->
|
<!-- iPhone 5 startup image -->
|
||||||
<link href="${http_root}images/res/screen/ios/Default-568h@2x~iphone5.jpg"
|
<link href="${http_root}images/res/ios/Default-568h@2x~iphone5.jpg"
|
||||||
media="(device-width: 320px) and (device-height: 568px)
|
media="(device-width: 320px) and (device-height: 568px)
|
||||||
and (-webkit-device-pixel-ratio: 2)"
|
and (-webkit-device-pixel-ratio: 2)"
|
||||||
rel="apple-touch-startup-image">
|
rel="apple-touch-startup-image">
|
||||||
|
|
||||||
<!-- iPhone < 5 retina startup image -->
|
<!-- iPhone < 5 retina startup image -->
|
||||||
<link href="${http_root}images/res/screen/ios/Default@2x~iphone.png"
|
<link href="${http_root}images/res/ios/Default@2x~iphone.png"
|
||||||
media="(device-width: 320px) and (device-height: 480px)
|
media="(device-width: 320px) and (device-height: 480px)
|
||||||
and (-webkit-device-pixel-ratio: 2)"
|
and (-webkit-device-pixel-ratio: 2)"
|
||||||
rel="apple-touch-startup-image">
|
rel="apple-touch-startup-image">
|
||||||
|
|
||||||
<!-- iPhone < 5 non-retina startup image -->
|
<!-- iPhone < 5 non-retina startup image -->
|
||||||
<link href="${http_root}images/res/screen/ios/Default~iphone.png"
|
<link href="${http_root}images/res/ios/Default~iphone.png"
|
||||||
media="(device-width: 320px) and (device-height: 480px)
|
media="(device-width: 320px) and (device-height: 480px)
|
||||||
and (-webkit-device-pixel-ratio: 1)"
|
and (-webkit-device-pixel-ratio: 1)"
|
||||||
rel="apple-touch-startup-image">
|
rel="apple-touch-startup-image">
|
||||||
@@ -223,8 +223,8 @@
|
|||||||
<li><a href="${anon_url('https://github.com/%s/plexpy/wiki/Frequently-Asked-Questions-(FAQ)' % plexpy.CONFIG.GIT_USER)}" target="_blank"><i class="fa fa-fw fa-question-circle"></i> FAQ</a></li>
|
<li><a href="${anon_url('https://github.com/%s/plexpy/wiki/Frequently-Asked-Questions-(FAQ)' % plexpy.CONFIG.GIT_USER)}" target="_blank"><i class="fa fa-fw fa-question-circle"></i> FAQ</a></li>
|
||||||
<li><a href="settings?support=true"><i class="fa fa-fw fa-comment"></i> Support</a></li>
|
<li><a href="settings?support=true"><i class="fa fa-fw fa-comment"></i> Support</a></li>
|
||||||
<li role="separator" class="divider"></li>
|
<li role="separator" class="divider"></li>
|
||||||
<li><a href="${anon_url('https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=DG783BMSCU3V4')}" target="_blank"><i class="fa fa-fw fa-paypal"></i> Paypal</a></li>
|
<li><a href="${anon_url('https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=6XPPKTDSX9QFL&lc=US&item_name=PlexPy¤cy_code=USD&bn=PP%2dDonationsBF%3abtn_donate_LG%2egif%3aNonHosted')}" target="_blank"><i class="fa fa-fw fa-paypal"></i> Paypal</a></li>
|
||||||
<li><a href="${anon_url('http://swiftpanda16.tip.me/')}" target="_blank"><i class="fa fa-fw fa-btc"></i> Bitcoin</a></li>
|
<li><a href="${anon_url('https://www.coinbase.com/JonnyWong16')}" target="_blank"><i class="fa fa-fw fa-btc"></i> Bitcoin</a></li>
|
||||||
<li role="separator" class="divider"></li>
|
<li role="separator" class="divider"></li>
|
||||||
% if plexpy.CONFIG.CHECK_GITHUB:
|
% if plexpy.CONFIG.CHECK_GITHUB:
|
||||||
<li><a href="#" id="nav-update"><i class="fa fa-fw fa-arrow-circle-up"></i> Check for Updates</a></li>
|
<li><a href="#" id="nav-update"><i class="fa fa-fw fa-arrow-circle-up"></i> Check for Updates</a></li>
|
||||||
|
@@ -2491,6 +2491,9 @@ a .home-platforms-list-cover-face:hover
|
|||||||
.dataTables_paginate li {
|
.dataTables_paginate li {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
div.dataTables_info {
|
||||||
|
white-space: normal !important;
|
||||||
|
}
|
||||||
.tooltip.top .tooltip-arrow {
|
.tooltip.top .tooltip-arrow {
|
||||||
border-top-color: #fff;
|
border-top-color: #fff;
|
||||||
}
|
}
|
||||||
@@ -2833,6 +2836,14 @@ div[id^='media_info_child'] div[id^='media_info_child'] div.dataTables_scrollHea
|
|||||||
width: 75px;
|
width: 75px;
|
||||||
height: 34px;
|
height: 34px;
|
||||||
}
|
}
|
||||||
|
#months-selection label {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
#graph-months {
|
||||||
|
margin: 0;
|
||||||
|
width: 75px;
|
||||||
|
height: 34px;
|
||||||
|
}
|
||||||
.card-sortable {
|
.card-sortable {
|
||||||
height: 36px;
|
height: 36px;
|
||||||
padding: 0 20px 0 0;
|
padding: 0 20px 0 0;
|
||||||
|
@@ -45,7 +45,7 @@ DOCUMENTATION :: END
|
|||||||
<input type="text" class="form-control" id="friendly_name" name="friendly_name" value="${data['friendly_name']}" size="30">
|
<input type="text" class="form-control" id="friendly_name" name="friendly_name" value="${data['friendly_name']}" size="30">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p class="help-block">Replace all occurances of the username with this name.</p>
|
<p class="help-block">Replace all occurrences of the username with this name.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="profile_url">Profile Picture URL</label>
|
<label for="profile_url">Profile Picture URL</label>
|
||||||
|
@@ -42,6 +42,11 @@
|
|||||||
<input type="number" name="graph-days" id="graph-days" value="${config['graph_days']}" min="1" /> days
|
<input type="number" name="graph-days" id="graph-days" value="${config['graph_days']}" min="1" /> days
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="btn-group" id="months-selection">
|
||||||
|
<label>
|
||||||
|
<input type="number" name="graph-months" id="graph-months" value="${config['graph_months']}" min="1" /> months
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class='table-card-back'>
|
<div class='table-card-back'>
|
||||||
@@ -226,7 +231,7 @@
|
|||||||
% endif
|
% endif
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
<h4><i class="fa fa-calendar"></i> Plays by Month <small>Last 12 months</small></h4>
|
<h4><i class="fa fa-calendar"></i> Plays by month <small>Last <span class="months">12</span> months</small></h4>
|
||||||
<p class="help-block">
|
<p class="help-block">
|
||||||
The combined total of tv, movies, and music by month.
|
The combined total of tv, movies, and music by month.
|
||||||
</p>
|
</p>
|
||||||
@@ -317,10 +322,12 @@
|
|||||||
|
|
||||||
// Initial values for graph from config
|
// Initial values for graph from config
|
||||||
var yaxis = "${config['graph_type']}";
|
var yaxis = "${config['graph_type']}";
|
||||||
var current_range = ${config['graph_days']};
|
var current_day_range = ${config['graph_days']};
|
||||||
|
var current_month_range = ${config['graph_months']};
|
||||||
var current_tab = "${'#' + config['graph_tab']}";
|
var current_tab = "${'#' + config['graph_tab']}";
|
||||||
|
|
||||||
$('.days').html(current_range);
|
$('.days').html(current_day_range);
|
||||||
|
$('.months').html(current_month_range);
|
||||||
|
|
||||||
// Load user ids and names (for the selector)
|
// Load user ids and names (for the selector)
|
||||||
$.ajax({
|
$.ajax({
|
||||||
@@ -352,6 +359,7 @@
|
|||||||
|
|
||||||
function loadGraphsTab1(time_range, yaxis) {
|
function loadGraphsTab1(time_range, yaxis) {
|
||||||
$('#days-selection').show();
|
$('#days-selection').show();
|
||||||
|
$('#months-selection').hide();
|
||||||
|
|
||||||
setGraphFormat(yaxis);
|
setGraphFormat(yaxis);
|
||||||
|
|
||||||
@@ -442,6 +450,7 @@
|
|||||||
|
|
||||||
function loadGraphsTab2(time_range, yaxis) {
|
function loadGraphsTab2(time_range, yaxis) {
|
||||||
$('#days-selection').show();
|
$('#days-selection').show();
|
||||||
|
$('#months-selection').hide();
|
||||||
|
|
||||||
setGraphFormat(yaxis);
|
setGraphFormat(yaxis);
|
||||||
|
|
||||||
@@ -525,15 +534,16 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadGraphsTab3(yaxis) {
|
function loadGraphsTab3(time_range, yaxis) {
|
||||||
$('#days-selection').hide();
|
$('#days-selection').hide();
|
||||||
|
$('#months-selection').show();
|
||||||
|
|
||||||
setGraphFormat(yaxis);
|
setGraphFormat(yaxis);
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: "get_plays_per_month",
|
url: "get_plays_per_month",
|
||||||
type: 'get',
|
type: 'get',
|
||||||
data: { y_axis: yaxis, user_id: selected_user_id },
|
data: { time_range: time_range, y_axis: yaxis, user_id: selected_user_id },
|
||||||
dataType: "json",
|
dataType: "json",
|
||||||
success: function(data) {
|
success: function(data) {
|
||||||
if (yaxis === 'duration') { dataSecondsToHours(data); }
|
if (yaxis === 'duration') { dataSecondsToHours(data); }
|
||||||
@@ -547,15 +557,15 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set initial state
|
// Set initial state
|
||||||
if (current_tab == '#tabs-1') { loadGraphsTab1(current_range, yaxis); }
|
if (current_tab == '#tabs-1') { loadGraphsTab1(current_day_range, yaxis); }
|
||||||
if (current_tab == '#tabs-2') { loadGraphsTab2(current_range, yaxis); }
|
if (current_tab == '#tabs-2') { loadGraphsTab2(current_day_range, yaxis); }
|
||||||
if (current_tab == '#tabs-3') { loadGraphsTab3(yaxis); }
|
if (current_tab == '#tabs-3') { loadGraphsTab3(current_month_range, yaxis); }
|
||||||
|
|
||||||
// Tab1 opened
|
// Tab1 opened
|
||||||
$('#graph-tabs a[href="#tabs-1"]').on('shown.bs.tab', function (e) {
|
$('#graph-tabs a[href="#tabs-1"]').on('shown.bs.tab', function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
current_tab = $(this).attr('href');
|
current_tab = $(this).attr('href');
|
||||||
loadGraphsTab1(current_range, yaxis);
|
loadGraphsTab1(current_day_range, yaxis);
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: 'set_graph_config',
|
url: 'set_graph_config',
|
||||||
data: { graph_tab: current_tab.replace('#','') },
|
data: { graph_tab: current_tab.replace('#','') },
|
||||||
@@ -567,7 +577,7 @@
|
|||||||
$('#graph-tabs a[href="#tabs-2"]').on('shown.bs.tab', function (e) {
|
$('#graph-tabs a[href="#tabs-2"]').on('shown.bs.tab', function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
current_tab = $(this).attr('href');
|
current_tab = $(this).attr('href');
|
||||||
loadGraphsTab2(current_range, yaxis);
|
loadGraphsTab2(current_day_range, yaxis);
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: 'set_graph_config',
|
url: 'set_graph_config',
|
||||||
data: { graph_tab: current_tab.replace('#','') },
|
data: { graph_tab: current_tab.replace('#','') },
|
||||||
@@ -579,7 +589,7 @@
|
|||||||
$('#graph-tabs a[href="#tabs-3"]').on('shown.bs.tab', function (e) {
|
$('#graph-tabs a[href="#tabs-3"]').on('shown.bs.tab', function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
current_tab = $(this).attr('href');
|
current_tab = $(this).attr('href');
|
||||||
loadGraphsTab3(yaxis);
|
loadGraphsTab3(current_month_range, yaxis);
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: 'set_graph_config',
|
url: 'set_graph_config',
|
||||||
data: { graph_tab: current_tab.replace('#','') },
|
data: { graph_tab: current_tab.replace('#','') },
|
||||||
@@ -589,17 +599,35 @@
|
|||||||
|
|
||||||
// Date range changed
|
// Date range changed
|
||||||
$('#graph-days').on('change', function() {
|
$('#graph-days').on('change', function() {
|
||||||
current_range = $(this).val();
|
current_day_range = Math.round($(this).val());
|
||||||
if (current_range < 1) {
|
$(this).val(current_day_range);
|
||||||
|
if (current_day_range < 1) {
|
||||||
$(this).val(7);
|
$(this).val(7);
|
||||||
current_range = 7;
|
current_day_range = 7;
|
||||||
}
|
}
|
||||||
if (current_tab == '#tabs-1') { loadGraphsTab1(current_range, yaxis); }
|
if (current_tab == '#tabs-1') { loadGraphsTab1(current_day_range, yaxis); }
|
||||||
if (current_tab == '#tabs-2') { loadGraphsTab2(current_range, yaxis); }
|
if (current_tab == '#tabs-2') { loadGraphsTab2(current_day_range, yaxis); }
|
||||||
$('.days').html(current_range);
|
$('.days').html(current_day_range);
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: 'set_graph_config',
|
url: 'set_graph_config',
|
||||||
data: { graph_days: current_range},
|
data: { graph_days: current_day_range},
|
||||||
|
async: true
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Month range changed
|
||||||
|
$('#graph-months').on('change', function() {
|
||||||
|
current_month_range = Math.round($(this).val());
|
||||||
|
$(this).val(current_month_range);
|
||||||
|
if (current_month_range < 1) {
|
||||||
|
$(this).val(12);
|
||||||
|
current_month_range = 12;
|
||||||
|
}
|
||||||
|
if (current_tab == '#tabs-3') { loadGraphsTab3(current_month_range, yaxis); }
|
||||||
|
$('.months').html(current_month_range);
|
||||||
|
$.ajax({
|
||||||
|
url: 'set_graph_config',
|
||||||
|
data: { graph_months: current_month_range},
|
||||||
async: true
|
async: true
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -607,17 +635,17 @@
|
|||||||
// User changed
|
// User changed
|
||||||
$('#graph-user').on('change', function() {
|
$('#graph-user').on('change', function() {
|
||||||
selected_user_id = $(this).val() || null;
|
selected_user_id = $(this).val() || null;
|
||||||
if (current_tab == '#tabs-1') { loadGraphsTab1(current_range, yaxis); }
|
if (current_tab == '#tabs-1') { loadGraphsTab1(current_day_range, yaxis); }
|
||||||
if (current_tab == '#tabs-2') { loadGraphsTab2(current_range, yaxis); }
|
if (current_tab == '#tabs-2') { loadGraphsTab2(current_day_range, yaxis); }
|
||||||
if (current_tab == '#tabs-3') { loadGraphsTab3(yaxis); }
|
if (current_tab == '#tabs-3') { loadGraphsTab3(current_month_range, yaxis); }
|
||||||
});
|
});
|
||||||
|
|
||||||
// Y-axis changed
|
// Y-axis changed
|
||||||
$('#yaxis-selection').on('change', function() {
|
$('#yaxis-selection').on('change', function() {
|
||||||
yaxis = $('input[name=yaxis-options]:checked', '#yaxis-selection').val();
|
yaxis = $('input[name=yaxis-options]:checked', '#yaxis-selection').val();
|
||||||
if (current_tab == '#tabs-1') { loadGraphsTab1(current_range, yaxis); }
|
if (current_tab == '#tabs-1') { loadGraphsTab1(current_day_range, yaxis); }
|
||||||
if (current_tab == '#tabs-2') { loadGraphsTab2(current_range, yaxis); }
|
if (current_tab == '#tabs-2') { loadGraphsTab2(current_day_range, yaxis); }
|
||||||
if (current_tab == '#tabs-3') { loadGraphsTab3(yaxis); }
|
if (current_tab == '#tabs-3') { loadGraphsTab3(current_month_range, yaxis); }
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: 'set_graph_config',
|
url: 'set_graph_config',
|
||||||
data: { graph_type: yaxis},
|
data: { graph_type: yaxis},
|
||||||
|
Before Width: | Height: | Size: 137 KiB |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 8.1 KiB After Width: | Height: | Size: 8.1 KiB |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 6.5 KiB After Width: | Height: | Size: 6.5 KiB |
@@ -204,8 +204,11 @@
|
|||||||
|
|
||||||
// update the progress bars
|
// update the progress bars
|
||||||
// percent - 3 because of 3px padding-right
|
// percent - 3 because of 3px padding-right
|
||||||
$('#bufferbar-' + key).width(parseInt(s.transcode_progress) - 3 + '%').html(s.transcode_progress + '%');
|
$('#bufferbar-' + key).width(parseInt(s.transcode_progress) - 3 + '%').html(s.transcode_progress + '%')
|
||||||
$('#bar-' + key).width(parseInt(s.progress_percent) - 3 + '%').html(s.progress_percent + '%');
|
.attr('data-original-title', 'Transcoder Progress ' + s.transcode_progress + '%');
|
||||||
|
$('#bar-' + key).width(parseInt(s.progress_percent) - 3 + '%').html(s.progress_percent + '%')
|
||||||
|
.attr('data-original-title', 'Stream Progress ' + s.progress_percent + '%');
|
||||||
|
|
||||||
|
|
||||||
// add temporary class so we know which instances are still active
|
// add temporary class so we know which instances are still active
|
||||||
instance.addClass('updated-temp');
|
instance.addClass('updated-temp');
|
||||||
|
@@ -115,9 +115,9 @@ DOCUMENTATION :: END
|
|||||||
<div class="col-md-9">
|
<div class="col-md-9">
|
||||||
<div class="summary-content-poster hidden-xs hidden-sm">
|
<div class="summary-content-poster hidden-xs hidden-sm">
|
||||||
% if data['media_type'] == 'track':
|
% if data['media_type'] == 'track':
|
||||||
<a href="https://app.plex.tv/web/app#!/server/${config['pms_identifier']}/details/%2Flibrary%2Fmetadata%2F${data['parent_rating_key']}" target="_blank" title="View in Plex Web">
|
<a href="https://app.plex.tv/web/app#!/server/${config['pms_identifier']}/details?key=%2Flibrary%2Fmetadata%2F${data['parent_rating_key']}" target="_blank" title="View in Plex Web">
|
||||||
% else:
|
% else:
|
||||||
<a href="https://app.plex.tv/web/app#!/server/${config['pms_identifier']}/details/%2Flibrary%2Fmetadata%2F${data['rating_key']}" target="_blank" title="View in Plex Web">
|
<a href="https://app.plex.tv/web/app#!/server/${config['pms_identifier']}/details?key=%2Flibrary%2Fmetadata%2F${data['rating_key']}" target="_blank" title="View in Plex Web">
|
||||||
% endif
|
% endif
|
||||||
% if data['media_type'] == 'episode':
|
% if data['media_type'] == 'episode':
|
||||||
<div class="summary-poster-face-episode" style="background-image: url(pms_image_proxy?img=${data['thumb']}&width=500&height=280&fallback=art);">
|
<div class="summary-poster-face-episode" style="background-image: url(pms_image_proxy?img=${data['thumb']}&width=500&height=280&fallback=art);">
|
||||||
|
@@ -117,6 +117,12 @@
|
|||||||
</div>
|
</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>
|
<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>
|
||||||
|
<div class="checkbox">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" id="week_start_monday" name="week_start_monday" value="1" ${config['week_start_monday']}> Week Starting on Monday
|
||||||
|
</label>
|
||||||
|
<p class="help-block">Change the "<em>Play by day of week</em>" graph to start on Monday. Default is start on Sunday.</p>
|
||||||
|
</div>
|
||||||
<div class="checkbox">
|
<div class="checkbox">
|
||||||
<label>
|
<label>
|
||||||
<input type="checkbox" id="group_history_tables" name="group_history_tables" value="1" ${config['group_history_tables']}> Group Table and Watch Statistics History
|
<input type="checkbox" id="group_history_tables" name="group_history_tables" value="1" ${config['group_history_tables']}> Group Table and Watch Statistics History
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
#
|
#
|
||||||
# PROVIDE: plexpy
|
# PROVIDE: plexpy
|
||||||
# REQUIRE: sabnzbd
|
# REQUIRE: plexpy
|
||||||
# KEYWORD: shutdown
|
# KEYWORD: shutdown
|
||||||
#
|
#
|
||||||
# Add the following lines to /etc/rc.conf.local or /etc/rc.conf
|
# Add the following lines to /etc/rc.conf.local or /etc/rc.conf
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
# plexpy_enable (bool): Set to NO by default.
|
# plexpy_enable (bool): Set to NO by default.
|
||||||
# Set it to YES to enable it.
|
# Set it to YES to enable it.
|
||||||
# plexpy_user: The user account PlexPy daemon runs as what
|
# plexpy_user: The user account PlexPy daemon runs as what
|
||||||
# you want it to be. It uses '_sabnzbd' user by
|
# you want it to be. It uses 'plexpy' user by
|
||||||
# default. Do not sets it as empty or it will run
|
# default. Do not sets it as empty or it will run
|
||||||
# as root.
|
# as root.
|
||||||
# plexpy_dir: Directory where PlexPy lives.
|
# plexpy_dir: Directory where PlexPy lives.
|
||||||
@@ -28,7 +28,7 @@ rcvar=${name}_enable
|
|||||||
load_rc_config ${name}
|
load_rc_config ${name}
|
||||||
|
|
||||||
: ${plexpy_enable:="NO"}
|
: ${plexpy_enable:="NO"}
|
||||||
: ${plexpy_user:="_sabnzbd"}
|
: ${plexpy_user:="plexpy"}
|
||||||
: ${plexpy_dir:="/usr/local/plexpy"}
|
: ${plexpy_dir:="/usr/local/plexpy"}
|
||||||
: ${plexpy_chdir:="${plexpy_dir}"}
|
: ${plexpy_chdir:="${plexpy_dir}"}
|
||||||
: ${plexpy_pid:="${plexpy_dir}/plexpy.pid"}
|
: ${plexpy_pid:="${plexpy_dir}/plexpy.pid"}
|
||||||
|
@@ -1,66 +0,0 @@
|
|||||||
# 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=/home/sabnzbd/plexpy/PlexPy.py --daemon --config /etc/plexpy/plexpy.ini --datadir /home/sabnzbd/.plexpy --nolaunch --quiet
|
|
||||||
GuessMainPID=no
|
|
||||||
Type=forking
|
|
||||||
User=sabnzbd
|
|
||||||
Group=sabnzbd
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
@@ -1,7 +1,7 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
#
|
#
|
||||||
# PROVIDE: plexpy
|
# PROVIDE: plexpy
|
||||||
# REQUIRE: DAEMON sabnzbd
|
# REQUIRE: DAEMON plexpy
|
||||||
# KEYWORD: shutdown
|
# KEYWORD: shutdown
|
||||||
#
|
#
|
||||||
# Add the following lines to /etc/rc.conf.local or /etc/rc.conf
|
# Add the following lines to /etc/rc.conf.local or /etc/rc.conf
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
# plexpy_enable (bool): Set to NO by default.
|
# plexpy_enable (bool): Set to NO by default.
|
||||||
# Set it to YES to enable it.
|
# Set it to YES to enable it.
|
||||||
# plexpy_user: The user account PlexPy daemon runs as what
|
# plexpy_user: The user account PlexPy daemon runs as what
|
||||||
# you want it to be. It uses '_sabnzbd' user by
|
# you want it to be. It uses 'plexpy' user by
|
||||||
# default. Do not sets it as empty or it will run
|
# default. Do not sets it as empty or it will run
|
||||||
# as root.
|
# as root.
|
||||||
# plexpy_dir: Directory where PlexPy lives.
|
# plexpy_dir: Directory where PlexPy lives.
|
||||||
@@ -29,7 +29,7 @@ rcvar=${name}_enable
|
|||||||
load_rc_config ${name}
|
load_rc_config ${name}
|
||||||
|
|
||||||
: ${plexpy_enable:="NO"}
|
: ${plexpy_enable:="NO"}
|
||||||
: ${plexpy_user:="_sabnzbd"}
|
: ${plexpy_user:="plexpy"}
|
||||||
: ${plexpy_dir:="/usr/local/share/plexpy"}
|
: ${plexpy_dir:="/usr/local/share/plexpy"}
|
||||||
: ${plexpy_chdir:="${plexpy_dir}"}
|
: ${plexpy_chdir:="${plexpy_dir}"}
|
||||||
: ${plexpy_pid:="${plexpy_dir}/plexpy.pid"}
|
: ${plexpy_pid:="${plexpy_dir}/plexpy.pid"}
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
#
|
#
|
||||||
# PROVIDE: plexpy
|
# PROVIDE: plexpy
|
||||||
# REQUIRE: DAEMON sabnzbd
|
# REQUIRE: DAEMON plexpy
|
||||||
# KEYWORD: shutdown
|
# KEYWORD: shutdown
|
||||||
#
|
#
|
||||||
# Add the following lines to /etc/rc.conf.local or /etc/rc.conf
|
# Add the following lines to /etc/rc.conf.local or /etc/rc.conf
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
# plexpy_enable (bool): Set to NO by default.
|
# plexpy_enable (bool): Set to NO by default.
|
||||||
# Set it to YES to enable it.
|
# Set it to YES to enable it.
|
||||||
# plexpy_user: The user account PlexPy daemon runs as what
|
# plexpy_user: The user account PlexPy daemon runs as what
|
||||||
# you want it to be. It uses '_sabnzbd' user by
|
# you want it to be. It uses 'plexpy' user by
|
||||||
# default. Do not sets it as empty or it will run
|
# default. Do not sets it as empty or it will run
|
||||||
# as root.
|
# as root.
|
||||||
# plexpy_dir: Directory where PlexPy lives.
|
# plexpy_dir: Directory where PlexPy lives.
|
||||||
@@ -29,7 +29,7 @@ rcvar=${name}_enable
|
|||||||
load_rc_config ${name}
|
load_rc_config ${name}
|
||||||
|
|
||||||
: ${plexpy_enable:="NO"}
|
: ${plexpy_enable:="NO"}
|
||||||
: ${plexpy_user:="_sabnzbd"}
|
: ${plexpy_user:="plexpy"}
|
||||||
: ${plexpy_dir:="/usr/local/share/plexpy"}
|
: ${plexpy_dir:="/usr/local/share/plexpy"}
|
||||||
: ${plexpy_chdir:="${plexpy_dir}"}
|
: ${plexpy_chdir:="${plexpy_dir}"}
|
||||||
: ${plexpy_pid:="${plexpy_dir}/plexpy.pid"}
|
: ${plexpy_pid:="${plexpy_dir}/plexpy.pid"}
|
||||||
|
@@ -1,67 +0,0 @@
|
|||||||
# 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
|
|
@@ -19,7 +19,7 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<method_context>
|
<method_context>
|
||||||
<method_credential user="sabnzbd" group="sabnzbd"/>
|
<method_credential user="plexpy" group="nogroup"/>
|
||||||
</method_context>
|
</method_context>
|
||||||
|
|
||||||
<exec_method type="method" name="start" exec="python /opt/plexpy/PlexPy.py --daemon --quiet --nolaunch" timeout_seconds="60"/>
|
<exec_method type="method" name="start" exec="python /opt/plexpy/PlexPy.py --daemon --quiet --nolaunch" timeout_seconds="60"/>
|
||||||
|
@@ -13,31 +13,19 @@
|
|||||||
# 3. Copy this file into your systemd service unit directory, which is
|
# 3. Copy this file into your systemd service unit directory, which is
|
||||||
# often '/lib/systemd/system'.
|
# often '/lib/systemd/system'.
|
||||||
#
|
#
|
||||||
# 4. Create any files/directories that you specified back in step #2.
|
# 4. Enable boot-time autostart with the following commands:
|
||||||
# e.g. '/etc/plexpy/plexpy.ini'
|
|
||||||
# '/home/sabnzbd/.plexpy'
|
|
||||||
#
|
|
||||||
# 5. Enable boot-time autostart with the following commands:
|
|
||||||
# systemctl daemon-reload
|
# systemctl daemon-reload
|
||||||
# systemctl enable plexpy.service
|
# systemctl enable plexpy.service
|
||||||
#
|
#
|
||||||
# 6. Start now with the following command:
|
# 5. Start now with the following command:
|
||||||
# systemctl start plexpy.service
|
# 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
|
# CONFIGURATION NOTES
|
||||||
#
|
#
|
||||||
# - The example settings in this file assume that:
|
# - The example settings in this file assume that you will run PlexPy as user: plexpy
|
||||||
# 1. You will run PlexPy as user/group: sabnzbd.sabnzbd
|
# - To create this user and give it ownership of the plexpy directory:
|
||||||
# 2. You will either have PlexPy installed as a subdirectory
|
# sudo adduser --system --no-create-home plexpy
|
||||||
# under '~sabnzbd', or that you will have a symlink under
|
# sudo chown plexpy:nogroup -R /opt/plexpy
|
||||||
# '~/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)
|
# - Option names (e.g. ExecStart=, Type=) appear to be case-sensitive)
|
||||||
#
|
#
|
@@ -407,7 +407,7 @@ General optional parameters:
|
|||||||
data = None
|
data = None
|
||||||
apikey = hashlib.sha224(str(random.getrandbits(256))).hexdigest()[0:32]
|
apikey = hashlib.sha224(str(random.getrandbits(256))).hexdigest()[0:32]
|
||||||
if plexpy.CONFIG.HTTP_USERNAME and plexpy.CONFIG.HTTP_PASSWORD:
|
if plexpy.CONFIG.HTTP_USERNAME and plexpy.CONFIG.HTTP_PASSWORD:
|
||||||
if username == plexpy.HTTP_USERNAME and password == plexpy.CONFIG.HTTP_PASSWORD:
|
if username == plexpy.CONFIG.HTTP_USERNAME and password == plexpy.CONFIG.HTTP_PASSWORD:
|
||||||
if plexpy.CONFIG.API_KEY:
|
if plexpy.CONFIG.API_KEY:
|
||||||
data = plexpy.CONFIG.API_KEY
|
data = plexpy.CONFIG.API_KEY
|
||||||
else:
|
else:
|
||||||
|
@@ -174,6 +174,7 @@ _CONFIG_DEFINITIONS = {
|
|||||||
'GIT_USER': (str, 'General', 'JonnyWong16'),
|
'GIT_USER': (str, 'General', 'JonnyWong16'),
|
||||||
'GRAPH_TYPE': (str, 'General', 'plays'),
|
'GRAPH_TYPE': (str, 'General', 'plays'),
|
||||||
'GRAPH_DAYS': (int, 'General', 30),
|
'GRAPH_DAYS': (int, 'General', 30),
|
||||||
|
'GRAPH_MONTHS': (int, 'General', 12),
|
||||||
'GRAPH_TAB': (str, 'General', 'tabs-1'),
|
'GRAPH_TAB': (str, 'General', 'tabs-1'),
|
||||||
'GROUP_HISTORY_TABLES': (int, 'General', 0),
|
'GROUP_HISTORY_TABLES': (int, 'General', 0),
|
||||||
'GROWL_ENABLED': (int, 'Growl', 0),
|
'GROWL_ENABLED': (int, 'Growl', 0),
|
||||||
@@ -565,6 +566,7 @@ _CONFIG_DEFINITIONS = {
|
|||||||
'UPDATE_LABELS': (int, 'General', 1),
|
'UPDATE_LABELS': (int, 'General', 1),
|
||||||
'VERIFY_SSL_CERT': (bool_int, 'Advanced', 1),
|
'VERIFY_SSL_CERT': (bool_int, 'Advanced', 1),
|
||||||
'VIDEO_LOGGING_ENABLE': (int, 'Monitoring', 1),
|
'VIDEO_LOGGING_ENABLE': (int, 'Monitoring', 1),
|
||||||
|
'WEEK_START_MONDAY': (int, 'General', 0),
|
||||||
'XBMC_ENABLED': (int, 'XBMC', 0),
|
'XBMC_ENABLED': (int, 'XBMC', 0),
|
||||||
'XBMC_HOST': (str, 'XBMC', ''),
|
'XBMC_HOST': (str, 'XBMC', ''),
|
||||||
'XBMC_PASSWORD': (str, 'XBMC', ''),
|
'XBMC_PASSWORD': (str, 'XBMC', ''),
|
||||||
|
@@ -169,8 +169,12 @@ class Graphs(object):
|
|||||||
logger.warn(u"PlexPy Graphs :: Unable to execute database query for get_total_plays_per_dayofweek: %s." % e)
|
logger.warn(u"PlexPy Graphs :: Unable to execute database query for get_total_plays_per_dayofweek: %s." % e)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
days_list = ['Sunday', 'Monday', 'Tuesday', 'Wednesday',
|
if plexpy.CONFIG.WEEK_START_MONDAY:
|
||||||
'Thursday', 'Friday', 'Saturday']
|
days_list = ['Monday', 'Tuesday', 'Wednesday',
|
||||||
|
'Thursday', 'Friday', 'Saturday', 'Sunday']
|
||||||
|
else:
|
||||||
|
days_list = ['Sunday', 'Monday', 'Tuesday', 'Wednesday',
|
||||||
|
'Thursday', 'Friday', 'Saturday']
|
||||||
|
|
||||||
categories = []
|
categories = []
|
||||||
series_1 = []
|
series_1 = []
|
||||||
@@ -291,9 +295,12 @@ class Graphs(object):
|
|||||||
'series': [series_1_output, series_2_output, series_3_output]}
|
'series': [series_1_output, series_2_output, series_3_output]}
|
||||||
return output
|
return output
|
||||||
|
|
||||||
def get_total_plays_per_month(self, y_axis='plays', user_id=None):
|
def get_total_plays_per_month(self, time_range='12', y_axis='plays', user_id=None):
|
||||||
import time as time
|
import time as time
|
||||||
|
|
||||||
|
if not time_range.isdigit():
|
||||||
|
time_range = '12'
|
||||||
|
|
||||||
monitor_db = database.MonitorDatabase()
|
monitor_db = database.MonitorDatabase()
|
||||||
|
|
||||||
user_cond = ''
|
user_cond = ''
|
||||||
@@ -309,9 +316,9 @@ class Graphs(object):
|
|||||||
'SUM(CASE WHEN media_type = "movie" THEN 1 ELSE 0 END) AS movie_count, ' \
|
'SUM(CASE WHEN media_type = "movie" THEN 1 ELSE 0 END) AS movie_count, ' \
|
||||||
'SUM(CASE WHEN media_type = "track" THEN 1 ELSE 0 END) AS music_count ' \
|
'SUM(CASE WHEN media_type = "track" THEN 1 ELSE 0 END) AS music_count ' \
|
||||||
'FROM session_history ' \
|
'FROM session_history ' \
|
||||||
'WHERE datetime(started, "unixepoch", "localtime") >= datetime("now", "-12 months", "localtime") %s' \
|
'WHERE datetime(started, "unixepoch", "localtime") >= datetime("now", "-%s months", "localtime") %s' \
|
||||||
'GROUP BY strftime("%%Y-%%m", datetime(started, "unixepoch", "localtime")) ' \
|
'GROUP BY strftime("%%Y-%%m", datetime(started, "unixepoch", "localtime")) ' \
|
||||||
'ORDER BY datestring DESC LIMIT 12' % (user_cond)
|
'ORDER BY datestring DESC LIMIT %s' % (time_range, user_cond, time_range)
|
||||||
|
|
||||||
result = monitor_db.select(query)
|
result = monitor_db.select(query)
|
||||||
else:
|
else:
|
||||||
@@ -323,9 +330,9 @@ class Graphs(object):
|
|||||||
'SUM(CASE WHEN media_type = "track" AND stopped > 0 THEN (stopped - started) ' \
|
'SUM(CASE WHEN media_type = "track" AND stopped > 0 THEN (stopped - started) ' \
|
||||||
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS music_count ' \
|
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS music_count ' \
|
||||||
'FROM session_history ' \
|
'FROM session_history ' \
|
||||||
'WHERE datetime(started, "unixepoch", "localtime") >= datetime("now", "-12 months", "localtime") %s' \
|
'WHERE datetime(started, "unixepoch", "localtime") >= datetime("now", "-%s months", "localtime") %s' \
|
||||||
'GROUP BY strftime("%%Y-%%m", datetime(started, "unixepoch", "localtime")) ' \
|
'GROUP BY strftime("%%Y-%%m", datetime(started, "unixepoch", "localtime")) ' \
|
||||||
'ORDER BY datestring DESC LIMIT 12' % (user_cond)
|
'ORDER BY datestring DESC LIMIT %s' % (time_range, user_cond, time_range)
|
||||||
|
|
||||||
result = monitor_db.select(query)
|
result = monitor_db.select(query)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -334,10 +341,9 @@ class Graphs(object):
|
|||||||
|
|
||||||
# create our date range as some months may not have any data
|
# create our date range as some months may not have any data
|
||||||
# but we still want to display them
|
# but we still want to display them
|
||||||
x = 12
|
|
||||||
base = time.localtime()
|
base = time.localtime()
|
||||||
month_range = [time.localtime(
|
month_range = [time.localtime(
|
||||||
time.mktime((base.tm_year, base.tm_mon - n, 1, 0, 0, 0, 0, 0, 0))) for n in range(x)]
|
time.mktime((base.tm_year, base.tm_mon - n, 1, 0, 0, 0, 0, 0, 0))) for n in range(int(time_range))]
|
||||||
|
|
||||||
categories = []
|
categories = []
|
||||||
series_1 = []
|
series_1 = []
|
||||||
|
@@ -666,7 +666,7 @@ def build_notify_text(session=None, timeline=None, notify_action=None, agent_id=
|
|||||||
remaining_duration = duration - view_offset
|
remaining_duration = duration - view_offset
|
||||||
|
|
||||||
# Build Plex URL
|
# Build Plex URL
|
||||||
metadata['plex_url'] = 'https://app.plex.tv/web/app#!/server/{0}/details/%2Flibrary%2Fmetadata%2F{1}'.format(
|
metadata['plex_url'] = 'https://app.plex.tv/web/app#!/server/{0}/details?key=%2Flibrary%2Fmetadata%2F{1}'.format(
|
||||||
plexpy.CONFIG.PMS_IDENTIFIER, str(rating_key))
|
plexpy.CONFIG.PMS_IDENTIFIER, str(rating_key))
|
||||||
|
|
||||||
# Get media IDs from guid and build URLs
|
# Get media IDs from guid and build URLs
|
||||||
|
@@ -1186,8 +1186,8 @@ class PmsConnect(object):
|
|||||||
transcode_audio_codec = helpers.get_xml_attr(transcode_session, 'audioCodec')
|
transcode_audio_codec = helpers.get_xml_attr(transcode_session, 'audioCodec')
|
||||||
video_decision = helpers.get_xml_attr(transcode_session, 'videoDecision')
|
video_decision = helpers.get_xml_attr(transcode_session, 'videoDecision')
|
||||||
transcode_video_codec = helpers.get_xml_attr(transcode_session, 'videoCodec')
|
transcode_video_codec = helpers.get_xml_attr(transcode_session, 'videoCodec')
|
||||||
transcode_width = helpers.get_xml_attr(transcode_session, 'width')
|
transcode_width = helpers.get_xml_attr(transcode_session, 'width') or width
|
||||||
transcode_height = helpers.get_xml_attr(transcode_session, 'height')
|
transcode_height = helpers.get_xml_attr(transcode_session, 'height') or height
|
||||||
transcode_container = helpers.get_xml_attr(transcode_session, 'container')
|
transcode_container = helpers.get_xml_attr(transcode_session, 'container')
|
||||||
transcode_protocol = helpers.get_xml_attr(transcode_session, 'protocol')
|
transcode_protocol = helpers.get_xml_attr(transcode_session, 'protocol')
|
||||||
else:
|
else:
|
||||||
@@ -1443,8 +1443,8 @@ class PmsConnect(object):
|
|||||||
transcode_speed = helpers.get_xml_attr(transcode_session, 'speed')
|
transcode_speed = helpers.get_xml_attr(transcode_session, 'speed')
|
||||||
video_decision = helpers.get_xml_attr(transcode_session, 'videoDecision')
|
video_decision = helpers.get_xml_attr(transcode_session, 'videoDecision')
|
||||||
transcode_video_codec = helpers.get_xml_attr(transcode_session, 'videoCodec')
|
transcode_video_codec = helpers.get_xml_attr(transcode_session, 'videoCodec')
|
||||||
transcode_width = helpers.get_xml_attr(transcode_session, 'width')
|
transcode_width = helpers.get_xml_attr(transcode_session, 'width') or width
|
||||||
transcode_height = helpers.get_xml_attr(transcode_session, 'height')
|
transcode_height = helpers.get_xml_attr(transcode_session, 'height') or height
|
||||||
transcode_container = helpers.get_xml_attr(transcode_session, 'container')
|
transcode_container = helpers.get_xml_attr(transcode_session, 'container')
|
||||||
transcode_protocol = helpers.get_xml_attr(transcode_session, 'protocol')
|
transcode_protocol = helpers.get_xml_attr(transcode_session, 'protocol')
|
||||||
else:
|
else:
|
||||||
|
@@ -1,2 +1,2 @@
|
|||||||
PLEXPY_VERSION = "master"
|
PLEXPY_VERSION = "master"
|
||||||
PLEXPY_RELEASE_VERSION = "1.4.15"
|
PLEXPY_RELEASE_VERSION = "1.4.19"
|
||||||
|
@@ -142,11 +142,12 @@ def process(opcode, data):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
info = json.loads(data)
|
info = json.loads(data)
|
||||||
except Exception as ex:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy WebSocket :: Error decoding message from websocket: %s" % ex)
|
logger.warn(u"PlexPy WebSocket :: Error decoding message from websocket: %s" % e)
|
||||||
logger.debug(data)
|
logger.debug(data)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
info = info.get('NotificationContainer', info)
|
||||||
type = info.get('type')
|
type = info.get('type')
|
||||||
|
|
||||||
if not type:
|
if not type:
|
||||||
@@ -154,9 +155,9 @@ def process(opcode, data):
|
|||||||
|
|
||||||
if type == 'playing':
|
if type == 'playing':
|
||||||
# logger.debug('%s.playing %s' % (name, info))
|
# logger.debug('%s.playing %s' % (name, info))
|
||||||
try:
|
time_line = info.get('PlaySessionStateNotification', info.get('_children'))
|
||||||
time_line = info.get('_children')
|
|
||||||
except:
|
if not time_line:
|
||||||
logger.debug(u"PlexPy WebSocket :: Session found but unable to get timeline data.")
|
logger.debug(u"PlexPy WebSocket :: Session found but unable to get timeline data.")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@@ -1747,6 +1747,7 @@ class WebInterface(object):
|
|||||||
config = {
|
config = {
|
||||||
"graph_type": plexpy.CONFIG.GRAPH_TYPE,
|
"graph_type": plexpy.CONFIG.GRAPH_TYPE,
|
||||||
"graph_days": plexpy.CONFIG.GRAPH_DAYS,
|
"graph_days": plexpy.CONFIG.GRAPH_DAYS,
|
||||||
|
"graph_months": plexpy.CONFIG.GRAPH_MONTHS,
|
||||||
"graph_tab": plexpy.CONFIG.GRAPH_TAB,
|
"graph_tab": plexpy.CONFIG.GRAPH_TAB,
|
||||||
"music_logging_enable": plexpy.CONFIG.MUSIC_LOGGING_ENABLE
|
"music_logging_enable": plexpy.CONFIG.MUSIC_LOGGING_ENABLE
|
||||||
}
|
}
|
||||||
@@ -1755,13 +1756,16 @@ class WebInterface(object):
|
|||||||
|
|
||||||
@cherrypy.expose
|
@cherrypy.expose
|
||||||
@requireAuth(member_of("admin"))
|
@requireAuth(member_of("admin"))
|
||||||
def set_graph_config(self, graph_type=None, graph_days=None, graph_tab=None, **kwargs):
|
def set_graph_config(self, graph_type=None, graph_days=None, graph_months=None, graph_tab=None, **kwargs):
|
||||||
if graph_type:
|
if graph_type:
|
||||||
plexpy.CONFIG.__setattr__('GRAPH_TYPE', graph_type)
|
plexpy.CONFIG.__setattr__('GRAPH_TYPE', graph_type)
|
||||||
plexpy.CONFIG.write()
|
plexpy.CONFIG.write()
|
||||||
if graph_days:
|
if graph_days:
|
||||||
plexpy.CONFIG.__setattr__('GRAPH_DAYS', graph_days)
|
plexpy.CONFIG.__setattr__('GRAPH_DAYS', graph_days)
|
||||||
plexpy.CONFIG.write()
|
plexpy.CONFIG.write()
|
||||||
|
if graph_months:
|
||||||
|
plexpy.CONFIG.__setattr__('GRAPH_MONTHS', graph_months)
|
||||||
|
plexpy.CONFIG.write()
|
||||||
if graph_tab:
|
if graph_tab:
|
||||||
plexpy.CONFIG.__setattr__('GRAPH_TAB', graph_tab)
|
plexpy.CONFIG.__setattr__('GRAPH_TAB', graph_tab)
|
||||||
plexpy.CONFIG.write()
|
plexpy.CONFIG.write()
|
||||||
@@ -1908,7 +1912,7 @@ class WebInterface(object):
|
|||||||
@cherrypy.tools.json_out()
|
@cherrypy.tools.json_out()
|
||||||
@requireAuth()
|
@requireAuth()
|
||||||
@addtoapi()
|
@addtoapi()
|
||||||
def get_plays_per_month(self, y_axis='plays', user_id=None, **kwargs):
|
def get_plays_per_month(self, time_range='12', y_axis='plays', user_id=None, **kwargs):
|
||||||
""" Get graph data by month.
|
""" Get graph data by month.
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -1916,7 +1920,7 @@ class WebInterface(object):
|
|||||||
None
|
None
|
||||||
|
|
||||||
Optional parameters:
|
Optional parameters:
|
||||||
time_range (str): The number of days of data to return
|
time_range (str): The number of months of data to return
|
||||||
y_axis (str): "plays" or "duration"
|
y_axis (str): "plays" or "duration"
|
||||||
user_id (str): The user id to filter the data
|
user_id (str): The user id to filter the data
|
||||||
|
|
||||||
@@ -1933,7 +1937,7 @@ class WebInterface(object):
|
|||||||
```
|
```
|
||||||
"""
|
"""
|
||||||
graph = graphs.Graphs()
|
graph = graphs.Graphs()
|
||||||
result = graph.get_total_plays_per_month(y_axis=y_axis, user_id=user_id)
|
result = graph.get_total_plays_per_month(time_range=time_range, y_axis=y_axis, user_id=user_id)
|
||||||
|
|
||||||
if result:
|
if result:
|
||||||
return result
|
return result
|
||||||
@@ -2618,7 +2622,8 @@ class WebInterface(object):
|
|||||||
"git_token": plexpy.CONFIG.GIT_TOKEN,
|
"git_token": plexpy.CONFIG.GIT_TOKEN,
|
||||||
"imgur_client_id": plexpy.CONFIG.IMGUR_CLIENT_ID,
|
"imgur_client_id": plexpy.CONFIG.IMGUR_CLIENT_ID,
|
||||||
"cache_images": checked(plexpy.CONFIG.CACHE_IMAGES),
|
"cache_images": checked(plexpy.CONFIG.CACHE_IMAGES),
|
||||||
"pms_version": plexpy.CONFIG.PMS_VERSION
|
"pms_version": plexpy.CONFIG.PMS_VERSION,
|
||||||
|
"week_start_monday": checked(plexpy.CONFIG.WEEK_START_MONDAY)
|
||||||
}
|
}
|
||||||
|
|
||||||
return serve_template(templatename="settings.html", title="Settings", config=config, kwargs=kwargs)
|
return serve_template(templatename="settings.html", title="Settings", config=config, kwargs=kwargs)
|
||||||
@@ -2632,7 +2637,7 @@ class WebInterface(object):
|
|||||||
checked_configs = [
|
checked_configs = [
|
||||||
"launch_browser", "enable_https", "https_create_cert", "api_enabled", "freeze_db", "check_github",
|
"launch_browser", "enable_https", "https_create_cert", "api_enabled", "freeze_db", "check_github",
|
||||||
"grouping_global_history", "grouping_user_history", "grouping_charts", "group_history_tables",
|
"grouping_global_history", "grouping_user_history", "grouping_charts", "group_history_tables",
|
||||||
"pms_use_bif", "pms_ssl", "pms_is_remote", "home_stats_type",
|
"pms_use_bif", "pms_ssl", "pms_is_remote", "home_stats_type", "week_start_monday",
|
||||||
"movie_notify_enable", "tv_notify_enable", "music_notify_enable", "monitoring_use_websocket",
|
"movie_notify_enable", "tv_notify_enable", "music_notify_enable", "monitoring_use_websocket",
|
||||||
"refresh_libraries_on_startup", "refresh_users_on_startup",
|
"refresh_libraries_on_startup", "refresh_users_on_startup",
|
||||||
"ip_logging_enable", "movie_logging_enable", "tv_logging_enable", "music_logging_enable",
|
"ip_logging_enable", "movie_logging_enable", "tv_logging_enable", "music_logging_enable",
|
||||||
@@ -4307,13 +4312,18 @@ class WebInterface(object):
|
|||||||
'Come with me if you want to live.',
|
'Come with me if you want to live.',
|
||||||
'Who is your daddy and what does he do?',
|
'Who is your daddy and what does he do?',
|
||||||
'Oh, cookies! I can\'t wait to toss them.',
|
'Oh, cookies! I can\'t wait to toss them.',
|
||||||
'Can you hurry up. My horse is getting tired.',
|
'Make it quick because my horse is getting tired.',
|
||||||
'What killed the dinosaurs? The Ice Age!',
|
'What killed the dinosaurs? The Ice Age!',
|
||||||
'That\'s for sleeping with my wife!',
|
'That\'s for sleeping with my wife!',
|
||||||
'Remember when I said I\'d kill you last... I lied!',
|
'Remember when I said I\'d kill you last... I lied!',
|
||||||
'You want to be a farmer? Here\'s a couple of acres',
|
'You want to be a farmer? Here\'s a couple of acres',
|
||||||
'Now, this is the plan. Get your ass to Mars.',
|
'Now, this is the plan. Get your ass to Mars.',
|
||||||
'I just had a terrible thought... What if this is a dream?'
|
'I just had a terrible thought... What if this is a dream?',
|
||||||
|
'Well, listen to this one: Rubber baby buggy bumpers!',
|
||||||
|
'Take your toy back to the carpet!',
|
||||||
|
'My name is John Kimble... And I love my car.',
|
||||||
|
'I eat Green Berets for breakfast.',
|
||||||
|
'Put that cookie down! NOW!'
|
||||||
]
|
]
|
||||||
|
|
||||||
random_number = randint(0, len(quote_list) - 1)
|
random_number = randint(0, len(quote_list) - 1)
|
||||||
|