Manual merge of v1.4.17 into v2

This commit is contained in:
JonnyWong16 2017-03-04 16:02:37 -08:00
commit 9318c4742d
18 changed files with 136 additions and 216 deletions

View file

@ -1,5 +1,15 @@
# Changelog # Changelog
## 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) ## v1.4.16 (2016-11-25)
* Fix: Websocket for new json response on PMS 1.3.0. * Fix: Websocket for new json response on PMS 1.3.0.

View file

@ -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">
@ -224,7 +224,7 @@
<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=_s-xclick&hosted_button_id=DG783BMSCU3V4')}" 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>

View file

@ -2797,6 +2797,14 @@ pre::-webkit-scrollbar-thumb {
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;

View file

@ -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>
@ -323,10 +328,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({
@ -358,6 +365,7 @@
function loadGraphsTab1(time_range, yaxis) { function loadGraphsTab1(time_range, yaxis) {
$('#days-selection').show(); $('#days-selection').show();
$('#months-selection').hide();
setGraphFormat(yaxis); setGraphFormat(yaxis);
@ -448,6 +456,7 @@
function loadGraphsTab2(time_range, yaxis) { function loadGraphsTab2(time_range, yaxis) {
$('#days-selection').show(); $('#days-selection').show();
$('#months-selection').hide();
setGraphFormat(yaxis); setGraphFormat(yaxis);
@ -531,15 +540,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); }
@ -553,15 +563,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('#','') },
@ -573,7 +583,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('#','') },
@ -585,7 +595,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('#','') },
@ -595,17 +605,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
}); });
}); });
@ -613,17 +641,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},

Binary file not shown.

Before

Width:  |  Height:  |  Size: 137 KiB

View file

@ -116,9 +116,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?key=%2Flibrary%2Fmetadata%2F${data['parent_rating_key']}" target="_blank" title="View on 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?key=%2Flibrary%2Fmetadata%2F${data['rating_key']}" target="_blank" title="View on 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);">

View file

@ -100,6 +100,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

View file

@ -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"}

View file

@ -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

View file

@ -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"}

View file

@ -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"}

View file

@ -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

View file

@ -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"/>

View file

@ -13,32 +13,20 @@
# 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)
# #
# - Adjust ExecStart= to point to: # - Adjust ExecStart= to point to:
@ -63,4 +51,4 @@ User=plexpy
Group=nogroup Group=nogroup
[Install] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target

View file

@ -175,6 +175,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),
@ -578,6 +579,7 @@ _CONFIG_DEFINITIONS = {
'VIDEO_LOGGING_ENABLE': (int, 'Monitoring', 1), 'VIDEO_LOGGING_ENABLE': (int, 'Monitoring', 1),
'WEBSOCKET_CONNECTION_ATTEMPTS': (int, 'Advanced', 5), 'WEBSOCKET_CONNECTION_ATTEMPTS': (int, 'Advanced', 5),
'WEBSOCKET_CONNECTION_TIMEOUT': (int, 'Advanced', 5), 'WEBSOCKET_CONNECTION_TIMEOUT': (int, 'Advanced', 5),
'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', ''),

View file

@ -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,8 +295,11 @@ 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()
@ -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 = []

View file

@ -1,2 +1,2 @@
PLEXPY_BRANCH = "master" PLEXPY_BRANCH = "master"
PLEXPY_RELEASE_VERSION = "1.4.16" PLEXPY_RELEASE_VERSION = "1.4.17"

View file

@ -1773,6 +1773,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
} }
@ -1781,13 +1782,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()
@ -1934,7 +1938,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.
``` ```
@ -1942,7 +1946,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
@ -1959,7 +1963,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
@ -2574,6 +2578,7 @@ class WebInterface(object):
"pms_uuid": plexpy.CONFIG.PMS_UUID, "pms_uuid": plexpy.CONFIG.PMS_UUID,
"date_format": plexpy.CONFIG.DATE_FORMAT, "date_format": plexpy.CONFIG.DATE_FORMAT,
"time_format": plexpy.CONFIG.TIME_FORMAT, "time_format": plexpy.CONFIG.TIME_FORMAT,
"week_start_monday": checked(plexpy.CONFIG.WEEK_START_MONDAY),
"get_file_sizes": checked(plexpy.CONFIG.GET_FILE_SIZES), "get_file_sizes": checked(plexpy.CONFIG.GET_FILE_SIZES),
"grouping_global_history": checked(plexpy.CONFIG.GROUPING_GLOBAL_HISTORY), "grouping_global_history": checked(plexpy.CONFIG.GROUPING_GLOBAL_HISTORY),
"grouping_user_history": checked(plexpy.CONFIG.GROUPING_USER_HISTORY), "grouping_user_history": checked(plexpy.CONFIG.GROUPING_USER_HISTORY),
@ -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", "movie_notify_enable", "tv_notify_enable", "music_notify_enable",
"refresh_libraries_on_startup", "refresh_users_on_startup", "refresh_libraries_on_startup", "refresh_users_on_startup",
"movie_logging_enable", "tv_logging_enable", "music_logging_enable", "movie_logging_enable", "tv_logging_enable", "music_logging_enable",