mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-07-30 03:28:31 -07:00
Merge branch 'dev'
This commit is contained in:
commit
08537c1d69
50 changed files with 1904 additions and 784 deletions
98
CHANGELOG.md
98
CHANGELOG.md
|
@ -1,9 +1,39 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## v1.3.10 (2016-03-12)
|
||||||
|
|
||||||
|
* Fix: Actually allow HTML tags for Pushover.
|
||||||
|
* Fix: PlexPy not restarting on Windows if there is a space in the folder path.
|
||||||
|
* Fix: Reconnect websocket when changing PMS SSL setting.
|
||||||
|
* Fix: Datatables not loading when view_offset or duration is blank.
|
||||||
|
* Fix: Bug when checking the PMS version in the settings.
|
||||||
|
* Fix: Auto-refreshing of log tables.
|
||||||
|
* Fix: Logging of IPv6 addresses. (PMS version >0.9.14 only.)
|
||||||
|
* Fix: Hide days selection from the Play Totals graph page.
|
||||||
|
* Fix: PlexPy overwriting user's own SSL certificate/key.
|
||||||
|
* Fix: Multiple watched notifications when using websocket.
|
||||||
|
* Fix: Some missing python library imports.
|
||||||
|
* Fix: Some typos in settings and PlexWatch importer.
|
||||||
|
* New: Ability to get notified of PMS updates.
|
||||||
|
* New: Ability to disable the link to Plex Web with Facebook notifications and use IMDB, TVDB, TMDb, or Last.fm instead.
|
||||||
|
* New: Ability to reset Imgur poster url from the info page if the poster is changed.
|
||||||
|
* New: Tooltips on the current activity progress bars.
|
||||||
|
* New: Side scrolling of Recently Added/Recently Played items.
|
||||||
|
* New: Document all date/time format options.
|
||||||
|
* New: Button to clear notification logs.
|
||||||
|
* New: Customizable backup, cache, and log directories.
|
||||||
|
* Change: Retry writing sessions to history if it fails, so sessions don't get lost. (Activity pinger only, not availble for websocket.)
|
||||||
|
* Change: Save any unknown sessions to the "Local" user.
|
||||||
|
* Change: History table modal is filtered depending on which graph series is clicked.
|
||||||
|
* Change: Revert back to saving the state of datatables (search, sorting, entries per page, etc.).
|
||||||
|
* Change: Newlines are not longer stripped from notification text which allows for finer control of how notifications look.
|
||||||
|
* Change: Updated FreeNAS/FreeBSD init scripts. (Must have updated jails.) (Thanks @chiviak)
|
||||||
|
|
||||||
|
|
||||||
## v1.3.9 (2016-02-21)
|
## v1.3.9 (2016-02-21)
|
||||||
|
|
||||||
* Fix: Recently added notification not sent to all notification agents.
|
* Fix: Recently added notification not sent to all notification agents.
|
||||||
* Add: Pushover HTML support. (Thanks @elseym)
|
* New: Pushover HTML support. (Thanks @elseym)
|
||||||
|
|
||||||
|
|
||||||
## v1.3.8 (2016-02-21)
|
## v1.3.8 (2016-02-21)
|
||||||
|
@ -12,8 +42,8 @@
|
||||||
* Fix: Remove media tags from script arguments for server notifications.
|
* Fix: Remove media tags from script arguments for server notifications.
|
||||||
* Fix: Encode poster titles to UTF-8 for Imgur upload.
|
* Fix: Encode poster titles to UTF-8 for Imgur upload.
|
||||||
* Fix: Allow notifications to send without poster if Imgur upload fails.
|
* Fix: Allow notifications to send without poster if Imgur upload fails.
|
||||||
* Add: Notification Logs table in the Logs tab.
|
* New: Notification Logs table in the Logs tab.
|
||||||
* Add: Toggle in settings to enable posters in notifications. (Disabled by default.)
|
* New: Toggle in settings to enable posters in notifications. (Disabled by default.)
|
||||||
* Change: Save Imgur poster URL to database so upload is not needed every time.
|
* Change: Save Imgur poster URL to database so upload is not needed every time.
|
||||||
* Change: Notify log in database to log each event as a separate entry.
|
* Change: Notify log in database to log each event as a separate entry.
|
||||||
* Change: Monitor remote access is unchecked if remote access is disabled on server.
|
* Change: Monitor remote access is unchecked if remote access is disabled on server.
|
||||||
|
@ -26,18 +56,18 @@
|
||||||
* Fix: Video metadata flags showing up for track info.
|
* Fix: Video metadata flags showing up for track info.
|
||||||
* Fix: Custom library icons not applied to Library Statistics.
|
* Fix: Custom library icons not applied to Library Statistics.
|
||||||
* Fix: Typos in the Web UI.
|
* Fix: Typos in the Web UI.
|
||||||
* Add: ETA to Current Activity overlay.
|
* New: ETA to Current Activity overlay.
|
||||||
* Add: Total duration to Libraries and Users tables.
|
* New: Total duration to Libraries and Users tables.
|
||||||
* Add: {machine_id} to notification options.
|
* New: {machine_id} to notification options.
|
||||||
* Add: IMDB, TVDB, TMDb, Last.fm, and Trackt IDs/URLs to notification options.
|
* New: IMDB, TVDB, TMDb, Last.fm, and Trackt IDs/URLs to notification options.
|
||||||
* Add: {poster_url} to notification options using Imgur.
|
* New: {poster_url} to notification options using Imgur.
|
||||||
* Add: Poster and link for Facebook notifications.
|
* New: Poster and link for Facebook notifications.
|
||||||
* Add: Log javascript errors from the Web UI.
|
* New: Log javascript errors from the Web UI.
|
||||||
* Add: Configuration and Scheduler info to the settings page.
|
* New: Configuration and Scheduler info to the settings page.
|
||||||
* Add: Schedule background task to backup the PlexPy database.
|
* New: Schedule background task to backup the PlexPy database.
|
||||||
* Add: URL anonymizer for external links.
|
* New: URL anonymizer for external links.
|
||||||
* Add: Plex Media Scanner log file to Log viewer.
|
* New: Plex Media Scanner log file to Log viewer.
|
||||||
* Add: API v2 (sill very experimental). (Thanks @Hellowlol)
|
* New: API v2 (sill very experimental). (Thanks @Hellowlol)
|
||||||
* Change: Allow secure websocket connections.
|
* Change: Allow secure websocket connections.
|
||||||
* Change: History grouping now accounts for the view offset.
|
* Change: History grouping now accounts for the view offset.
|
||||||
* Change: Subject line can be toggled off for Facebook, Slack, Telegram, and Twitter.
|
* Change: Subject line can be toggled off for Facebook, Slack, Telegram, and Twitter.
|
||||||
|
@ -60,9 +90,9 @@
|
||||||
* Fix: Unable to expand media info table when missing "Added At" date.
|
* Fix: Unable to expand media info table when missing "Added At" date.
|
||||||
* Fix: Server verification for unpublished servers.
|
* Fix: Server verification for unpublished servers.
|
||||||
* Fix: Updating PMS identifier for server change.
|
* Fix: Updating PMS identifier for server change.
|
||||||
* Add: {stream_time}, {remaining_time}, and {progress_time} to notification options.
|
* New: {stream_time}, {remaining_time}, and {progress_time} to notification options.
|
||||||
* Add: Powershell script support. (Thanks @Hellowlol)
|
* New: Powershell script support. (Thanks @Hellowlol)
|
||||||
* Add: Method to delete duplicate libraries.
|
* New: Method to delete duplicate libraries.
|
||||||
* Change: Daemonize before running start up tasks.
|
* Change: Daemonize before running start up tasks.
|
||||||
|
|
||||||
|
|
||||||
|
@ -74,7 +104,7 @@
|
||||||
* Fix: Libraries and Users lists not refreshing.
|
* Fix: Libraries and Users lists not refreshing.
|
||||||
* Fix: Server verification in settings.
|
* Fix: Server verification in settings.
|
||||||
* Fix: Empty libraries not added to database.
|
* Fix: Empty libraries not added to database.
|
||||||
* Add: Unique identifiers to notification options.
|
* New: Unique identifiers to notification options.
|
||||||
* Remove: Requirement of media type toggles for recently added notifications.
|
* Remove: Requirement of media type toggles for recently added notifications.
|
||||||
* Remove: Built in Twitter key and secret.
|
* Remove: Built in Twitter key and secret.
|
||||||
* Change: Unnecessary quoting of script arguments.
|
* Change: Unnecessary quoting of script arguments.
|
||||||
|
@ -107,21 +137,21 @@
|
||||||
|
|
||||||
## v1.3.0 (2016-01-23)
|
## v1.3.0 (2016-01-23)
|
||||||
|
|
||||||
* Add: Brand new Libraries section.
|
* New: Brand new Libraries section.
|
||||||
* Add: Lots of new library statistics.
|
* New: Lots of new library statistics.
|
||||||
* Add: Media info table for libraries.
|
* New: Media info table for libraries.
|
||||||
* Add: Web app for Android and iOS. (Thanks @zobe123)
|
* New: Web app for Android and iOS. (Thanks @zobe123)
|
||||||
* Add: Slack notification agent. (Thanks @richipargo)
|
* New: Slack notification agent. (Thanks @richipargo)
|
||||||
* Add: Facebook notification agent.
|
* New: Facebook notification agent.
|
||||||
* Add: Custom script notification agent. (Thanks @Hellowlol)
|
* New: Custom script notification agent. (Thanks @Hellowlol)
|
||||||
* Add: Custom "From Name" to email notification agent.
|
* New: Custom "From Name" to email notification agent.
|
||||||
* Add: Ability to test notifications / send custom one-off notifications.
|
* New: Ability to test notifications / send custom one-off notifications.
|
||||||
* Add: 'datestamp' and 'timestamp' notification options.
|
* New: 'datestamp' and 'timestamp' notification options.
|
||||||
* Add: More concurrent stream statistics.
|
* New: More concurrent stream statistics.
|
||||||
* Add: Media info flags on the info pages.
|
* New: Media info flags on the info pages.
|
||||||
* Add: Ability to fix broken metadata if the item has been moved in Plex.
|
* New: Ability to fix broken metadata if the item has been moved in Plex.
|
||||||
* Add: Ability to rearrange the homepage statistics cards.
|
* New: Ability to rearrange the homepage statistics cards.
|
||||||
* Add: CentOS startup script (Thanks @PHoSawyer)
|
* New: CentOS startup script (Thanks @PHoSawyer)
|
||||||
* Fix: Server name blank after first run wizard.
|
* Fix: Server name blank after first run wizard.
|
||||||
* Fix: Incorrect duration for grouped home stats.
|
* Fix: Incorrect duration for grouped home stats.
|
||||||
* Fix: Allow SSL when verifying server in settings.
|
* Fix: Allow SSL when verifying server in settings.
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<%
|
<%
|
||||||
import plexpy
|
import plexpy
|
||||||
from plexpy import version
|
from plexpy import version
|
||||||
|
from plexpy.helpers import anon_url
|
||||||
%>
|
%>
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
|
|
||||||
|
@ -136,15 +137,15 @@ from plexpy import version
|
||||||
<div id="ajaxMsg" class="ajaxMsg"></div>
|
<div id="ajaxMsg" class="ajaxMsg"></div>
|
||||||
% if plexpy.CONFIG.CHECK_GITHUB and not plexpy.CURRENT_VERSION:
|
% if plexpy.CONFIG.CHECK_GITHUB and not plexpy.CURRENT_VERSION:
|
||||||
<div id="updatebar" style="display: none;">
|
<div id="updatebar" style="display: none;">
|
||||||
You're running an unknown version of PlexPy. <a href="update">Update</a> or
|
You're running an unknown version of PlexPy.<br />
|
||||||
<a href="#" id="updateDismiss">Close</a>
|
<a href="update">Update</a> or <a href="#" id="updateDismiss">Close</a>
|
||||||
</div>
|
</div>
|
||||||
% elif plexpy.CONFIG.CHECK_GITHUB and plexpy.CURRENT_VERSION != plexpy.LATEST_VERSION and plexpy.COMMITS_BEHIND > 0 and plexpy.INSTALL_TYPE != 'win':
|
% elif plexpy.CONFIG.CHECK_GITHUB and plexpy.CURRENT_VERSION != plexpy.LATEST_VERSION and plexpy.COMMITS_BEHIND > 0 and plexpy.INSTALL_TYPE != 'win':
|
||||||
<div id="updatebar" style="display: none;">
|
<div id="updatebar" style="display: none;">
|
||||||
A <a
|
A <a href="${anon_url('https://github.com/%s/plexpy/compare/%s...%s' % (plexpy.CONFIG.GIT_USER, plexpy.CURRENT_VERSION, plexpy.LATEST_VERSION))}" target="_blank">
|
||||||
href="https://github.com/${plexpy.CONFIG.GIT_USER}/plexpy/compare/${plexpy.CURRENT_VERSION}...${plexpy.LATEST_VERSION}" target="_blank">
|
newer version</a> is available.<br />
|
||||||
newer version</a> is available. You're ${plexpy.COMMITS_BEHIND} commits behind. <a href="update">Update</a> or
|
You're ${plexpy.COMMITS_BEHIND} commits behind.<br />
|
||||||
<a href="#" id="updateDismiss">Close</a>
|
<a href="update">Update</a> or <a href="#" id="updateDismiss">Close</a>
|
||||||
</div>
|
</div>
|
||||||
% endif
|
% endif
|
||||||
<nav class="navbar navbar-fixed-top">
|
<nav class="navbar navbar-fixed-top">
|
||||||
|
|
|
@ -882,10 +882,11 @@ a .dashboard-activity-metadata-user-thumb:hover {
|
||||||
}
|
}
|
||||||
.dashboard-recent-media-row {
|
.dashboard-recent-media-row {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin:0 auto;
|
margin: 0 auto;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 0;
|
z-index: 0;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
.dashboard-recent-media {
|
.dashboard-recent-media {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@ -2407,6 +2408,9 @@ a .home-platforms-instance-list-oval:hover,
|
||||||
padding: 0;
|
padding: 0;
|
||||||
border: 0;
|
border: 0;
|
||||||
}
|
}
|
||||||
|
.history-thumbnail-popover.popover.left {
|
||||||
|
margin-left: -15px;
|
||||||
|
}
|
||||||
.history-thumbnail-popover.popover.right {
|
.history-thumbnail-popover.popover.right {
|
||||||
margin-left: 15px;
|
margin-left: 15px;
|
||||||
}
|
}
|
||||||
|
@ -2655,6 +2659,7 @@ table[id^='media_info_child'] table[id^='media_info_child'] thead th {
|
||||||
margin: 5px 0 0 0.5em;
|
margin: 5px 0 0 0.5em;
|
||||||
}
|
}
|
||||||
.notification-params {
|
.notification-params {
|
||||||
|
width: 100%;
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
background-color: #282828;
|
background-color: #282828;
|
||||||
}
|
}
|
||||||
|
@ -2669,6 +2674,14 @@ table[id^='media_info_child'] table[id^='media_info_child'] thead th {
|
||||||
padding-left: 10px;
|
padding-left: 10px;
|
||||||
width: 200px;
|
width: 200px;
|
||||||
}
|
}
|
||||||
|
.notification-params.time-options td:first-child {
|
||||||
|
padding-left: 10px;
|
||||||
|
width: 125px;
|
||||||
|
}
|
||||||
|
.notification-params.time-options td:nth-child(2) {
|
||||||
|
padding-left: 10px;
|
||||||
|
width: 275px;
|
||||||
|
}
|
||||||
.notification-params td:not(:first-child) {
|
.notification-params td:not(:first-child) {
|
||||||
padding-right: 10px;
|
padding-right: 10px;
|
||||||
}
|
}
|
||||||
|
@ -2759,3 +2772,21 @@ a.no-highlight:hover {
|
||||||
.save-button {
|
.save-button {
|
||||||
margin-top: 15px;
|
margin-top: 15px;
|
||||||
}
|
}
|
||||||
|
.nav-dashboard > li {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
.btn-gray.disabled,
|
||||||
|
.btn-gray.disabled:focus,
|
||||||
|
.btn-gray.disabled:hover,
|
||||||
|
.btn-gray.disabled:active {
|
||||||
|
color: #323232;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
.nav-header > li > a:focus,
|
||||||
|
.nav-header > li > a:hover {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
#recently-added-row-scroller,
|
||||||
|
#recently-watched-row-scroller {
|
||||||
|
position: relative;
|
||||||
|
}
|
|
@ -217,8 +217,8 @@ DOCUMENTATION :: END
|
||||||
% endif
|
% endif
|
||||||
<div class="dashboard-activity-progress">
|
<div class="dashboard-activity-progress">
|
||||||
<div class="dashboard-activity-progress-bar">
|
<div class="dashboard-activity-progress-bar">
|
||||||
<div class="bufferbar" style="width: ${a['transcode_progress']}%">${a['transcode_progress']}%</div>
|
<div class="bufferbar" style="width: ${a['transcode_progress']}%" data-toggle="tooltip" title="Transcoder Progress">${a['transcode_progress']}%</div>
|
||||||
<div class="bar" style="width: ${a['progress_percent']}%">${a['progress_percent']}%</div>
|
<div class="bar" style="width: ${a['progress_percent']}%" data-toggle="tooltip" title="Stream Progress">${a['progress_percent']}%</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="dashboard-activity-metadata-wrapper">
|
<div class="dashboard-activity-metadata-wrapper">
|
||||||
|
@ -261,11 +261,7 @@ DOCUMENTATION :: END
|
||||||
% endif
|
% endif
|
||||||
</div>
|
</div>
|
||||||
<div class="dashboard-activity-metadata-user">
|
<div class="dashboard-activity-metadata-user">
|
||||||
% if a['user_id']:
|
|
||||||
<a href="user?user_id=${a['user_id']}" title="${a['friendly_name']}">${a['friendly_name']}</a>
|
<a href="user?user_id=${a['user_id']}" title="${a['friendly_name']}">${a['friendly_name']}</a>
|
||||||
% else:
|
|
||||||
<a href="user?user=${a['user']}" title="${a['friendly_name']}">${a['friendly_name']}</a>
|
|
||||||
% endif
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -289,11 +285,13 @@ DOCUMENTATION :: END
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add hover class to dashboard-instance
|
// Add hover class to dashboard-instance
|
||||||
$('.dashboard-activity-poster').hover(function() {
|
$('.dashboard-activity-poster, .dashboard-activity-progress-bar').hover(function() {
|
||||||
$(this).closest('.dashboard-instance').addClass('hover');
|
$(this).closest('.dashboard-instance').addClass('hover');
|
||||||
}, function() {
|
}, function() {
|
||||||
$(this).closest('.dashboard-instance').removeClass('hover');
|
$(this).closest('.dashboard-instance').removeClass('hover');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$('.bar, .bufferbar').tooltip({container: 'body', placement: 'right', delay: 50});
|
||||||
</script>
|
</script>
|
||||||
% else:
|
% else:
|
||||||
<div class="text-muted">Nothing is currently being watched.</div><br>
|
<div class="text-muted">Nothing is currently being watched.</div><br>
|
||||||
|
|
|
@ -249,7 +249,7 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// Modal popup dialog
|
// Modal popup dialog
|
||||||
function selectHandler(selectedDate) {
|
function selectHandler(selectedDate, selectedSeries) {
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -259,10 +259,25 @@
|
||||||
var y = dateValue.getFullYear();
|
var y = dateValue.getFullYear();
|
||||||
var dateString = '' + y + '-' + (m<=9 ? '0' + m : m) + '-' + (d <= 9 ? '0' + d : d);
|
var dateString = '' + y + '-' + (m<=9 ? '0' + m : m) + '-' + (d <= 9 ? '0' + d : d);
|
||||||
|
|
||||||
|
var media_type = 'all';
|
||||||
|
var transcode_decision = null;
|
||||||
|
switch(selectedSeries) {
|
||||||
|
case "TV": media_type = 'episode'; break;
|
||||||
|
case "Movies": media_type = 'movie'; break;
|
||||||
|
case "Music": media_type = 'track'; break;
|
||||||
|
case "Direct Play": transcode_decision = 'direct play'; break;
|
||||||
|
case "Direct Stream": transcode_decision = 'copy'; break;
|
||||||
|
case "Transcode": transcode_decision = 'transcode'; break;
|
||||||
|
}
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
"url": "history_table_modal",
|
url: "history_table_modal",
|
||||||
type: 'post',
|
type: 'post',
|
||||||
data: { 'start_date': dateString },
|
data: {
|
||||||
|
start_date: dateString,
|
||||||
|
media_type: media_type,
|
||||||
|
transcode_decision: transcode_decision
|
||||||
|
},
|
||||||
complete: function(xhr, status) {
|
complete: function(xhr, status) {
|
||||||
$('#history-modal').modal('show');
|
$('#history-modal').modal('show');
|
||||||
$("#history-modal").html(xhr.responseText);
|
$("#history-modal").html(xhr.responseText);
|
||||||
|
@ -271,7 +286,7 @@
|
||||||
}
|
}
|
||||||
catch(err)
|
catch(err)
|
||||||
{
|
{
|
||||||
console.log("Failed to retrieve data");
|
console.log("Failed to retrieve history modal data.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -299,6 +314,8 @@
|
||||||
var music_visible = (${config['music_logging_enable']} == 1 ? true : false);
|
var music_visible = (${config['music_logging_enable']} == 1 ? true : false);
|
||||||
|
|
||||||
function loadGraphsTab1(time_range, yaxis) {
|
function loadGraphsTab1(time_range, yaxis) {
|
||||||
|
$('#days-selection').show();
|
||||||
|
|
||||||
setGraphFormat(yaxis);
|
setGraphFormat(yaxis);
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
|
@ -382,6 +399,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadGraphsTab2(time_range, yaxis) {
|
function loadGraphsTab2(time_range, yaxis) {
|
||||||
|
$('#days-selection').show();
|
||||||
|
|
||||||
setGraphFormat(yaxis);
|
setGraphFormat(yaxis);
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
|
@ -460,6 +479,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadGraphsTab3(yaxis) {
|
function loadGraphsTab3(yaxis) {
|
||||||
|
$('#days-selection').hide();
|
||||||
|
|
||||||
setGraphFormat(yaxis);
|
setGraphFormat(yaxis);
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class='table-card-back'>
|
<div class='table-card-back'>
|
||||||
<table class="display" id="history_table" width="100%">
|
<table class="display history_table" id="history_table" width="100%">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th align="left" id="delete_row">Delete</th>
|
<th align="left" id="delete_row">Delete</th>
|
||||||
|
|
|
@ -5,12 +5,12 @@
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true"><i class="fa fa-remove"></i></button>
|
<button type="button" class="close" data-dismiss="modal" aria-hidden="true"><i class="fa fa-remove"></i></button>
|
||||||
<h4 class="modal-title" id="myModalLabel">
|
<h4 class="modal-title" id="myModalLabel">
|
||||||
<strong><span id="modal_header_ip_address">
|
<strong><span id="modal_header_ip_address">
|
||||||
<i class="fa fa-history"></i> History for <span id="date-header">${data}</span>
|
<i class="fa fa-history"></i> History for <span id="date-header">${data['start_date']}</span>
|
||||||
</span></strong>
|
</span></strong>
|
||||||
</h4>
|
</h4>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body" id="modal-text">
|
<div class="modal-body" id="modal-text">
|
||||||
<table class="display" id="history_table" width="100%">
|
<table class="display history_table" id="history_table_modal" width="100%">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th align="left" id="started">Started</th>
|
<th align="left" id="started">Started</th>
|
||||||
|
@ -32,7 +32,7 @@
|
||||||
<script src="interfaces/default/js/tables/history_table_modal.js"></script>
|
<script src="interfaces/default/js/tables/history_table_modal.js"></script>
|
||||||
<script>
|
<script>
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
$('#date-header').html(moment('${data}','YYYY-MM-DD').format('ddd MMM Do YYYY'));
|
$('#date-header').html(moment('${data["start_date"]}','YYYY-MM-DD').format('ddd MMM Do YYYY'));
|
||||||
history_table_modal_options.ajax = {
|
history_table_modal_options.ajax = {
|
||||||
url: 'get_history',
|
url: 'get_history',
|
||||||
type: 'post',
|
type: 'post',
|
||||||
|
@ -40,14 +40,16 @@
|
||||||
return {
|
return {
|
||||||
json_data: JSON.stringify(d),
|
json_data: JSON.stringify(d),
|
||||||
grouping: false,
|
grouping: false,
|
||||||
start_date: '${data}'
|
start_date: "${data['start_date']}",
|
||||||
};
|
media_type: "${data.get('media_type')}",
|
||||||
|
transcode_decision: "${data.get('transcode_decision')}"
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
history_table = $('#history_table').DataTable(history_table_modal_options);
|
history_table = $('#history_table_modal').DataTable(history_table_modal_options);
|
||||||
|
|
||||||
clearSearchButton('history_table', history_table);
|
clearSearchButton('history_table_modal', history_table);
|
||||||
|
|
||||||
// Move #info-modal to parent container
|
// Move #info-modal to parent container
|
||||||
if (!($('#history-modal').next().is('#info-modal'))) {
|
if (!($('#history-modal').next().is('#info-modal'))) {
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
<h3>Watch Statistics <small>Last ${config['home_stats_length']} days</small></h3>
|
<h3>Watch Statistics <small>Last ${config['home_stats_length']} days</small></h3>
|
||||||
</div>
|
</div>
|
||||||
<div id="home-stats" class="home-platforms">
|
<div id="home-stats" class="home-platforms">
|
||||||
<div class='text-muted'><i class="fa fa-refresh fa-spin"></i> Loading stats...</div>
|
<div class="text-muted"><i class="fa fa-refresh fa-spin"></i> Loading stats...</div>
|
||||||
<br>
|
<br>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -36,19 +36,27 @@
|
||||||
<h3>Library Statistics <small>${config['pms_name']}</small></h3>
|
<h3>Library Statistics <small>${config['pms_name']}</small></h3>
|
||||||
</div>
|
</div>
|
||||||
<div id="library-stats" class="library-platforms">
|
<div id="library-stats" class="library-platforms">
|
||||||
<div class='text-muted'><i class="fa fa-refresh fa-spin"></i> Loading stats...</div>
|
<div class="text-muted"><i class="fa fa-refresh fa-spin"></i> Loading stats...</div>
|
||||||
<br>
|
<br>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
% endif
|
% endif
|
||||||
<div class='row'>
|
<div class="row">
|
||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
<div class="padded-header">
|
<div class="padded-header">
|
||||||
|
<ul class="nav nav-header nav-dashboard pull-right">
|
||||||
|
<li>
|
||||||
|
<a href="#" id="recently-added-page-left" class="paginate btn-gray disabled" data-id="+1"><i class="fa fa-lg fa-chevron-left"></i></a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="#" id="recently-added-page-right" class="paginate btn-gray disabled" data-id="-1"><i class="fa fa-lg fa-chevron-right"></i></a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
<h3>Recently Added</h3>
|
<h3>Recently Added</h3>
|
||||||
</div>
|
</div>
|
||||||
<div id='recentlyAdded'>
|
<div id="recentlyAdded" style="margin-right: -15px;">
|
||||||
<div class='text-muted'><i class="fa fa-refresh fa-spin"></i> Looking for new items...</div>
|
<div class="text-muted"><i class="fa fa-refresh fa-spin"></i> Looking for new items...</div>
|
||||||
<br>
|
<br>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -59,7 +67,6 @@
|
||||||
<%def name="javascriptIncludes()">
|
<%def name="javascriptIncludes()">
|
||||||
<script src="interfaces/default/js/moment-with-locale.js"></script>
|
<script src="interfaces/default/js/moment-with-locale.js"></script>
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
function currentActivityHeader() {
|
function currentActivityHeader() {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: 'get_current_activity_header',
|
url: 'get_current_activity_header',
|
||||||
|
@ -71,7 +78,6 @@
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
currentActivityHeader();
|
currentActivityHeader();
|
||||||
setInterval(currentActivityHeader, 15000);
|
|
||||||
|
|
||||||
function currentActivity() {
|
function currentActivity() {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
|
@ -84,7 +90,12 @@
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
currentActivity();
|
currentActivity();
|
||||||
setInterval(currentActivity, 15000);
|
|
||||||
|
setInterval(function () {
|
||||||
|
$('.bar, .bufferbar').tooltip('destroy');
|
||||||
|
currentActivityHeader();
|
||||||
|
currentActivity();
|
||||||
|
}, 15000);
|
||||||
|
|
||||||
function getHomeStats(days) {
|
function getHomeStats(days) {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
|
@ -97,6 +108,7 @@
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
getHomeStats();
|
||||||
|
|
||||||
function getLibraryStats() {
|
function getLibraryStats() {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
|
@ -109,33 +121,21 @@
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
getLibraryStats();
|
||||||
|
|
||||||
function recentlyAdded() {
|
function recentlyAdded() {
|
||||||
var widthVal = $('body').find(".container-fluid").width();
|
|
||||||
var tmp = (widthVal-20) / 182;
|
|
||||||
|
|
||||||
if (tmp > 0) {
|
|
||||||
containerSize = parseInt(tmp);
|
|
||||||
} else {
|
|
||||||
containerSize = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: 'get_recently_added',
|
url: 'get_recently_added',
|
||||||
type: "GET",
|
type: "GET",
|
||||||
async: true,
|
async: true,
|
||||||
data: { count : containerSize },
|
data: { count : 50 },
|
||||||
complete: function(xhr, status) {
|
complete: function(xhr, status) {
|
||||||
$("#recentlyAdded").html(xhr.responseText);
|
$("#recentlyAdded").html(xhr.responseText);
|
||||||
|
highlightAddedScrollerButton();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
$(document).ready(function () {
|
recentlyAdded();
|
||||||
recentlyAdded();
|
|
||||||
$(window).resize(function() {
|
|
||||||
recentlyAdded();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
var date_format = 'YYYY-MM-DD';
|
var date_format = 'YYYY-MM-DD';
|
||||||
var time_format = 'hh:mm a';
|
var time_format = 'hh:mm a';
|
||||||
|
@ -148,10 +148,44 @@
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
getHomeStats();
|
function highlightAddedScrollerButton() {
|
||||||
getLibraryStats();
|
var scroller = $("#recently-added-row-scroller");
|
||||||
|
var numElems = scroller.find("li").length;
|
||||||
|
scroller.width(numElems * 175);
|
||||||
|
if (scroller.width() > $("body").find(".container-fluid").width()) {
|
||||||
|
$("#recently-added-page-right").removeClass("disabled");
|
||||||
|
} else {
|
||||||
|
$("#recently-added-page-right").addClass("disabled");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$(window).resize(function () {
|
||||||
|
highlightAddedScrollerButton();
|
||||||
|
});
|
||||||
|
|
||||||
|
var leftTotal = 0;
|
||||||
|
$(".paginate").click(function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
var scroller = $("#recently-added-row-scroller");
|
||||||
|
var containerWidth = $("body").find(".container-fluid").width();
|
||||||
|
var scrollAmount = $(this).data("id") * parseInt((containerWidth - 15) / 175) * 175;
|
||||||
|
var leftMax = Math.min(-parseInt(scroller.width()) + Math.abs(scrollAmount), 0);
|
||||||
|
|
||||||
|
leftTotal = Math.max(Math.min(leftTotal + scrollAmount, 0), leftMax);
|
||||||
|
scroller.animate({ left: leftTotal }, 250);
|
||||||
|
|
||||||
|
if (leftTotal == 0) {
|
||||||
|
$("#recently-added-page-left").addClass("disabled").blur();
|
||||||
|
} else {
|
||||||
|
$("#recently-added-page-left").removeClass("disabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (leftTotal == leftMax) {
|
||||||
|
$("#recently-added-page-right").addClass("disabled").blur();
|
||||||
|
} else {
|
||||||
|
$("#recently-added-page-right").removeClass("disabled");
|
||||||
|
}
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
</%def>
|
</%def>
|
||||||
|
|
|
@ -344,25 +344,41 @@ DOCUMENTATION :: END
|
||||||
<button class="btn btn-danger btn-edit" data-toggle="button" aria-pressed="false" autocomplete="off" id="row-edit-mode">
|
<button class="btn btn-danger btn-edit" data-toggle="button" aria-pressed="false" autocomplete="off" id="row-edit-mode">
|
||||||
<i class="fa fa-trash-o"></i> Delete mode
|
<i class="fa fa-trash-o"></i> Delete mode
|
||||||
</button>
|
</button>
|
||||||
|
% if source == 'history':
|
||||||
|
<a href="update_metadata?rating_key=${data['rating_key']}&update=True" class="btn btn-danger btn-edit" id="fix-metadata">
|
||||||
|
<i class="fa fa-wrench"></i> Fix Metadata
|
||||||
|
</a>
|
||||||
|
% endif
|
||||||
|
% if data.get('poster_url'):
|
||||||
|
% if data['media_type'] == 'artist' or data['media_type'] == 'album' or data['media_type'] == 'track':
|
||||||
|
<span class="imgur-poster-tooltip" data-toggle="popover" data-img="${data['poster_url']}" data-height="80" data-width="80" style="display: inline-flex;">
|
||||||
|
% else:
|
||||||
|
<span class="imgur-poster-tooltip" data-toggle="popover" data-img="${data['poster_url']}" data-height="120" data-width="80" style="display: inline-flex;">
|
||||||
|
% endif
|
||||||
|
<button class="btn btn-danger btn-edit" data-toggle="button" aria-pressed="false" autocomplete="off" id="delete-imgur-poster">
|
||||||
|
<i class="fa fa-picture-o"></i> Reset Imgur Poster
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
|
% endif
|
||||||
<div class="alert alert-danger alert-edit" role="alert" id="row-edit-mode-alert"><i class="fa fa-exclamation-triangle"></i> Select rows to delete. Data is deleted upon exiting delete mode.</div>
|
<div class="alert alert-danger alert-edit" role="alert" id="row-edit-mode-alert"><i class="fa fa-exclamation-triangle"></i> Select rows to delete. Data is deleted upon exiting delete mode.</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="table-card-back">
|
<div class="table-card-back">
|
||||||
<table class="display" id="history_table" width="100%">
|
<table class="display history_table" id="history_table-RK-${data['rating_key']}" width="100%">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th align='left' id="delete">Delete</th>
|
<th align="left" id="delete">Delete</th>
|
||||||
<th align='left' id="time">Time</th>
|
<th align="left" id="time">Time</th>
|
||||||
<th align='left' id="friendly_name">User</th>
|
<th align="left" id="friendly_name">User</th>
|
||||||
<th align='left' id="ip_address">IP Address</th>
|
<th align="left" id="ip_address">IP Address</th>
|
||||||
<th align='left' id="platform">Platform</th>
|
<th align="left" id="platform">Platform</th>
|
||||||
<th align='left' id="player">Player</th>
|
<th align="left" id="player">Player</th>
|
||||||
<th align='left' id="title">Title</th>
|
<th align="left" id="title">Title</th>
|
||||||
<th align='left' id="started">Started</th>
|
<th align="left" id="started">Started</th>
|
||||||
<th align='left' id="paused_counter">Paused</th>
|
<th align="left" id="paused_counter">Paused</th>
|
||||||
<th align='left' id="stopped">Stopped</th>
|
<th align="left" id="stopped">Stopped</th>
|
||||||
<th align='left' id="duration">Duration</th>
|
<th align="left" id="duration">Duration</th>
|
||||||
<th align='left' id="percent_complete"></th>
|
<th align="left" id="percent_complete"></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody></tbody>
|
<tbody></tbody>
|
||||||
|
@ -458,11 +474,11 @@ DOCUMENTATION :: END
|
||||||
<script>
|
<script>
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
get_history();
|
get_history();
|
||||||
history_table = $('#history_table').DataTable(history_table_options);
|
history_table = $('#history_table-RK-${data["rating_key"]}').DataTable(history_table_options);
|
||||||
var colvis = new $.fn.dataTable.ColVis(history_table, { buttonText: '<i class="fa fa-columns"></i> Select columns', buttonClass: 'btn btn-dark', exclude: [0, 11] });
|
var colvis = new $.fn.dataTable.ColVis(history_table, { buttonText: '<i class="fa fa-columns"></i> Select columns', buttonClass: 'btn btn-dark', exclude: [0, 11] });
|
||||||
$(colvis.button()).appendTo('div.colvis-button-bar');
|
$(colvis.button()).appendTo('div.colvis-button-bar');
|
||||||
|
|
||||||
clearSearchButton('history_table', history_table);
|
clearSearchButton('history_table-RK-${data["rating_key"]}', history_table);
|
||||||
|
|
||||||
$('#row-edit-mode').on('click', function() {
|
$('#row-edit-mode').on('click', function() {
|
||||||
$('#row-edit-mode-alert').fadeIn(200);
|
$('#row-edit-mode-alert').fadeIn(200);
|
||||||
|
@ -519,10 +535,33 @@ DOCUMENTATION :: END
|
||||||
$("#runtime").html(millisecondsToMinutes($("#runtime").text(), true));
|
$("#runtime").html(millisecondsToMinutes($("#runtime").text(), true));
|
||||||
$('div.art-face').animate({ opacity: 0.2 }, { duration: 1000 });
|
$('div.art-face').animate({ opacity: 0.2 }, { duration: 1000 });
|
||||||
</script>
|
</script>
|
||||||
% if source == 'history':
|
% if data.get('poster_url'):
|
||||||
<script>
|
<script>
|
||||||
$('#row-edit-mode').after('<a href="update_metadata?rating_key=${data['rating_key']}&update=True" class="btn btn-danger btn-edit" id="fix-metadata"> \
|
$('.imgur-poster-tooltip').popover({
|
||||||
<i class="fa fa-wrench"></i> Fix Metadata</a>');
|
html: true,
|
||||||
|
container: 'body',
|
||||||
|
trigger: 'hover',
|
||||||
|
placement: 'left',
|
||||||
|
template: '<div class="popover history-thumbnail-popover" role="tooltip"><div class="arrow" style="top: 50%;"></div><div class="popover-content"></div></div>',
|
||||||
|
content: function () {
|
||||||
|
return '<div class="history-thumbnail" style="background-image: url(' + $(this).data('img') + '); height: ' + $(this).data('height') + 'px; width: ' + $(this).data('width') + 'px;" />';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#delete-imgur-poster').on('click', function() {
|
||||||
|
$.ajax({
|
||||||
|
url: 'delete_poster_url',
|
||||||
|
type: 'POST',
|
||||||
|
async: true,
|
||||||
|
data: { poster_url : "${data['poster_url']}" },
|
||||||
|
success: function (data) {
|
||||||
|
var msg = '<i class="fa fa-check"></i> Imgur poster reset';
|
||||||
|
showMsg(msg, false, true, 2000);
|
||||||
|
$('.imgur-poster-tooltip').popover('destroy');
|
||||||
|
$('#delete-imgur-poster').closest('span').remove();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
% endif
|
% endif
|
||||||
% endif
|
% endif
|
||||||
|
|
|
@ -32,7 +32,8 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<span class="text-muted">Telize service written by <a href="https://github.com/fcambus/telize" target="_blank">Frederic Cambus</a>.</span>
|
<% from plexpy.helpers import anon_url %>
|
||||||
|
<span class="text-muted">Telize service written by <a href="${anon_url('https://github.com/fcambus/telize')}" target="_blank">Frederic Cambus</a>.</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -28,8 +28,8 @@ var hc_plays_by_day_options = {
|
||||||
cursor: 'pointer',
|
cursor: 'pointer',
|
||||||
point: {
|
point: {
|
||||||
events: {
|
events: {
|
||||||
click: function() {
|
click: function () {
|
||||||
selectHandler(this.category);
|
selectHandler(this.category, this.series.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -60,7 +60,8 @@ var hc_plays_by_day_options = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
tooltip: {
|
tooltip: {
|
||||||
shared: true
|
shared: true,
|
||||||
|
crosshairs: true
|
||||||
},
|
},
|
||||||
series: [{}]
|
series: [{}]
|
||||||
};
|
};
|
|
@ -29,7 +29,7 @@ var hc_plays_by_stream_type_options = {
|
||||||
point: {
|
point: {
|
||||||
events: {
|
events: {
|
||||||
click: function() {
|
click: function() {
|
||||||
selectHandler(this.category);
|
selectHandler(this.category, this.series.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -60,7 +60,8 @@ var hc_plays_by_stream_type_options = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
tooltip: {
|
tooltip: {
|
||||||
shared: true
|
shared: true,
|
||||||
|
crosshairs: true
|
||||||
},
|
},
|
||||||
series: [{}]
|
series: [{}]
|
||||||
};
|
};
|
|
@ -22,7 +22,7 @@ history_table_options = {
|
||||||
"emptyTable": "No data in table"
|
"emptyTable": "No data in table"
|
||||||
},
|
},
|
||||||
"pagingType": "bootstrap",
|
"pagingType": "bootstrap",
|
||||||
"stateSave": false,
|
"stateSave": true,
|
||||||
"processing": false,
|
"processing": false,
|
||||||
"serverSide": true,
|
"serverSide": true,
|
||||||
"pageLength": 25,
|
"pageLength": 25,
|
||||||
|
@ -107,7 +107,7 @@ history_table_options = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"width": "10%",
|
"width": "10%",
|
||||||
"className": "no-wrap hidden-md hidden-sm hidden-xs modal-control"
|
"className": "no-wrap hidden-md hidden-sm hidden-xs"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"targets": [5],
|
"targets": [5],
|
||||||
|
@ -115,11 +115,11 @@ history_table_options = {
|
||||||
"createdCell": function (td, cellData, rowData, row, col) {
|
"createdCell": function (td, cellData, rowData, row, col) {
|
||||||
if (cellData !== '') {
|
if (cellData !== '') {
|
||||||
var transcode_dec = '';
|
var transcode_dec = '';
|
||||||
if (rowData['video_decision'] === 'transcode' || rowData['audio_decision'] === 'transcode') {
|
if (rowData['transcode_decision'] === 'transcode') {
|
||||||
transcode_dec = '<span class="transcode-tooltip" data-toggle="tooltip" title="Transcode"><i class="fa fa-server fa-fw"></i></span>';
|
transcode_dec = '<span class="transcode-tooltip" data-toggle="tooltip" title="Transcode"><i class="fa fa-server fa-fw"></i></span>';
|
||||||
} else if (rowData['video_decision'] === 'copy' || rowData['audio_decision'] === 'copy') {
|
} else if (rowData['transcode_decision'] === 'copy') {
|
||||||
transcode_dec = '<span class="transcode-tooltip" data-toggle="tooltip" title="Direct Stream"><i class="fa fa-video-camera fa-fw"></i></span>';
|
transcode_dec = '<span class="transcode-tooltip" data-toggle="tooltip" title="Direct Stream"><i class="fa fa-video-camera fa-fw"></i></span>';
|
||||||
} else if (rowData['video_decision'] === 'direct play' || rowData['audio_decision'] === 'direct play') {
|
} else if (rowData['transcode_decision'] === 'direct play') {
|
||||||
transcode_dec = '<span class="transcode-tooltip" data-toggle="tooltip" title="Direct Play"><i class="fa fa-play-circle fa-fw"></i></span>';
|
transcode_dec = '<span class="transcode-tooltip" data-toggle="tooltip" title="Direct Play"><i class="fa fa-play-circle fa-fw"></i></span>';
|
||||||
}
|
}
|
||||||
$(td).html('<div><a href="#" data-target="#info-modal" data-toggle="modal"><div style="float: left;">' + transcode_dec + ' ' + cellData + '</div></a></div>');
|
$(td).html('<div><a href="#" data-target="#info-modal" data-toggle="modal"><div style="float: left;">' + transcode_dec + ' ' + cellData + '</div></a></div>');
|
||||||
|
@ -307,7 +307,7 @@ history_table_options = {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parent table platform modal
|
// Parent table platform modal
|
||||||
$('#history_table').on('click', '> tbody > tr > td.modal-control', function () {
|
$('.history_table').on('click', '> tbody > tr > td.modal-control', function () {
|
||||||
var tr = $(this).closest('tr');
|
var tr = $(this).closest('tr');
|
||||||
var row = history_table.row( tr );
|
var row = history_table.row( tr );
|
||||||
var rowData = row.data();
|
var rowData = row.data();
|
||||||
|
@ -327,7 +327,7 @@ $('#history_table').on('click', '> tbody > tr > td.modal-control', function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Parent table ip address modal
|
// Parent table ip address modal
|
||||||
$('#history_table').on('click', '> tbody > tr > td.modal-control-ip', function () {
|
$('.history_table').on('click', '> tbody > tr > td.modal-control-ip', function () {
|
||||||
var tr = $(this).closest('tr');
|
var tr = $(this).closest('tr');
|
||||||
var row = history_table.row( tr );
|
var row = history_table.row( tr );
|
||||||
var rowData = row.data();
|
var rowData = row.data();
|
||||||
|
@ -350,7 +350,7 @@ $('#history_table').on('click', '> tbody > tr > td.modal-control-ip', function (
|
||||||
});
|
});
|
||||||
|
|
||||||
// Parent table delete mode
|
// Parent table delete mode
|
||||||
$('#history_table').on('click', '> tbody > tr > td.delete-control > button', function () {
|
$('.history_table').on('click', '> tbody > tr > td.delete-control > button', function () {
|
||||||
var tr = $(this).closest('tr');
|
var tr = $(this).closest('tr');
|
||||||
var row = history_table.row( tr );
|
var row = history_table.row( tr );
|
||||||
var rowData = row.data();
|
var rowData = row.data();
|
||||||
|
@ -399,7 +399,7 @@ $('#history_table').on('click', '> tbody > tr > td.delete-control > button', fun
|
||||||
});
|
});
|
||||||
|
|
||||||
// Parent table expand detailed history
|
// Parent table expand detailed history
|
||||||
$('#history_table').on('click', '> tbody > tr > td.expand-history a', function () {
|
$('.history_table').on('click', '> tbody > tr > td.expand-history a', function () {
|
||||||
var tr = $(this).closest('tr');
|
var tr = $(this).closest('tr');
|
||||||
var row = history_table.row(tr);
|
var row = history_table.row(tr);
|
||||||
var rowData = row.data();
|
var rowData = row.data();
|
||||||
|
|
|
@ -79,11 +79,11 @@ history_table_modal_options = {
|
||||||
"createdCell": function (td, cellData, rowData, row, col) {
|
"createdCell": function (td, cellData, rowData, row, col) {
|
||||||
if (cellData !== '') {
|
if (cellData !== '') {
|
||||||
var transcode_dec = '';
|
var transcode_dec = '';
|
||||||
if (rowData['video_decision'] === 'transcode' || rowData['audio_decision'] === 'transcode') {
|
if (rowData['transcode_decision'] === 'transcode') {
|
||||||
transcode_dec = '<span class="transcode-tooltip" data-toggle="tooltip" title="Transcode"><i class="fa fa-server fa-fw"></i></span>';
|
transcode_dec = '<span class="transcode-tooltip" data-toggle="tooltip" title="Transcode"><i class="fa fa-server fa-fw"></i></span>';
|
||||||
} else if (rowData['video_decision'] === 'copy' || rowData['audio_decision'] === 'copy') {
|
} else if (rowData['transcode_decision'] === 'copy') {
|
||||||
transcode_dec = '<span class="transcode-tooltip" data-toggle="tooltip" title="Direct Stream"><i class="fa fa-video-camera fa-fw"></i></span>';
|
transcode_dec = '<span class="transcode-tooltip" data-toggle="tooltip" title="Direct Stream"><i class="fa fa-video-camera fa-fw"></i></span>';
|
||||||
} else if (rowData['video_decision'] === 'direct play' || rowData['audio_decision'] === 'direct play') {
|
} else if (rowData['transcode_decision'] === 'direct play') {
|
||||||
transcode_dec = '<span class="transcode-tooltip" data-toggle="tooltip" title="Direct Play"><i class="fa fa-play-circle fa-fw"></i></span>';
|
transcode_dec = '<span class="transcode-tooltip" data-toggle="tooltip" title="Direct Play"><i class="fa fa-play-circle fa-fw"></i></span>';
|
||||||
}
|
}
|
||||||
$(td).html('<div><a href="#" data-target="#info-modal" data-toggle="modal"><div style="float: left;">' + transcode_dec + ' ' + cellData + '</div></a></div>');
|
$(td).html('<div><a href="#" data-target="#info-modal" data-toggle="modal"><div style="float: left;">' + transcode_dec + ' ' + cellData + '</div></a></div>');
|
||||||
|
@ -148,7 +148,7 @@ history_table_modal_options = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$('#history_table').on('click', 'td.modal-control', function () {
|
$('.history_table').on('click', 'td.modal-control', function () {
|
||||||
var tr = $(this).parents('tr');
|
var tr = $(this).parents('tr');
|
||||||
var row = history_table.row(tr);
|
var row = history_table.row(tr);
|
||||||
var rowData = row.data();
|
var rowData = row.data();
|
||||||
|
|
|
@ -16,7 +16,7 @@ libraries_list_table_options = {
|
||||||
"pageLength": 10,
|
"pageLength": 10,
|
||||||
"order": [ 2, 'asc'],
|
"order": [ 2, 'asc'],
|
||||||
"autoWidth": true,
|
"autoWidth": true,
|
||||||
"stateSave": false,
|
"stateSave": true,
|
||||||
"pagingType": "bootstrap",
|
"pagingType": "bootstrap",
|
||||||
"columnDefs": [
|
"columnDefs": [
|
||||||
{
|
{
|
||||||
|
|
|
@ -5,7 +5,7 @@ var log_table_options = {
|
||||||
"pagingType": "bootstrap",
|
"pagingType": "bootstrap",
|
||||||
"order": [ 0, 'desc'],
|
"order": [ 0, 'desc'],
|
||||||
"pageLength": 50,
|
"pageLength": 50,
|
||||||
"stateSave": false,
|
"stateSave": true,
|
||||||
"language": {
|
"language": {
|
||||||
"search":"Search: ",
|
"search":"Search: ",
|
||||||
"lengthMenu":"Show _MENU_ lines per page",
|
"lengthMenu":"Show _MENU_ lines per page",
|
||||||
|
|
|
@ -23,7 +23,7 @@ media_info_table_options = {
|
||||||
"emptyTable": "No data in table"
|
"emptyTable": "No data in table"
|
||||||
},
|
},
|
||||||
"pagingType": "bootstrap",
|
"pagingType": "bootstrap",
|
||||||
"stateSave": false,
|
"stateSave": true,
|
||||||
"processing": false,
|
"processing": false,
|
||||||
"serverSide": true,
|
"serverSide": true,
|
||||||
"pageLength": 25,
|
"pageLength": 25,
|
||||||
|
@ -294,7 +294,7 @@ media_info_table_options = {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parent table expand detailed media info
|
// Parent table expand detailed media info
|
||||||
$('#media_info_table').on('click', '> tbody > tr > td.expand-media-info a', function () {
|
$('.media_info_table').on('click', '> tbody > tr > td.expand-media-info a', function () {
|
||||||
var tr = $(this).closest('tr');
|
var tr = $(this).closest('tr');
|
||||||
var row = media_info_table.row(tr);
|
var row = media_info_table.row(tr);
|
||||||
var rowData = row.data();
|
var rowData = row.data();
|
||||||
|
|
|
@ -5,7 +5,7 @@ notification_log_table_options = {
|
||||||
"pagingType": "bootstrap",
|
"pagingType": "bootstrap",
|
||||||
"order": [ 0, 'desc'],
|
"order": [ 0, 'desc'],
|
||||||
"pageLength": 50,
|
"pageLength": 50,
|
||||||
"stateSave": false,
|
"stateSave": true,
|
||||||
"language": {
|
"language": {
|
||||||
"search":"Search: ",
|
"search":"Search: ",
|
||||||
"lengthMenu":"Show _MENU_ lines per page",
|
"lengthMenu":"Show _MENU_ lines per page",
|
||||||
|
|
|
@ -5,7 +5,7 @@ var plex_log_table_options = {
|
||||||
"pagingType": "bootstrap",
|
"pagingType": "bootstrap",
|
||||||
"order": [ 0, 'desc'],
|
"order": [ 0, 'desc'],
|
||||||
"pageLength": 50,
|
"pageLength": 50,
|
||||||
"stateSave": false,
|
"stateSave": true,
|
||||||
"language": {
|
"language": {
|
||||||
"search":"Search: ",
|
"search":"Search: ",
|
||||||
"lengthMenu":"Show _MENU_ lines per page",
|
"lengthMenu":"Show _MENU_ lines per page",
|
||||||
|
|
|
@ -4,7 +4,7 @@ sync_table_options = {
|
||||||
"pagingType": "bootstrap",
|
"pagingType": "bootstrap",
|
||||||
"order": [ [ 0, 'desc'], [ 1, 'asc'], [2, 'asc'] ],
|
"order": [ [ 0, 'desc'], [ 1, 'asc'], [2, 'asc'] ],
|
||||||
"pageLength": 25,
|
"pageLength": 25,
|
||||||
"stateSave": false,
|
"stateSave": true,
|
||||||
"language": {
|
"language": {
|
||||||
"search":"Search: ",
|
"search":"Search: ",
|
||||||
"lengthMenu":"Show _MENU_ lines per page",
|
"lengthMenu":"Show _MENU_ lines per page",
|
||||||
|
|
|
@ -8,7 +8,7 @@ user_ip_table_options = {
|
||||||
"infoFiltered":"(filtered from _MAX_ total entries)",
|
"infoFiltered":"(filtered from _MAX_ total entries)",
|
||||||
"emptyTable": "No data in table",
|
"emptyTable": "No data in table",
|
||||||
},
|
},
|
||||||
"stateSave": false,
|
"stateSave": true,
|
||||||
"pagingType": "bootstrap",
|
"pagingType": "bootstrap",
|
||||||
"processing": false,
|
"processing": false,
|
||||||
"serverSide": true,
|
"serverSide": true,
|
||||||
|
@ -56,7 +56,7 @@ user_ip_table_options = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"width": "15%",
|
"width": "15%",
|
||||||
"className": "no-wrap hidden-md hidden-sm hidden-xs modal-control"
|
"className": "no-wrap hidden-md hidden-sm hidden-xs"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"targets": [3],
|
"targets": [3],
|
||||||
|
@ -64,11 +64,11 @@ user_ip_table_options = {
|
||||||
"createdCell": function (td, cellData, rowData, row, col) {
|
"createdCell": function (td, cellData, rowData, row, col) {
|
||||||
if (cellData) {
|
if (cellData) {
|
||||||
var transcode_dec = '';
|
var transcode_dec = '';
|
||||||
if (rowData['video_decision'] === 'transcode' || rowData['audio_decision'] === 'transcode') {
|
if (rowData['transcode_decision'] === 'transcode') {
|
||||||
transcode_dec = '<span class="transcode-tooltip" data-toggle="tooltip" title="Transcode"><i class="fa fa-server fa-fw"></i></span>';
|
transcode_dec = '<span class="transcode-tooltip" data-toggle="tooltip" title="Transcode"><i class="fa fa-server fa-fw"></i></span>';
|
||||||
} else if (rowData['video_decision'] === 'copy' || rowData['audio_decision'] === 'copy') {
|
} else if (rowData['transcode_decision'] === 'copy') {
|
||||||
transcode_dec = '<span class="transcode-tooltip" data-toggle="tooltip" title="Direct Stream"><i class="fa fa-video-camera fa-fw"></i></span>';
|
transcode_dec = '<span class="transcode-tooltip" data-toggle="tooltip" title="Direct Stream"><i class="fa fa-video-camera fa-fw"></i></span>';
|
||||||
} else if (rowData['video_decision'] === 'direct play' || rowData['audio_decision'] === 'direct play') {
|
} else if (rowData['transcode_decision'] === 'direct play') {
|
||||||
transcode_dec = '<span class="transcode-tooltip" data-toggle="tooltip" title="Direct Play"><i class="fa fa-play-circle fa-fw"></i></span>';
|
transcode_dec = '<span class="transcode-tooltip" data-toggle="tooltip" title="Direct Play"><i class="fa fa-play-circle fa-fw"></i></span>';
|
||||||
}
|
}
|
||||||
$(td).html('<div><a href="#" data-target="#info-modal" data-toggle="modal"><div style="float: left;">' + transcode_dec + ' ' + cellData + '</div></a></div>');
|
$(td).html('<div><a href="#" data-target="#info-modal" data-toggle="modal"><div style="float: left;">' + transcode_dec + ' ' + cellData + '</div></a></div>');
|
||||||
|
@ -146,11 +146,11 @@ user_ip_table_options = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$('#user_ip_table').on('mouseenter', 'td.modal-control span', function () {
|
$('.user_ip_table').on('mouseenter', 'td.modal-control span', function () {
|
||||||
$(this).tooltip();
|
$(this).tooltip();
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#user_ip_table').on('click', 'td.modal-control', function () {
|
$('.user_ip_table').on('click', 'td.modal-control', function () {
|
||||||
var tr = $(this).parents('tr');
|
var tr = $(this).parents('tr');
|
||||||
var row = user_ip_table.row(tr);
|
var row = user_ip_table.row(tr);
|
||||||
var rowData = row.data();
|
var rowData = row.data();
|
||||||
|
@ -169,7 +169,7 @@ $('#user_ip_table').on('click', 'td.modal-control', function () {
|
||||||
showStreamDetails();
|
showStreamDetails();
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#user_ip_table').on('click', 'td.modal-control-ip', function () {
|
$('.user_ip_table').on('click', 'td.modal-control-ip', function () {
|
||||||
var tr = $(this).parents('tr');
|
var tr = $(this).parents('tr');
|
||||||
var row = user_ip_table.row( tr );
|
var row = user_ip_table.row( tr );
|
||||||
var rowData = row.data();
|
var rowData = row.data();
|
||||||
|
|
|
@ -16,7 +16,7 @@ users_list_table_options = {
|
||||||
"pageLength": 10,
|
"pageLength": 10,
|
||||||
"order": [ 2, 'asc'],
|
"order": [ 2, 'asc'],
|
||||||
"autoWidth": true,
|
"autoWidth": true,
|
||||||
"stateSave": false,
|
"stateSave": true,
|
||||||
"pagingType": "bootstrap",
|
"pagingType": "bootstrap",
|
||||||
"columnDefs": [
|
"columnDefs": [
|
||||||
{
|
{
|
||||||
|
@ -120,11 +120,11 @@ users_list_table_options = {
|
||||||
"createdCell": function (td, cellData, rowData, row, col) {
|
"createdCell": function (td, cellData, rowData, row, col) {
|
||||||
if (cellData !== null && cellData !== '') {
|
if (cellData !== null && cellData !== '') {
|
||||||
var transcode_dec = '';
|
var transcode_dec = '';
|
||||||
if (rowData['video_decision'] === 'transcode' || rowData['audio_decision'] === 'transcode') {
|
if (rowData['transcode_decision'] === 'transcode') {
|
||||||
transcode_dec = '<span class="transcode-tooltip" data-toggle="tooltip" title="Transcode"><i class="fa fa-server fa-fw"></i></span>';
|
transcode_dec = '<span class="transcode-tooltip" data-toggle="tooltip" title="Transcode"><i class="fa fa-server fa-fw"></i></span>';
|
||||||
} else if (rowData['video_decision'] === 'copy' || rowData['audio_decision'] === 'copy') {
|
} else if (rowData['transcode_decision'] === 'copy') {
|
||||||
transcode_dec = '<span class="transcode-tooltip" data-toggle="tooltip" title="Direct Stream"><i class="fa fa-video-camera fa-fw"></i></span>';
|
transcode_dec = '<span class="transcode-tooltip" data-toggle="tooltip" title="Direct Stream"><i class="fa fa-video-camera fa-fw"></i></span>';
|
||||||
} else if (rowData['video_decision'] === 'direct play' || rowData['audio_decision'] === 'direct play') {
|
} else if (rowData['transcode_decision'] === 'direct play') {
|
||||||
transcode_dec = '<span class="transcode-tooltip" data-toggle="tooltip" title="Direct Play"><i class="fa fa-play-circle fa-fw"></i></span>';
|
transcode_dec = '<span class="transcode-tooltip" data-toggle="tooltip" title="Direct Play"><i class="fa fa-play-circle fa-fw"></i></span>';
|
||||||
}
|
}
|
||||||
$(td).html('<div><a href="#" data-target="#info-modal" data-toggle="modal"><div style="float: left;">' + transcode_dec + ' ' + cellData + '</div></a></div>');
|
$(td).html('<div><a href="#" data-target="#info-modal" data-toggle="modal"><div style="float: left;">' + transcode_dec + ' ' + cellData + '</div></a></div>');
|
||||||
|
|
|
@ -118,8 +118,16 @@ DOCUMENTATION :: END
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
<div class="table-card-header">
|
<div class="table-card-header">
|
||||||
|
<ul class="nav nav-header nav-dashboard pull-right">
|
||||||
|
<li>
|
||||||
|
<a href="#" id="recently-watched-page-left" class="paginate-watched btn-gray disabled" data-id="+1"><i class="fa fa-lg fa-chevron-left"></i></a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="#" id="recently-watched-page-right" class="paginate-watched btn-gray disabled" data-id="-1"><i class="fa fa-lg fa-chevron-right"></i></a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
<div class="header-bar">
|
<div class="header-bar">
|
||||||
<span><i class="fa fa-history"></i> Recently Watched</span>
|
<span><i class="fa fa-history"></i> Recently Played</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="table-card-back">
|
<div class="table-card-back">
|
||||||
|
@ -135,6 +143,14 @@ DOCUMENTATION :: END
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
<div class="table-card-header">
|
<div class="table-card-header">
|
||||||
|
<ul class="nav nav-header nav-dashboard pull-right">
|
||||||
|
<li>
|
||||||
|
<a href="#" id="recently-added-page-left" class="paginate-added btn-gray disabled" data-id="+1"><i class="fa fa-lg fa-chevron-left"></i></a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="#" id="recently-added-page-right" class="paginate-added btn-gray disabled" data-id="-1"><i class="fa fa-lg fa-chevron-right"></i></a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
<div class="header-bar">
|
<div class="header-bar">
|
||||||
<span><i class="fa fa-history"></i> Recently Added</span>
|
<span><i class="fa fa-history"></i> Recently Added</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -170,7 +186,7 @@ DOCUMENTATION :: END
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="table-card-back">
|
<div class="table-card-back">
|
||||||
<table class="display" id="history_table" width="100%">
|
<table class="display history_table" id="history_table-SID-${data['section_id']}" width="100%">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th align="left" id="delete">Delete</th>
|
<th align="left" id="delete">Delete</th>
|
||||||
|
@ -229,7 +245,7 @@ DOCUMENTATION :: END
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="table-card-back">
|
<div class="table-card-back">
|
||||||
<table class="display" id="media_info_table" width="100%">
|
<table class="display media_info_table" id="media_info_table-SID-${data['section_id']}" width="100%">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th align="left" id="added_at">Added At</th>
|
<th align="left" id="added_at">Added At</th>
|
||||||
|
@ -364,12 +380,12 @@ DOCUMENTATION :: END
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
history_table = $('#history_table').DataTable(history_table_options);
|
history_table = $('#history_table-SID-${data["section_id"]}').DataTable(history_table_options);
|
||||||
|
|
||||||
var colvis = new $.fn.dataTable.ColVis(history_table, { buttonText: '<i class="fa fa-columns"></i> Select columns', buttonClass: 'btn btn-dark', exclude: [0, 11] });
|
var colvis = new $.fn.dataTable.ColVis(history_table, { buttonText: '<i class="fa fa-columns"></i> Select columns', buttonClass: 'btn btn-dark', exclude: [0, 11] });
|
||||||
$(colvis.button()).appendTo('#button-bar-history');
|
$(colvis.button()).appendTo('#button-bar-history');
|
||||||
|
|
||||||
clearSearchButton('history_table', history_table);
|
clearSearchButton('history_table-SID-${data["section_id"]}', history_table);
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadMediaInfoTable() {
|
function loadMediaInfoTable() {
|
||||||
|
@ -385,12 +401,12 @@ DOCUMENTATION :: END
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
media_info_table = $('#media_info_table').DataTable(media_info_table_options);
|
media_info_table = $('#media_info_table-SID-${data["section_id"]}').DataTable(media_info_table_options);
|
||||||
|
|
||||||
var colvis = new $.fn.dataTable.ColVis(media_info_table, { buttonText: '<i class="fa fa-columns"></i> Select columns', buttonClass: 'btn btn-dark' });
|
var colvis = new $.fn.dataTable.ColVis(media_info_table, { buttonText: '<i class="fa fa-columns"></i> Select columns', buttonClass: 'btn btn-dark' });
|
||||||
$(colvis.button()).appendTo('#button-bar-media-info');
|
$(colvis.button()).appendTo('#button-bar-media-info');
|
||||||
|
|
||||||
clearSearchButton('media_info_table', media_info_table);
|
clearSearchButton('media_info_table-SID-${data["section_id"]}', media_info_table);
|
||||||
}
|
}
|
||||||
|
|
||||||
$( "#history-tab-btn" ).one( "click", function() {
|
$( "#history-tab-btn" ).one( "click", function() {
|
||||||
|
@ -460,61 +476,116 @@ DOCUMENTATION :: END
|
||||||
});
|
});
|
||||||
|
|
||||||
function recentlyWatched() {
|
function recentlyWatched() {
|
||||||
var widthVal = $("#library-recently-watched").width();
|
|
||||||
var tmp = (widthVal-25) / 175;
|
|
||||||
|
|
||||||
if (tmp > 0) {
|
|
||||||
var containerSize = parseInt(tmp);
|
|
||||||
} else {
|
|
||||||
var containerSize = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Populate recently watched
|
// Populate recently watched
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: 'get_library_recently_watched',
|
url: 'get_library_recently_watched',
|
||||||
async: true,
|
async: true,
|
||||||
data: {
|
data: {
|
||||||
section_id: section_id,
|
section_id: section_id,
|
||||||
limit: containerSize
|
limit: 50
|
||||||
},
|
},
|
||||||
complete: function(xhr, status) {
|
complete: function(xhr, status) {
|
||||||
$("#library-recently-watched").html(xhr.responseText);
|
$("#library-recently-watched").html(xhr.responseText);
|
||||||
|
highlightWatchedScrollerButton();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function recentlyAdded() {
|
function recentlyAdded() {
|
||||||
var widthVal = $("#library-recently-added").width();
|
|
||||||
var tmp = (widthVal-25) / 175;
|
|
||||||
|
|
||||||
if (tmp > 0) {
|
|
||||||
var containerSize = parseInt(tmp);
|
|
||||||
} else {
|
|
||||||
var containerSize = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Populate recently added
|
// Populate recently added
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: 'get_library_recently_added',
|
url: 'get_library_recently_added',
|
||||||
async: true,
|
async: true,
|
||||||
data: {
|
data: {
|
||||||
section_id: section_id,
|
section_id: section_id,
|
||||||
limit: containerSize
|
limit: 50
|
||||||
},
|
},
|
||||||
complete: function(xhr, status) {
|
complete: function(xhr, status) {
|
||||||
$("#library-recently-added").html(xhr.responseText);
|
$("#library-recently-added").html(xhr.responseText);
|
||||||
|
highlightAddedScrollerButton();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
recentlyWatched();
|
recentlyWatched();
|
||||||
recentlyAdded();
|
recentlyAdded();
|
||||||
|
|
||||||
|
function highlightWatchedScrollerButton() {
|
||||||
|
var scroller = $("#recently-watched-row-scroller");
|
||||||
|
var numElems = scroller.find("li").length;
|
||||||
|
scroller.width(numElems * 175);
|
||||||
|
if (scroller.width() > $("#library-recently-watched").width()) {
|
||||||
|
$("#recently-watched-page-right").removeClass("disabled");
|
||||||
|
} else {
|
||||||
|
$("#recently-watched-page-right").addClass("disabled");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function highlightAddedScrollerButton() {
|
||||||
|
var scroller = $("#recently-added-row-scroller");
|
||||||
|
var numElems = scroller.find("li").length;
|
||||||
|
scroller.width(numElems * 175);
|
||||||
|
if (scroller.width() > $("#library-recently-added").width()) {
|
||||||
|
$("#recently-added-page-right").removeClass("disabled");
|
||||||
|
} else {
|
||||||
|
$("#recently-added-page-right").addClass("disabled");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$(window).resize(function() {
|
$(window).resize(function() {
|
||||||
recentlyWatched();
|
highlightWatchedScrollerButton();
|
||||||
recentlyAdded();
|
highlightAddedScrollerButton();
|
||||||
});
|
});
|
||||||
|
|
||||||
$('div.art-face').animate({ opacity: 0.2 }, { duration: 1000 });
|
$('div.art-face').animate({ opacity: 0.2 }, { duration: 1000 });
|
||||||
|
|
||||||
|
var leftTotalWatched = 0;
|
||||||
|
$(".paginate-watched").click(function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
var scroller = $("#recently-watched-row-scroller");
|
||||||
|
var containerWidth = $("#library-recently-watched").width();
|
||||||
|
var scrollAmount = $(this).data("id") * parseInt(containerWidth / 175) * 175;
|
||||||
|
var leftMax = Math.min(-parseInt(scroller.width()) + Math.abs(scrollAmount), 0);
|
||||||
|
|
||||||
|
leftTotalWatched = Math.max(Math.min(leftTotalWatched + scrollAmount, 0), leftMax);
|
||||||
|
scroller.animate({ left: leftTotalWatched }, 250);
|
||||||
|
|
||||||
|
if (leftTotalWatched == 0) {
|
||||||
|
$("#recently-watched-page-left").addClass("disabled").blur();
|
||||||
|
} else {
|
||||||
|
$("#recently-watched-page-left").removeClass("disabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (leftTotalWatched == leftMax) {
|
||||||
|
$("#recently-watched-page-right").addClass("disabled").blur();
|
||||||
|
} else {
|
||||||
|
$("#recently-watched-page-right").removeClass("disabled");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var leftTotalAdded = 0;
|
||||||
|
$(".paginate-added").click(function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
var scroller = $("#recently-added-row-scroller");
|
||||||
|
var containerWidth = $("#library-recently-added").width();
|
||||||
|
var scrollAmount = $(this).data("id") * parseInt(containerWidth / 175) * 175;
|
||||||
|
var leftMax = Math.min(-parseInt(scroller.width()) + Math.abs(scrollAmount), 0);
|
||||||
|
|
||||||
|
leftTotalAdded = Math.max(Math.min(leftTotalAdded + scrollAmount, 0), leftMax);
|
||||||
|
scroller.animate({ left: leftTotalAdded }, 250);
|
||||||
|
|
||||||
|
if (leftTotalAdded == 0) {
|
||||||
|
$("#recently-added-page-left").addClass("disabled").blur();
|
||||||
|
} else {
|
||||||
|
$("#recently-added-page-left").removeClass("disabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (leftTotalAdded == leftMax) {
|
||||||
|
$("#recently-added-page-right").addClass("disabled").blur();
|
||||||
|
} else {
|
||||||
|
$("#recently-added-page-right").removeClass("disabled");
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
% endif
|
% endif
|
||||||
|
|
|
@ -32,63 +32,65 @@ DOCUMENTATION :: END
|
||||||
|
|
||||||
% if data:
|
% if data:
|
||||||
<div class="dashboard-recent-media-row">
|
<div class="dashboard-recent-media-row">
|
||||||
<ul class="dashboard-recent-media list-unstyled">
|
<div id="recently-added-row-scroller" style="left: 0;">
|
||||||
% for item in data:
|
<ul class="dashboard-recent-media list-unstyled">
|
||||||
<li>
|
% for item in data:
|
||||||
% if item['media_type'] == 'episode' or item['media_type'] == 'movie':
|
<li>
|
||||||
<a href="info?rating_key=${item['rating_key']}">
|
% if item['media_type'] == 'episode' or item['media_type'] == 'movie':
|
||||||
<div class="dashboard-recent-media-poster">
|
<a href="info?rating_key=${item['rating_key']}">
|
||||||
% if item['media_type'] == 'episode':
|
<div class="dashboard-recent-media-poster">
|
||||||
% if item['parent_thumb']:
|
% if item['media_type'] == 'episode':
|
||||||
<div class="dashboard-recent-media-poster-face" style="background-image: url(pms_image_proxy?img=${item['parent_thumb']}&width=300&height=450&fallback=poster);">
|
% if item['parent_thumb']:
|
||||||
% else:
|
<div class="dashboard-recent-media-poster-face" style="background-image: url(pms_image_proxy?img=${item['parent_thumb']}&width=300&height=450&fallback=poster);">
|
||||||
<div class="dashboard-recent-media-poster-face" style="background-image: url(pms_image_proxy?img=${item['grandparent_thumb']}&width=300&height=450&fallback=poster);">
|
% else:
|
||||||
% endif
|
<div class="dashboard-recent-media-poster-face" style="background-image: url(pms_image_proxy?img=${item['grandparent_thumb']}&width=300&height=450&fallback=poster);">
|
||||||
% elif item['media_type'] == 'movie':
|
% endif
|
||||||
<div class="dashboard-recent-media-poster-face" style="background-image: url(pms_image_proxy?img=${item['thumb']}&width=300&height=450&fallback=poster);">
|
% elif item['media_type'] == 'movie':
|
||||||
% endif
|
<div class="dashboard-recent-media-poster-face" style="background-image: url(pms_image_proxy?img=${item['thumb']}&width=300&height=450&fallback=poster);">
|
||||||
<div class="dashboard-recent-media-overlay">
|
% endif
|
||||||
<div class="dashboard-recent-media-overlay-text" id="added_at-${item['rating_key']}">
|
<div class="dashboard-recent-media-overlay">
|
||||||
<script>
|
<div class="dashboard-recent-media-overlay-text" id="added_at-${item['rating_key']}">
|
||||||
|
<script>
|
||||||
|
$('#added_at-${item['rating_key']}').text('Added ' + moment(${item['added_at']}, "X").fromNow())
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="dashboard-recent-media-metacontainer">
|
||||||
|
% if item['media_type'] == 'episode':
|
||||||
|
<h3 title="${item['grandparent_title']}">${item['grandparent_title']}</h3>
|
||||||
|
<h3 title="${item['title']}">${item['title']}</h3>
|
||||||
|
<h3 class="text-muted">S${item['parent_media_index']} · E${item['media_index']}</h3>
|
||||||
|
% elif item['media_type'] == 'movie':
|
||||||
|
<h3 title="${item['title']}">${item['title']}</h3>
|
||||||
|
<h3 class="text-muted">${item['year']}</h3>
|
||||||
|
% endif
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
% elif item['media_type'] == 'album':
|
||||||
|
<a href="info?rating_key=${item['rating_key']}">
|
||||||
|
<div class="dashboard-recent-media-cover">
|
||||||
|
<div class="dashboard-recent-media-cover-face" style="background-image: url(pms_image_proxy?img=${item['thumb']}&width=300&height=300&fallback=cover);">
|
||||||
|
<div class="dashboard-recent-media-overlay">
|
||||||
|
<div class="dashboard-recent-media-overlay-text" id="added_at-${item['rating_key']}">
|
||||||
|
<script>
|
||||||
$('#added_at-${item['rating_key']}').text('Added ' + moment(${item['added_at']}, "X").fromNow())
|
$('#added_at-${item['rating_key']}').text('Added ' + moment(${item['added_at']}, "X").fromNow())
|
||||||
</script>
|
</script>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="dashboard-recent-media-metacontainer">
|
||||||
<div class="dashboard-recent-media-metacontainer">
|
<h3 title="${item['parent_title']}">${item['parent_title']}</h3>
|
||||||
% if item['media_type'] == 'episode':
|
<h3 class="text-muted">${item['title']}</h3>
|
||||||
<h3 title="${item['grandparent_title']}">${item['grandparent_title']}</h3>
|
|
||||||
<h3 title="${item['title']}">${item['title']}</h3>
|
|
||||||
<h3 class="text-muted">S${item['parent_media_index']} · E${item['media_index']}</h3>
|
|
||||||
% elif item['media_type'] == 'movie':
|
|
||||||
<h3 title="${item['title']}">${item['title']}</h3>
|
|
||||||
<h3 class="text-muted">${item['year']}</h3>
|
|
||||||
% endif
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
% elif item['media_type'] == 'album':
|
|
||||||
<a href="info?rating_key=${item['rating_key']}">
|
|
||||||
<div class="dashboard-recent-media-cover">
|
|
||||||
<div class="dashboard-recent-media-cover-face" style="background-image: url(pms_image_proxy?img=${item['thumb']}&width=300&height=300&fallback=cover);">
|
|
||||||
<div class="dashboard-recent-media-overlay">
|
|
||||||
<div class="dashboard-recent-media-overlay-text" id="added_at-${item['rating_key']}">
|
|
||||||
<script>
|
|
||||||
$('#added_at-${item['rating_key']}').text('Added ' + moment(${item['added_at']}, "X").fromNow())
|
|
||||||
</script>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</a>
|
||||||
<div class="dashboard-recent-media-metacontainer">
|
% endif
|
||||||
<h3 title="${item['parent_title']}">${item['parent_title']}</h3>
|
</li>
|
||||||
<h3 class="text-muted">${item['title']}</h3>
|
% endfor
|
||||||
</div>
|
</ul>
|
||||||
</a>
|
</div>
|
||||||
% endif
|
|
||||||
</li>
|
|
||||||
% endfor
|
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
% else:
|
% else:
|
||||||
<div class="text-muted">No stats to show.
|
<div class="text-muted">No stats to show.
|
||||||
|
|
|
@ -22,6 +22,7 @@ from plexpy import helpers
|
||||||
</div>
|
</div>
|
||||||
<div class="button-bar">
|
<div class="button-bar">
|
||||||
<button class="btn btn-dark" id="clear-logs"><i class="fa fa-trash-o"></i> Clear log</button>
|
<button class="btn btn-dark" id="clear-logs"><i class="fa fa-trash-o"></i> Clear log</button>
|
||||||
|
<button class="btn btn-dark" id="clear-notify-logs" style="display: none;"><i class="fa fa-trash-o"></i> Clear log</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class='table-card-back'>
|
<div class='table-card-back'>
|
||||||
|
@ -156,24 +157,28 @@ from plexpy import helpers
|
||||||
|
|
||||||
$("#plexpy-logs-btn").click(function () {
|
$("#plexpy-logs-btn").click(function () {
|
||||||
$("#clear-logs").show();
|
$("#clear-logs").show();
|
||||||
|
$("#clear-notify-logs").hide();
|
||||||
LoadPlexPyLogs();
|
LoadPlexPyLogs();
|
||||||
clearSearchButton('log_table', log_table);
|
clearSearchButton('log_table', log_table);
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#plex-logs-btn").click(function () {
|
$("#plex-logs-btn").click(function () {
|
||||||
$("#clear-logs").hide();
|
$("#clear-logs").hide();
|
||||||
|
$("#clear-notify-logs").hide();
|
||||||
LoadPlexLogs();
|
LoadPlexLogs();
|
||||||
clearSearchButton('plex_log_table', plex_log_table);
|
clearSearchButton('plex_log_table', plex_log_table);
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#plex-scanner-logs-btn").click(function () {
|
$("#plex-scanner-logs-btn").click(function () {
|
||||||
$("#clear-logs").hide();
|
$("#clear-logs").hide();
|
||||||
|
$("#clear-notify-logs").hide();
|
||||||
LoadPlexScannerLogs();
|
LoadPlexScannerLogs();
|
||||||
clearSearchButton('plex_scanner_log_table', plex_scanner_log_table);
|
clearSearchButton('plex_scanner_log_table', plex_scanner_log_table);
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#notification-logs-btn").click(function () {
|
$("#notification-logs-btn").click(function () {
|
||||||
$("#clear-logs").hide();
|
$("#clear-logs").hide();
|
||||||
|
$("#clear-notify-logs").show();
|
||||||
LoadNotificationLogs();
|
LoadNotificationLogs();
|
||||||
clearSearchButton('notification_log_table', notification_log_table);
|
clearSearchButton('notification_log_table', notification_log_table);
|
||||||
});
|
});
|
||||||
|
@ -185,6 +190,19 @@ from plexpy import helpers
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$("#clear-notify-logs").click(function () {
|
||||||
|
var r = confirm("Are you sure you want to clear the PlexPy notification log?");
|
||||||
|
if (r == true) {
|
||||||
|
$.ajax({
|
||||||
|
url: 'clearNotifyLogs',
|
||||||
|
type: 'POST',
|
||||||
|
success: function (data) {
|
||||||
|
notification_log_table.draw();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
var timer;
|
var timer;
|
||||||
function setRefresh()
|
function setRefresh()
|
||||||
{
|
{
|
||||||
|
@ -200,8 +218,12 @@ from plexpy import helpers
|
||||||
timer = setInterval(function() {
|
timer = setInterval(function() {
|
||||||
if ($("#tabs-1").hasClass("active")) {
|
if ($("#tabs-1").hasClass("active")) {
|
||||||
log_table.ajax.reload();
|
log_table.ajax.reload();
|
||||||
} else {
|
} else if ($("#tabs-2").hasClass("active")) {
|
||||||
plex_log_table.ajax.reload();
|
plex_log_table.ajax.reload();
|
||||||
|
} else if ($("#tabs-3").hasClass("active")) {
|
||||||
|
plex_scanner_log_table.ajax.reload();
|
||||||
|
} else if ($("#tabs-4").hasClass("active")) {
|
||||||
|
notification_log_table.ajax.reload();
|
||||||
}
|
}
|
||||||
}, 1000*refreshrate.value);
|
}, 1000*refreshrate.value);
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,6 +92,13 @@ from plexpy import helpers
|
||||||
</label>
|
</label>
|
||||||
<p class="help-block">Trigger notification when the Plex Media Server can be reached externally after being down.</p>
|
<p class="help-block">Trigger notification when the Plex Media Server can be reached externally after being down.</p>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="checkbox">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" data-size="small" data-id="${data['id']}" data-config-name="${data['config_prefix']}_on_pmsupdate" ${helpers.checked(data['on_pmsupdate'])} class="toggle-switches">
|
||||||
|
Notify on Plex update available
|
||||||
|
</label>
|
||||||
|
<p class="help-block">Trigger notification when an update for the Plex Media Server is available.</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -32,56 +32,58 @@ DOCUMENTATION :: END
|
||||||
|
|
||||||
% if data != None:
|
% if data != None:
|
||||||
<div class="dashboard-recent-media-row">
|
<div class="dashboard-recent-media-row">
|
||||||
<ul class="dashboard-recent-media list-unstyled">
|
<div id="recently-added-row-scroller" style="left: 0;">
|
||||||
% for item in data:
|
<ul class="dashboard-recent-media list-unstyled">
|
||||||
<div class="dashboard-recent-media-instance">
|
% for item in data:
|
||||||
<li>
|
<div class="dashboard-recent-media-instance">
|
||||||
% if item['media_type'] == 'season' or item['media_type'] == 'movie':
|
<li>
|
||||||
<a href="info?rating_key=${item['rating_key']}">
|
% if item['media_type'] == 'season' or item['media_type'] == 'movie':
|
||||||
<div class="dashboard-recent-media-poster">
|
<a href="info?rating_key=${item['rating_key']}">
|
||||||
<div class="dashboard-recent-media-poster-face" style="background-image: url(pms_image_proxy?img=${item['thumb']}&width=300&height=450&fallback=poster);">
|
<div class="dashboard-recent-media-poster">
|
||||||
<div class="dashboard-recent-media-overlay">
|
<div class="dashboard-recent-media-poster-face" style="background-image: url(pms_image_proxy?img=${item['thumb']}&width=300&height=450&fallback=poster);">
|
||||||
<div class="dashboard-recent-media-overlay-text" id="added_at-${item['rating_key']}">
|
<div class="dashboard-recent-media-overlay">
|
||||||
<script>
|
<div class="dashboard-recent-media-overlay-text" id="added_at-${item['rating_key']}">
|
||||||
$('#added_at-${item['rating_key']}').text('Added ' + moment(${item['added_at']}, "X").fromNow())
|
<script>
|
||||||
</script>
|
$('#added_at-${item['rating_key']}').text('Added ' + moment(${item['added_at']}, "X").fromNow())
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="dashboard-recent-media-metacontainer">
|
||||||
<div class="dashboard-recent-media-metacontainer">
|
% if item['media_type'] == 'season':
|
||||||
% if item['media_type'] == 'season':
|
<h3 title="${item['parent_title']}">${item['parent_title']}</h3>
|
||||||
<h3 title="${item['parent_title']}">${item['parent_title']}</h3>
|
<h3 class="text-muted">${item['title']}</h3>
|
||||||
<h3 class="text-muted">${item['title']}</h3>
|
% elif item['media_type'] == 'movie':
|
||||||
% elif item['media_type'] == 'movie':
|
<h3 title="${item['title']}">${item['title']}</h3>
|
||||||
<h3 title="${item['title']}">${item['title']}</h3>
|
<h3 class="text-muted">${item['year']}</h3>
|
||||||
<h3 class="text-muted">${item['year']}</h3>
|
% endif
|
||||||
% endif
|
</div>
|
||||||
</div>
|
</a>
|
||||||
</a>
|
% elif item['media_type'] == 'album':
|
||||||
% elif item['media_type'] == 'album':
|
<a href="info?rating_key=${item['rating_key']}">
|
||||||
<a href="info?rating_key=${item['rating_key']}">
|
<div class="dashboard-recent-media-cover">
|
||||||
<div class="dashboard-recent-media-cover">
|
<div class="dashboard-recent-media-cover-face" style="background-image: url(pms_image_proxy?img=${item['thumb']}&width=300&height=300&fallback=cover);">
|
||||||
<div class="dashboard-recent-media-cover-face" style="background-image: url(pms_image_proxy?img=${item['thumb']}&width=300&height=300&fallback=cover);">
|
<div class="dashboard-recent-media-overlay">
|
||||||
<div class="dashboard-recent-media-overlay">
|
<div class="dashboard-recent-media-overlay-text" id="added_at-${item['rating_key']}">
|
||||||
<div class="dashboard-recent-media-overlay-text" id="added_at-${item['rating_key']}">
|
<script>
|
||||||
<script>
|
$('#added_at-${item['rating_key']}').text('Added ' + moment(${item['added_at']}, "X").fromNow())
|
||||||
$('#added_at-${item['rating_key']}').text('Added ' + moment(${item['added_at']}, "X").fromNow())
|
</script>
|
||||||
</script>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="dashboard-recent-media-metacontainer">
|
||||||
<div class="dashboard-recent-media-metacontainer">
|
<h3 title="${item['parent_title']}">${item['parent_title']}</h3>
|
||||||
<h3 title="${item['parent_title']}">${item['parent_title']}</h3>
|
<h3 class="text-muted">${item['title']}</h3>
|
||||||
<h3 class="text-muted">${item['title']}</h3>
|
</div>
|
||||||
</div>
|
</a>
|
||||||
</a>
|
% endif
|
||||||
% endif
|
</li>
|
||||||
</li>
|
</div>
|
||||||
</div>
|
% endfor
|
||||||
% endfor
|
</ul>
|
||||||
</ul>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
% else:
|
% else:
|
||||||
<div class="text-muted">There was an error communicating with your Plex Server. Please check your <a href="settings">settings</a>.
|
<div class="text-muted">There was an error communicating with your Plex Server. Please check your <a href="settings">settings</a>.
|
||||||
|
|
|
@ -43,7 +43,7 @@ available_notification_agents = sorted(notifiers.available_notification_agents()
|
||||||
<li role="presentation"><a href="#tabs-5" aria-controls="tabs-5" role="tab" data-toggle="tab">Plex Media Server</a></li>
|
<li role="presentation"><a href="#tabs-5" aria-controls="tabs-5" role="tab" data-toggle="tab">Plex Media Server</a></li>
|
||||||
<li role="presentation"><a href="#tabs-6" aria-controls="tabs-6" role="tab" data-toggle="tab">Plex.tv Account</a></li>
|
<li role="presentation"><a href="#tabs-6" aria-controls="tabs-6" role="tab" data-toggle="tab">Plex.tv Account</a></li>
|
||||||
<li role="presentation"><a href="#tabs-7" aria-controls="tabs-7" role="tab" data-toggle="tab">Extra Settings</a></li>
|
<li role="presentation"><a href="#tabs-7" aria-controls="tabs-7" role="tab" data-toggle="tab">Extra Settings</a></li>
|
||||||
<li role="presentation"><a href="#tabs-8" aria-controls="tabs-8" role="tab" data-toggle="tab">Monitoring</a></li>
|
<li role="presentation"><a href="#tabs-8" aria-controls="tabs-8" role="tab" data-toggle="tab">Activity Monitoring</a></li>
|
||||||
<li role="presentation"><a href="#tabs-9" aria-controls="tabs-9" role="tab" data-toggle="tab">Notifications</a></li>
|
<li role="presentation"><a href="#tabs-9" aria-controls="tabs-9" role="tab" data-toggle="tab">Notifications</a></li>
|
||||||
<li role="presentation"><a href="#tabs-10" aria-controls="tabs-10" role="tab" data-toggle="tab">Notification Agents</a></li>
|
<li role="presentation"><a href="#tabs-10" aria-controls="tabs-10" role="tab" data-toggle="tab">Notification Agents</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -82,15 +82,15 @@ available_notification_agents = sorted(notifiers.available_notification_agents()
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Backup Directory:</td>
|
<td>Backup Directory:</td>
|
||||||
<td>${plexpy.CONFIG.BACKUP_DIR}</td>
|
<td>${config['backup_dir']}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Cache Directory:</td>
|
<td>Cache Directory:</td>
|
||||||
<td>${plexpy.CONFIG.CACHE_DIR}</td>
|
<td>${config['cache_dir']}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Log Directory:</td>
|
<td>Log Directory:</td>
|
||||||
<td>${plexpy.CONFIG.LOG_DIR}</td>
|
<td>${config['log_dir']}</td>
|
||||||
</tr>
|
</tr>
|
||||||
% if plexpy.ARGS:
|
% if plexpy.ARGS:
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -169,6 +169,35 @@ available_notification_agents = sorted(notifiers.available_notification_agents()
|
||||||
</label>
|
</label>
|
||||||
<p class="help-block">Group successive play history by the same user as a single entry in the tables and watch statistics.</p>
|
<p class="help-block">Group successive play history by the same user as a single entry in the tables and watch statistics.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="padded-header">
|
||||||
|
<h3>Directories</h3>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="backup_dir">Backup Directory</label>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<input type="text" class="form-control directory-settings" id="backup_dir" name="backup_dir" value="${config['backup_dir']}">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="cache_dir">Cache Directory</label>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<input type="text" class="form-control directory-settings" id="cache_dir" name="cache_dir" value="${config['cache_dir']}">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="log_dir">Log Directory</label>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<input type="text" class="form-control directory-settings" id="log_dir" name="log_dir" value="${config['log_dir']}">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<p><input type="button" class="btn btn-bright save-button" value="Save" data-success="Changes saved successfully"></p>
|
<p><input type="button" class="btn btn-bright save-button" value="Save" data-success="Changes saved successfully"></p>
|
||||||
</div>
|
</div>
|
||||||
<div role="tabpanel" class="tab-pane" id="tabs-2">
|
<div role="tabpanel" class="tab-pane" id="tabs-2">
|
||||||
|
@ -437,9 +466,24 @@ available_notification_agents = sorted(notifiers.available_notification_agents()
|
||||||
<div role="tabpanel" class="tab-pane" id="tabs-5">
|
<div role="tabpanel" class="tab-pane" id="tabs-5">
|
||||||
|
|
||||||
<div class="padded-header">
|
<div class="padded-header">
|
||||||
<h3>Plex Media Server</h3>
|
<h3>Plex Media Server <small style="color: #fff;">Version <span id="pms_version">unknown</span></small></h3>
|
||||||
</div>
|
</div>
|
||||||
<p class="help-block">If you're using websocket monitoring, any server changes require a restart of PlexPy.</p>
|
<p class="help-block">If you're using websocket monitoring, any server changes require a restart of PlexPy.</p>
|
||||||
|
<div class="checkbox">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" id="monitor_pms_updates" name="monitor_pms_updates" value="1" ${config['monitor_pms_updates']}> Monitor Plex Updates
|
||||||
|
</label>
|
||||||
|
<p class="help-block">Enable to have PlexPy check if updates are available for the Plex Media Server.<br />
|
||||||
|
Note: The Plex updater is broken on certain Plex Pass version of Plex Media Server. PlexPy will automatically disable checking for Plex updates if one of these versions is found.</p>
|
||||||
|
</div>
|
||||||
|
<div class="checkbox">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" id="monitor_remote_access" name="monitor_remote_access" value="1" ${config['monitor_remote_access']}> Monitor Plex Remote Access
|
||||||
|
</label>
|
||||||
|
<span id="remoteAccessCheck" style="color: #eb8600; padding-left: 10px;"></span>
|
||||||
|
<p class="help-block">Enable to have PlexPy check if remote access to the Plex Media Server goes down.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="form-group has-feedback" id="pms-ip-group">
|
<div class="form-group has-feedback" id="pms-ip-group">
|
||||||
<label for="pms_ip">Plex IP or Hostname</label>
|
<label for="pms_ip">Plex IP or Hostname</label>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
@ -485,8 +529,9 @@ available_notification_agents = sorted(notifiers.available_notification_agents()
|
||||||
<label for="pms_logs_folder">Logs Folder</label>
|
<label for="pms_logs_folder">Logs Folder</label>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<input type="text" class="form-control" id="pms_logs_folder" name="pms_logs_folder" value="${config['pms_logs_folder']}" size="30" data-parsley-trigger="change">
|
<input type="text" class="form-control" id="pms_logs_folder" name="pms_logs_folder" value="${config['pms_logs_folder']}" size="30" data-parsley-trigger="change" data-parsley-pattern="^[^\~\%]" data-parsley-errors-container="#pms_logs_folder_error" data-parsley-error-message="Shortcuts are not recognized.">
|
||||||
</div>
|
</div>
|
||||||
|
<div id="pms_logs_folder_error" class="alert alert-danger settings-alert" role="alert"></div>
|
||||||
</div>
|
</div>
|
||||||
<p class="help-block">Set the complete folder path where your Plex Server logs are, shortcuts are not recognized.<br />
|
<p class="help-block">Set the complete folder path where your Plex Server logs are, shortcuts are not recognized.<br />
|
||||||
<a href="${anon_url('https://support.plex.tv/hc/en-us/articles/200250417-Plex-Media-Server-Log-Files')}" target="_blank">Click here</a> for help. This is required if you enable IP logging (for PMS 0.9.12 and below). </p>
|
<a href="${anon_url('https://support.plex.tv/hc/en-us/articles/200250417-Plex-Media-Server-Log-Files')}" target="_blank">Click here</a> for help. This is required if you enable IP logging (for PMS 0.9.12 and below). </p>
|
||||||
|
@ -613,13 +658,6 @@ available_notification_agents = sorted(notifiers.available_notification_agents()
|
||||||
</label>
|
</label>
|
||||||
<p class="help-block">Instead of polling the server at regular intervals let the server tell PlexPy when something happens.</p>
|
<p class="help-block">Instead of polling the server at regular intervals let the server tell PlexPy when something happens.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="checkbox">
|
|
||||||
<label>
|
|
||||||
<input type="checkbox" id="monitor_remote_access" name="monitor_remote_access" value="1" ${config['monitor_remote_access']}> Monitor Plex Remote Access
|
|
||||||
</label>
|
|
||||||
<span id="remoteAccessCheck" style="color: #eb8600; padding-left: 10px;"></span>
|
|
||||||
<p class="help-block">Enable to have PlexPy check if remote access to the Plex Media Server goes down.</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="padded-header">
|
<div class="padded-header">
|
||||||
<h3>History Logging</h3>
|
<h3>History Logging</h3>
|
||||||
|
@ -749,8 +787,14 @@ available_notification_agents = sorted(notifiers.available_notification_agents()
|
||||||
<label>
|
<label>
|
||||||
<input type="checkbox" name="notify_recently_added_grandparent" id="notify_recently_added_grandparent" value="1" ${config['notify_recently_added_grandparent']}> Group notifications for recently added TV Shows or Music
|
<input type="checkbox" name="notify_recently_added_grandparent" id="notify_recently_added_grandparent" value="1" ${config['notify_recently_added_grandparent']}> Group notifications for recently added TV Shows or Music
|
||||||
</label>
|
</label>
|
||||||
<p class="help-block">Enable to only get one TV Show or Artist notification for a batch of recently added Episodes or Tracks. Movies are unaffected.<br />
|
<p class="help-block">
|
||||||
Note: No Season/Episode or Album/Track metadata will be available.</p>
|
Enable to only get one TV Show or Artist notification for a batch of recently added Episodes or Tracks. Movies are unaffected.<br />
|
||||||
|
% if config['notify_recently_added_grandparent'] == 'Checked':
|
||||||
|
<span id="notify_recently_added_grandparent_note" style="color: #eb8600;">Note: No Season/Episode or Album/Track metadata will be available.</span>
|
||||||
|
% else:
|
||||||
|
<span id="notify_recently_added_grandparent_note">Note: No Season/Episode or Album/Track metadata will be available.</span>
|
||||||
|
% endif
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="notify_recently_added_delay">Notification Delay</label>
|
<label for="notify_recently_added_delay">Notification Delay</label>
|
||||||
|
@ -965,6 +1009,23 @@ available_notification_agents = sorted(notifiers.available_notification_agents()
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<div class="link"><i class="fa fa-refresh fa-fw"></i> Plex Update Available<i class="fa fa-chevron-down"></i></div>
|
||||||
|
<ul class="submenu">
|
||||||
|
<li>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="notify_on_pmsupdate_subject_text">Subject Line</label>
|
||||||
|
<input class="form-control" type="text" id="notify_on_pmsupdate_subject_text" name="notify_on_pmsupdate_subject_text" value="${config['notify_on_pmsupdate_subject_text']}" data-parsley-trigger="change" required>
|
||||||
|
<p class="help-block">Set a custom subject line.</p>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="notify_on_extup_body_text">Message Body</label>
|
||||||
|
<textarea class="form-control" id="notify_on_pmsupdate_body_text" name="notify_on_pmsupdate_body_text" data-parsley-trigger="change" data-autoresize required>${config['notify_on_pmsupdate_body_text']}</textarea>
|
||||||
|
<p class="help-block">Set a custom body.</p>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<ul id="accordion-scripts" class="accordion list-unstyled">
|
<ul id="accordion-scripts" class="accordion list-unstyled">
|
||||||
<li>
|
<li>
|
||||||
|
@ -1025,24 +1086,45 @@ available_notification_agents = sorted(notifiers.available_notification_agents()
|
||||||
<h4 class="modal-title">Date & Time Format Options</h4>
|
<h4 class="modal-title">Date & Time Format Options</h4>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<table>
|
<table class="notification-params time-options">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
Year
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
|
||||||
<td align="center" colspan="3"><h5>Year</h5></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
<tr>
|
||||||
<td><strong>YYYY</strong></td>
|
<td><strong>YYYY</strong></td>
|
||||||
<td>Numeric, 4 digits</td>
|
<td>Numeric, four digits</td>
|
||||||
<td>Eg., 1999, 2003</td>
|
<td>Eg., 1999, 2003</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><strong>YY</strong></td>
|
<td><strong>YY</strong></td>
|
||||||
<td>Numeric, 2 digits</td>
|
<td>Numeric, two digits</td>
|
||||||
<td>Eg., 99, 03</td>
|
<td>Eg., 99, 03</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<table class="notification-params time-options">
|
||||||
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<td align="center" colspan="3"><h5>Month</h5></td>
|
<th>
|
||||||
|
Month
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td><strong>MMMM</strong></td>
|
||||||
|
<td>Textual, full</td>
|
||||||
|
<td>January-December</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><strong>MMM</strong></td>
|
||||||
|
<td>Textual, three letters</td>
|
||||||
|
<td>Jan-Dec</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><strong>MM</strong></td>
|
<td><strong>MM</strong></td>
|
||||||
|
@ -1054,23 +1136,41 @@ available_notification_agents = sorted(notifiers.available_notification_agents()
|
||||||
<td>Numeric, without leading zeros</td>
|
<td>Numeric, without leading zeros</td>
|
||||||
<td>1-12</td>
|
<td>1-12</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<table class="notification-params time-options">
|
||||||
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<td><strong>MMMM</strong></td>
|
<th>
|
||||||
<td>Textual full</td>
|
Day of the Year
|
||||||
<td>January-December</td>
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td><strong>DDDD</strong></td>
|
||||||
|
<td>Numeric, with leading zeros</td>
|
||||||
|
<td>001-365</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><strong>MMM</strong></td>
|
<td><strong>DDD</strong></td>
|
||||||
<td>Textual three letters</td>
|
<td>Numeric, without leading zeros</td>
|
||||||
<td>Jan-Dec</td>
|
<td>1-365</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<table class="notification-params time-options">
|
||||||
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<td align="center" colspan="3"><h5>Day</h5></td>
|
<th>
|
||||||
|
Day of the Month
|
||||||
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td width="100"><strong>DD</strong></td>
|
<td><strong>DD</strong></td>
|
||||||
<td width="300">Numeric, with leading zeros</td>
|
<td>Numeric, with leading zeros</td>
|
||||||
<td>01-31</td>
|
<td>01-31</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -1080,57 +1180,165 @@ available_notification_agents = sorted(notifiers.available_notification_agents()
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><strong>Do</strong></td>
|
<td><strong>Do</strong></td>
|
||||||
<td>The English suffix for the day of the month</td>
|
<td>Numeric, with suffix</td>
|
||||||
<td>st, nd or th in the 1st, 2nd or 15th.</td>
|
<td>Eg., 1st, 2nd ... 31st.</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<table class="notification-params time-options">
|
||||||
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<td align="center" colspan="3"><h5>Time</h5></td>
|
<th>
|
||||||
|
Day of the Week
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td><strong>dddd</strong></td>
|
||||||
|
<td>Textual, full</td>
|
||||||
|
<td>Sunday-Saturday</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><strong>a</strong></td>
|
<td><strong>ddd</strong></td>
|
||||||
<td width="300">am/pm Lowercase</td>
|
<td>Textual, three letters</td>
|
||||||
<td>am, pm</td>
|
<td>Sun-Sat</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><strong>A</strong></td>
|
<td><strong>d</strong></td>
|
||||||
<td>AM/PM Uppercase</td>
|
<td>Numeric</td>
|
||||||
<td>AM, PM</td>
|
<td>0-6</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<table class="notification-params time-options">
|
||||||
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<td><strong>h</strong></td>
|
<th>
|
||||||
<td>Hour, 12-hour, without leading zeros</td>
|
Hour
|
||||||
<td>1-12</td>
|
</th>
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><strong>hh</strong></td>
|
|
||||||
<td>Hour, 12-hour, with leading zeros</td>
|
|
||||||
<td>01-12</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><strong>H</strong></td>
|
|
||||||
<td>Hour, 24-hour, without leading zeros</td>
|
|
||||||
<td>0-23</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td><strong>HH</strong></td>
|
<td><strong>HH</strong></td>
|
||||||
<td>Hour, 24-hour, with leading zeros</td>
|
<td>24-hour, with leading zeros</td>
|
||||||
<td>00-23</td>
|
<td>00-23</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><strong>H</strong></td>
|
||||||
|
<td>24-hour, without leading zeros</td>
|
||||||
|
<td>0-23</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><strong>hh</strong></td>
|
||||||
|
<td>12-hour, with leading zeros</td>
|
||||||
|
<td>01-12</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><strong>h</strong></td>
|
||||||
|
<td>12-hour, without leading zeros</td>
|
||||||
|
<td>1-12</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<table class="notification-params time-options">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
Minute
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td><strong>mm</strong></td>
|
<td><strong>mm</strong></td>
|
||||||
<td>Minutes, with leading zeros</td>
|
<td>Numeric, with leading zeros</td>
|
||||||
<td>00-59</td>
|
<td>00-59</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><strong>m</strong></td>
|
||||||
|
<td>Numeric, without leading zeros</td>
|
||||||
|
<td>0-59</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<table class="notification-params time-options">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
Second
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td><strong>ss</strong></td>
|
<td><strong>ss</strong></td>
|
||||||
<td>Seconds, with leading zeros</td>
|
<td>Numeric, with leading zeros</td>
|
||||||
<td>00-59</td>
|
<td>00-59</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><strong>zz</strong></td>
|
<td><strong>s</strong></td>
|
||||||
<td>Timezone abbreviation</td>
|
<td>Numeric, without leading zeros</td>
|
||||||
<td>Eg., EST, MDT ...</td>
|
<td>0-59</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<table class="notification-params time-options">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
AM / PM
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td><strong>A</strong></td>
|
||||||
|
<td>AM/PM uppercase</td>
|
||||||
|
<td>AM, PM</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><strong>a</strong></td>
|
||||||
|
<td width="300">am/pm lowercase</td>
|
||||||
|
<td>am, pm</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<table class="notification-params time-options">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
Timezone
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td><strong>ZZ</strong></td>
|
||||||
|
<td>UTC offset</td>
|
||||||
|
<td>Eg., +0100, -0700</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><strong>Z</strong></td>
|
||||||
|
<td>UTC offset</td>
|
||||||
|
<td>Eg., +01:00, -07:00</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<table class="notification-params time-options">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
Timestamp
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td><strong>X</strong></td>
|
||||||
|
<td>Unix timestamp</td>
|
||||||
|
<td>Eg., 1456887825</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
@ -1215,6 +1423,10 @@ available_notification_agents = sorted(notifiers.available_notification_agents()
|
||||||
<td><strong>{server_uptime}</strong></td>
|
<td><strong>{server_uptime}</strong></td>
|
||||||
<td>The uptime (in days, hours, mins, secs) of your Plex Server.</td>
|
<td>The uptime (in days, hours, mins, secs) of your Plex Server.</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><strong>{server_version}</strong></td>
|
||||||
|
<td>The current version of your Plex Server.</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><strong>{action}</strong></td>
|
<td><strong>{action}</strong></td>
|
||||||
<td>The action that triggered the notification.</td>
|
<td>The action that triggered the notification.</td>
|
||||||
|
@ -1407,7 +1619,7 @@ available_notification_agents = sorted(notifiers.available_notification_agents()
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><strong>{artist_name}</strong></td>
|
<td><strong>{artist_name}</strong></td>
|
||||||
<td>The name of the artistd.</td>
|
<td>The name of the artist.</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><strong>{album_name}</strong></td>
|
<td><strong>{album_name}</strong></td>
|
||||||
|
@ -1521,7 +1733,7 @@ available_notification_agents = sorted(notifiers.available_notification_agents()
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><strong>{lastfm_url}</strong></td>
|
<td><strong>{lastfm_url}</strong></td>
|
||||||
<td>The last.fm URL for the album.
|
<td>The Last.fm URL for the album.
|
||||||
<p class="small-muted">(PMS agent must be Last.fm)</p></td>
|
<p class="small-muted">(PMS agent must be Last.fm)</p></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -1546,6 +1758,29 @@ available_notification_agents = sorted(notifiers.available_notification_agents()
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
<table class="notification-params">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
Plex Update Available
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td><strong>{update_version}</strong></td>
|
||||||
|
<td>The available update version for your Plex Server.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><strong>{update_url}</strong></td>
|
||||||
|
<td>The available update download URL.</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><strong>{update_changelog}</strong></td>
|
||||||
|
<td>The changelog for the available update.</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer"></div>
|
<div class="modal-footer"></div>
|
||||||
|
@ -1650,10 +1885,11 @@ $(document).ready(function() {
|
||||||
authChanged = false;
|
authChanged = false;
|
||||||
httpChanged = false;
|
httpChanged = false;
|
||||||
monitorChanged = false;
|
monitorChanged = false;
|
||||||
|
directoryChanged = false;
|
||||||
|
|
||||||
// Alert the user that their changes require a restart.
|
// Alert the user that their changes require a restart.
|
||||||
function postSaveChecks() {
|
function postSaveChecks() {
|
||||||
if ((serverChanged && $('#monitoring_use_websocket').is(":checked")) || authChanged || httpChanged || monitorChanged) {
|
if ((serverChanged && $('#monitoring_use_websocket').is(":checked")) || authChanged || httpChanged || monitorChanged || directoryChanged) {
|
||||||
$('#restart-modal').modal('show');
|
$('#restart-modal').modal('show');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1766,6 +2002,10 @@ $(document).ready(function() {
|
||||||
monitorChanged = true;
|
monitorChanged = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$( ".directory-settings" ).change(function() {
|
||||||
|
directoryChanged = true;
|
||||||
|
});
|
||||||
|
|
||||||
$( ".pms-settings" ).change(function() {
|
$( ".pms-settings" ).change(function() {
|
||||||
serverChanged = true;
|
serverChanged = true;
|
||||||
$("#pms_identifier").val("");
|
$("#pms_identifier").val("");
|
||||||
|
@ -1899,50 +2139,62 @@ $(document).ready(function() {
|
||||||
$.get("/osxnotifyregister", { 'app': osx_notify_app }, function (data) { showMsg("<div class='msg'><span class='ui-icon ui-icon-check'></span>" + data + "</div>", false, true, 3000); });
|
$.get("/osxnotifyregister", { 'app': osx_notify_app }, function (data) { showMsg("<div class='msg'><span class='ui-icon ui-icon-check'></span>" + data + "</div>", false, true, 3000); });
|
||||||
})
|
})
|
||||||
|
|
||||||
|
pms_version = false;
|
||||||
|
pms_logs_debug = false;
|
||||||
|
pms_logs = false;
|
||||||
|
|
||||||
|
// Checks to see if PMS server version is >= 0.9.14 with automaatically logged IP addresses
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: 'get_server_identity',
|
url: 'get_server_identity',
|
||||||
async: true,
|
async: true,
|
||||||
success: function(data) {
|
success: function(data) {
|
||||||
var version = data.version.split('.')
|
if (data.version){ $("#pms_version").text(data.version); }
|
||||||
if (parseInt(version[0]) >= 0 && parseInt(version[1]) >= 9 && parseInt(version[2]) >= 14) {
|
var version = (data.version ? data.version.split('.') : null);
|
||||||
|
if (version && parseInt(version[0]) >= 0 && parseInt(version[1]) >= 9 && parseInt(version[2]) >= 14) {
|
||||||
$("#debugLogCheck").html("IP address is automatically logged for PMS version 0.9.14 and above.");
|
$("#debugLogCheck").html("IP address is automatically logged for PMS version 0.9.14 and above.");
|
||||||
$("#ip_logging_enable").attr("disabled", true);
|
$("#ip_logging_enable").attr("disabled", true);
|
||||||
$("#ip_logging_enable").attr("checked", true);
|
$("#ip_logging_enable").attr("checked", true);
|
||||||
|
pms_version = true;
|
||||||
|
checkLogsPath();
|
||||||
} else {
|
} else {
|
||||||
|
// Check to see if debug logs are enabled on the PMS.
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: 'get_server_pref',
|
url: 'get_server_pref',
|
||||||
data: { pref: 'logDebug' },
|
data: { pref: 'logDebug' },
|
||||||
async: true,
|
async: true,
|
||||||
success: function(data) {
|
success: function(data) {
|
||||||
if (data !== 'true') {
|
pms_logs_debug = (data == 'true' ? true : false);
|
||||||
$("#debugLogCheck").html("Debug logging must be enabled on your Plex Server. <a target='_blank' href='${anon_url('https://support.plex.tv/hc/en-us/articles/201643703-Reporting-issues-with-Plex-Media-Server')}'>Click here</a> for help.");
|
// Check to see if our logs folder is set before allowing IP logging to be enabled.
|
||||||
$("#ip_logging_enable").attr("disabled", true);
|
checkLogsPath();
|
||||||
$("#ip_logging_enable").attr("checked", false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Check to see if our logs folder is set before allowing IP logging to be enabled.
|
|
||||||
checkLogsPath();
|
|
||||||
|
|
||||||
$("#pms_logs_folder").change(function() {
|
|
||||||
checkLogsPath();
|
|
||||||
});
|
|
||||||
|
|
||||||
function checkLogsPath() {
|
|
||||||
if ($("#pms_logs_folder").val() == '') {
|
|
||||||
$("#debugLogCheck").html("You must first define your Plex Server Logs folder path under the Plex Media Server tab.");
|
|
||||||
$("#ip_logging_enable").attr("disabled", true);
|
|
||||||
$("#ip_logging_enable").attr("checked", false);
|
|
||||||
} else {
|
|
||||||
$("#ip_logging_enable").attr("disabled", false);
|
|
||||||
$("#debugLogCheck").html("");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$("#pms_logs_folder").change(function() {
|
||||||
|
checkLogsPath();
|
||||||
|
});
|
||||||
|
|
||||||
|
function checkLogsPath() {
|
||||||
|
pms_logs = ($("#pms_logs_folder").val() == '' ? false : true);
|
||||||
|
// Toggle IP logging checkbox depending on debug logs, and logs path
|
||||||
|
if (!(pms_version)) {
|
||||||
|
if (pms_logs_debug && pms_logs) {
|
||||||
|
$("#ip_logging_enable").attr("disabled", false);
|
||||||
|
$("#debugLogCheck").html("");
|
||||||
|
} else if (!(pms_logs_debug)) {
|
||||||
|
$("#debugLogCheck").html("Debug logging must be enabled on your Plex Server. <a target='_blank' href='${anon_url('https://support.plex.tv/hc/en-us/articles/201643703-Reporting-issues-with-Plex-Media-Server')}'>Click here</a> for help.");
|
||||||
|
$("#ip_logging_enable").attr("disabled", true);
|
||||||
|
$("#ip_logging_enable").attr("checked", false);
|
||||||
|
} else {
|
||||||
|
$("#debugLogCheck").html("You must first define your Plex Server Logs folder path under the Plex Media Server tab.");
|
||||||
|
$("#ip_logging_enable").attr("disabled", true);
|
||||||
|
$("#ip_logging_enable").attr("checked", false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: 'get_server_pref',
|
url: 'get_server_pref',
|
||||||
data: { pref: 'PublishServerOnPlexOnlineKey' },
|
data: { pref: 'PublishServerOnPlexOnlineKey' },
|
||||||
|
@ -2055,6 +2307,10 @@ $(document).ready(function() {
|
||||||
}
|
}
|
||||||
getSchedulerTable();
|
getSchedulerTable();
|
||||||
|
|
||||||
|
$("#notify_recently_added_grandparent").change(function () {
|
||||||
|
var c = this.checked ? '#eb8600' : '#737373';
|
||||||
|
$('#notify_recently_added_grandparent_note').css('color', c);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</%def>
|
</%def>
|
|
@ -112,8 +112,16 @@ from plexpy import helpers
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
<div class="table-card-header">
|
<div class="table-card-header">
|
||||||
|
<ul class="nav nav-header nav-dashboard pull-right">
|
||||||
|
<li>
|
||||||
|
<a href="#" id="recently-watched-page-left" class="paginate btn-gray disabled" data-id="+1"><i class="fa fa-lg fa-chevron-left"></i></a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="#" id="recently-watched-page-right" class="paginate btn-gray" data-id="-1"><i class="fa fa-lg fa-chevron-right"></i></a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
<div class="header-bar">
|
<div class="header-bar">
|
||||||
<span><i class="fa fa-history"></i> Recently Watched</span>
|
<span><i class="fa fa-history"></i> Recently Played</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="table-card-back">
|
<div class="table-card-back">
|
||||||
|
@ -140,7 +148,7 @@ from plexpy import helpers
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="table-card-back">
|
<div class="table-card-back">
|
||||||
<table id="user_ip_table" class="display" width="100%">
|
<table class="display user_ip_table" id="user_ip_table-UID-${data['user_id']}" width="100%">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th align="left">Last Seen</th>
|
<th align="left">Last Seen</th>
|
||||||
|
@ -178,7 +186,7 @@ from plexpy import helpers
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="table-card-back">
|
<div class="table-card-back">
|
||||||
<table class="display" id="history_table" width="100%">
|
<table class="display history_table" id="history_table-UID-${data['user_id']}" width="100%">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th align="left" id="delete">Delete</th>
|
<th align="left" id="delete">Delete</th>
|
||||||
|
@ -218,7 +226,7 @@ from plexpy import helpers
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="table-card-back">
|
<div class="table-card-back">
|
||||||
<table class="display" id="sync_table" width="100%">
|
<table class="display" id="sync_table-UID-${data['user_id']}" width="100%">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th align="left" id="state">State</th>
|
<th align="left" id="state">State</th>
|
||||||
|
@ -348,13 +356,13 @@ from plexpy import helpers
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
history_table = $('#history_table').DataTable(history_table_options);
|
history_table = $('#history_table-UID-${data["user_id"]}').DataTable(history_table_options);
|
||||||
history_table.column(2).visible(false);
|
history_table.column(2).visible(false);
|
||||||
|
|
||||||
var colvis = new $.fn.dataTable.ColVis(history_table, { buttonText: '<i class="fa fa-columns"></i> Select columns', buttonClass: 'btn btn-dark', exclude: [0, 11] });
|
var colvis = new $.fn.dataTable.ColVis(history_table, { buttonText: '<i class="fa fa-columns"></i> Select columns', buttonClass: 'btn btn-dark', exclude: [0, 11] });
|
||||||
$(colvis.button()).appendTo('#button-bar-history');
|
$(colvis.button()).appendTo('#button-bar-history');
|
||||||
|
|
||||||
clearSearchButton('history_table', history_table);
|
clearSearchButton('history_table-UID-${data["user_id"]}', history_table);
|
||||||
|
|
||||||
$('#history_table_filter').prepend('<div class="btn-group" data-toggle="buttons" id="media_type-selection" style="padding-right: 15px;"> \
|
$('#history_table_filter').prepend('<div class="btn-group" data-toggle="buttons" id="media_type-selection" style="padding-right: 15px;"> \
|
||||||
<label class="btn btn-dark active"> \
|
<label class="btn btn-dark active"> \
|
||||||
|
@ -397,9 +405,9 @@ from plexpy import helpers
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
user_ip_table = $('#user_ip_table').DataTable(user_ip_table_options);
|
user_ip_table = $('#user_ip_table-UID-${data["user_id"]}').DataTable(user_ip_table_options);
|
||||||
|
|
||||||
clearSearchButton('user_ip_table', user_ip_table);
|
clearSearchButton('user_ip_table-UID-${data["user_id"]}', user_ip_table);
|
||||||
});
|
});
|
||||||
|
|
||||||
$( "#sync-tab-btn" ).one( "click", function() {
|
$( "#sync-tab-btn" ).one( "click", function() {
|
||||||
|
@ -410,13 +418,13 @@ from plexpy import helpers
|
||||||
d.user_id = user_id;
|
d.user_id = user_id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sync_table = $('#sync_table').DataTable(sync_table_options);
|
sync_table = $('#sync_table-UID-${data["user_id"]}').DataTable(sync_table_options);
|
||||||
sync_table.column(1).visible(false);
|
sync_table.column(1).visible(false);
|
||||||
|
|
||||||
var colvis_sync = new $.fn.dataTable.ColVis( sync_table, { buttonText: '<i class="fa fa-columns"></i> Select columns', buttonClass: 'btn btn-dark' } );
|
var colvis_sync = new $.fn.dataTable.ColVis( sync_table, { buttonText: '<i class="fa fa-columns"></i> Select columns', buttonClass: 'btn btn-dark' } );
|
||||||
$( colvis_sync.button() ).appendTo('#button-bar-sync');
|
$( colvis_sync.button() ).appendTo('#button-bar-sync');
|
||||||
|
|
||||||
clearSearchButton('sync_table', sync_table);
|
clearSearchButton('sync_table-UID-${data["user_id"]}', sync_table);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Load edit user modal
|
// Load edit user modal
|
||||||
|
@ -471,32 +479,60 @@ from plexpy import helpers
|
||||||
});
|
});
|
||||||
|
|
||||||
function recentlyWatched() {
|
function recentlyWatched() {
|
||||||
var widthVal = $("#user-recently-watched").width();
|
|
||||||
var tmp = (widthVal-25) / 175;
|
|
||||||
|
|
||||||
if (tmp > 0) {
|
|
||||||
var containerSize = parseInt(tmp);
|
|
||||||
} else {
|
|
||||||
var containerSize = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Populate recently watched
|
// Populate recently watched
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: 'get_user_recently_watched',
|
url: 'get_user_recently_watched',
|
||||||
async: true,
|
async: true,
|
||||||
data: {
|
data: {
|
||||||
user_id: user_id,
|
user_id: user_id,
|
||||||
limit: containerSize
|
limit: 50
|
||||||
},
|
},
|
||||||
complete: function(xhr, status) {
|
complete: function(xhr, status) {
|
||||||
$("#user-recently-watched").html(xhr.responseText);
|
$("#user-recently-watched").html(xhr.responseText);
|
||||||
|
highlightWatchedScrollerButton();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
recentlyWatched();
|
recentlyWatched();
|
||||||
|
|
||||||
|
function highlightWatchedScrollerButton() {
|
||||||
|
var scroller = $("#recently-watched-row-scroller");
|
||||||
|
var numElems = scroller.find("li").length;
|
||||||
|
scroller.width(numElems * 175);
|
||||||
|
if (scroller.width() > $("#user-recently-watched").width()) {
|
||||||
|
$("#recently-watched-page-right").removeClass("disabled");
|
||||||
|
} else {
|
||||||
|
$("#recently-watched-page-right").addClass("disabled");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$(window).resize(function() {
|
$(window).resize(function() {
|
||||||
recentlyWatched();
|
highlightWatchedScrollerButton();
|
||||||
|
});
|
||||||
|
|
||||||
|
var leftTotal = 0;
|
||||||
|
$(".paginate").click(function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
var scroller = $("#recently-watched-row-scroller");
|
||||||
|
var containerWidth = $("#user-recently-watched").width();
|
||||||
|
var scrollAmount = $(this).data("id") * parseInt(containerWidth / 175) * 175;
|
||||||
|
var leftMax = Math.min(-parseInt(scroller.width()) + Math.abs(scrollAmount), 0);
|
||||||
|
|
||||||
|
leftTotal = Math.max(Math.min(leftTotal + scrollAmount, 0), leftMax);
|
||||||
|
scroller.animate({ left: leftTotal }, 250);
|
||||||
|
|
||||||
|
if (leftTotal == 0) {
|
||||||
|
$("#recently-watched-page-left").addClass("disabled").blur();
|
||||||
|
} else {
|
||||||
|
$("#recently-watched-page-left").removeClass("disabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (leftTotal == leftMax) {
|
||||||
|
$("#recently-watched-page-right").addClass("disabled").blur();
|
||||||
|
} else {
|
||||||
|
$("#recently-watched-page-right").removeClass("disabled");
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -28,56 +28,58 @@ DOCUMENTATION :: END
|
||||||
|
|
||||||
% if data:
|
% if data:
|
||||||
<div class="dashboard-recent-media-row">
|
<div class="dashboard-recent-media-row">
|
||||||
<ul class="dashboard-recent-media list-unstyled">
|
<div id="recently-watched-row-scroller" style="left: 0;">
|
||||||
% for item in data:
|
<ul class="dashboard-recent-media list-unstyled">
|
||||||
<li>
|
% for item in data:
|
||||||
% if item['media_type'] == 'episode' or item['media_type'] == 'movie':
|
<li>
|
||||||
<a href="info?source=history&rating_key=${item['rating_key']}">
|
% if item['media_type'] == 'episode' or item['media_type'] == 'movie':
|
||||||
<div class="dashboard-recent-media-poster">
|
<a href="info?source=history&rating_key=${item['rating_key']}">
|
||||||
<div class="dashboard-recent-media-poster-face" style="background-image: url(pms_image_proxy?img=${item['thumb']}&width=300&height=450&fallback=poster);">
|
<div class="dashboard-recent-media-poster">
|
||||||
<div class="dashboard-recent-media-overlay">
|
<div class="dashboard-recent-media-poster-face" style="background-image: url(pms_image_proxy?img=${item['thumb']}&width=300&height=450&fallback=poster);">
|
||||||
<div class="dashboard-recent-media-overlay-text" id="time-${item['time']}">
|
<div class="dashboard-recent-media-overlay">
|
||||||
<script>
|
<div class="dashboard-recent-media-overlay-text" id="time-${item['time']}">
|
||||||
$('#time-${item['time']}').text('Watched ' + moment(${item['time']}, "X").fromNow())
|
<script>
|
||||||
</script>
|
$('#time-${item['time']}').text('Watched ' + moment(${item['time']}, "X").fromNow())
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="dashboard-recent-media-metacontainer">
|
||||||
<div class="dashboard-recent-media-metacontainer">
|
% if item['media_type'] == 'episode':
|
||||||
% if item['media_type'] == 'episode':
|
<h3 title="${item['grandparent_title']}">${item['grandparent_title']}</h3>
|
||||||
<h3 title="${item['grandparent_title']}">${item['grandparent_title']}</h3>
|
<h3 title="${item['title']}">${item['title']}</h3>
|
||||||
<h3 title="${item['title']}">${item['title']}</h3>
|
<h3 class="text-muted">S${item['parent_media_index']} · E${item['media_index']}</h3>
|
||||||
<h3 class="text-muted">S${item['parent_media_index']} · E${item['media_index']}</h3>
|
% elif item['media_type'] == 'movie':
|
||||||
% elif item['media_type'] == 'movie':
|
<h3 title="${item['title']}">${item['title']}</h3>
|
||||||
<h3 title="${item['title']}">${item['title']}</h3>
|
<h3 class="text-muted">${item['year']}</h3>
|
||||||
<h3 class="text-muted">${item['year']}</h3>
|
% endif
|
||||||
% endif
|
</div>
|
||||||
</div>
|
</a>
|
||||||
</a>
|
% elif item['media_type'] == 'track':
|
||||||
% elif item['media_type'] == 'track':
|
<a href="info?source=history&rating_key=${item['rating_key']}">
|
||||||
<a href="info?source=history&rating_key=${item['rating_key']}">
|
<div class="dashboard-recent-media-cover">
|
||||||
<div class="dashboard-recent-media-cover">
|
<div class="dashboard-recent-media-cover-face" style="background-image: url(pms_image_proxy?img=${item['thumb']}&width=300&height=300&fallback=cover);">
|
||||||
<div class="dashboard-recent-media-cover-face" style="background-image: url(pms_image_proxy?img=${item['thumb']}&width=300&height=300&fallback=cover);">
|
<div class="dashboard-recent-media-overlay">
|
||||||
<div class="dashboard-recent-media-overlay">
|
<div class="dashboard-recent-media-overlay-text" id="time-${item['time']}">
|
||||||
<div class="dashboard-recent-media-overlay-text" id="time-${item['time']}">
|
<script>
|
||||||
<script>
|
$('#time-${item['time']}').text('Watched ' + moment(${item['time']}, "X").fromNow())
|
||||||
$('#time-${item['time']}').text('Watched ' + moment(${item['time']}, "X").fromNow())
|
</script>
|
||||||
</script>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="dashboard-recent-media-metacontainer">
|
||||||
<div class="dashboard-recent-media-metacontainer">
|
<h3 title="${item['grandparent_title']}">${item['grandparent_title']}</h3>
|
||||||
<h3 title="${item['grandparent_title']}">${item['grandparent_title']}</h3>
|
<h3 title="${item['title']}">${item['title']}</h3>
|
||||||
<h3 title="${item['title']}">${item['title']}</h3>
|
<h3 class="text-muted">${item['parent_title']}</h3>
|
||||||
<h3 class="text-muted">${item['parent_title']}</h3>
|
</div>
|
||||||
</div>
|
</a>
|
||||||
</a>
|
% endif
|
||||||
% endif
|
</li>
|
||||||
</li>
|
% endfor
|
||||||
% endfor
|
</ul>
|
||||||
</ul>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
% else:
|
% else:
|
||||||
<div class="text-muted">No stats to show.</div><br>
|
<div class="text-muted">No stats to show.</div><br>
|
||||||
|
|
|
@ -33,12 +33,13 @@ load_rc_config ${name}
|
||||||
: ${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"}
|
||||||
|
: ${plexpy_flags:=""}
|
||||||
|
|
||||||
status_cmd="${name}_status"
|
status_cmd="${name}_status"
|
||||||
stop_cmd="${name}_stop"
|
stop_cmd="${name}_stop"
|
||||||
|
|
||||||
command="/usr/sbin/daemon"
|
command="${plexpy_dir}/PlexPy.py"
|
||||||
command_args="python2 ${plexpy_dir}/PlexPy.py --daemon --pidfile ${plexpy_pid} --quiet --nolaunch"
|
command_args="--daemon --pidfile ${plexpy_pid} --quiet --nolaunch ${plexpy_flags}"
|
||||||
|
|
||||||
# Ensure user is root when running this script.
|
# Ensure user is root when running this script.
|
||||||
if [ `id -u` != "0" ]; then
|
if [ `id -u` != "0" ]; then
|
||||||
|
|
5
init-scripts/init.freenas
Normal file → Executable file
5
init-scripts/init.freenas
Normal file → Executable file
|
@ -33,12 +33,13 @@ load_rc_config ${name}
|
||||||
: ${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"}
|
||||||
|
: ${plexpy_flags:=""}
|
||||||
|
|
||||||
status_cmd="${name}_status"
|
status_cmd="${name}_status"
|
||||||
stop_cmd="${name}_stop"
|
stop_cmd="${name}_stop"
|
||||||
|
|
||||||
command="/usr/sbin/daemon"
|
command="${plexpy_dir}/PlexPy.py"
|
||||||
command_args="python2 ${plexpy_dir}/PlexPy.py --daemon --pidfile ${plexpy_pid} --quiet --nolaunch"
|
command_args="--daemon --pidfile ${plexpy_pid} --quiet --nolaunch ${plexpy_flags}"
|
||||||
|
|
||||||
# Ensure user is root when running this script.
|
# Ensure user is root when running this script.
|
||||||
if [ `id -u` != "0" ]; then
|
if [ `id -u` != "0" ]; then
|
||||||
|
|
|
@ -103,7 +103,7 @@ def initialize(config_file):
|
||||||
if not CONFIG.HTTPS_KEY:
|
if not CONFIG.HTTPS_KEY:
|
||||||
CONFIG.HTTPS_KEY = os.path.join(DATA_DIR, 'server.key')
|
CONFIG.HTTPS_KEY = os.path.join(DATA_DIR, 'server.key')
|
||||||
|
|
||||||
if not CONFIG.LOG_DIR.startswith(os.path.abspath(DATA_DIR)):
|
if not CONFIG.LOG_DIR:
|
||||||
CONFIG.LOG_DIR = os.path.join(DATA_DIR, 'logs')
|
CONFIG.LOG_DIR = os.path.join(DATA_DIR, 'logs')
|
||||||
|
|
||||||
if not os.path.exists(CONFIG.LOG_DIR):
|
if not os.path.exists(CONFIG.LOG_DIR):
|
||||||
|
@ -120,8 +120,7 @@ def initialize(config_file):
|
||||||
logger.initLogger(console=not QUIET, log_dir=CONFIG.LOG_DIR,
|
logger.initLogger(console=not QUIET, log_dir=CONFIG.LOG_DIR,
|
||||||
verbose=VERBOSE)
|
verbose=VERBOSE)
|
||||||
|
|
||||||
if not CONFIG.BACKUP_DIR.startswith(os.path.abspath(DATA_DIR)):
|
if not CONFIG.BACKUP_DIR:
|
||||||
# Put the backup dir in the data dir for now
|
|
||||||
CONFIG.BACKUP_DIR = os.path.join(DATA_DIR, 'backups')
|
CONFIG.BACKUP_DIR = os.path.join(DATA_DIR, 'backups')
|
||||||
if not os.path.exists(CONFIG.BACKUP_DIR):
|
if not os.path.exists(CONFIG.BACKUP_DIR):
|
||||||
try:
|
try:
|
||||||
|
@ -129,14 +128,13 @@ def initialize(config_file):
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
logger.error("Could not create backup dir '%s': %s", BACKUP_DIR, e)
|
logger.error("Could not create backup dir '%s': %s", BACKUP_DIR, e)
|
||||||
|
|
||||||
if not CONFIG.CACHE_DIR.startswith(os.path.abspath(DATA_DIR)):
|
if not CONFIG.CACHE_DIR:
|
||||||
# Put the cache dir in the data dir for now
|
|
||||||
CONFIG.CACHE_DIR = os.path.join(DATA_DIR, 'cache')
|
CONFIG.CACHE_DIR = os.path.join(DATA_DIR, 'cache')
|
||||||
if not os.path.exists(CONFIG.CACHE_DIR):
|
if not os.path.exists(CONFIG.CACHE_DIR):
|
||||||
try:
|
try:
|
||||||
os.makedirs(CONFIG.CACHE_DIR)
|
os.makedirs(CONFIG.CACHE_DIR)
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
logger.error("Could not create cache dir '%s': %s", DATA_DIR, e)
|
logger.error("Could not create cache dir '%s': %s", CACHE_DIR, e)
|
||||||
|
|
||||||
# Initialize the database
|
# Initialize the database
|
||||||
logger.info('Checking to see if the database has all tables....')
|
logger.info('Checking to see if the database has all tables....')
|
||||||
|
@ -306,6 +304,13 @@ def initialize_scheduler():
|
||||||
schedule_job(activity_pinger.check_recently_added, 'Check for recently added items',
|
schedule_job(activity_pinger.check_recently_added, 'Check for recently added items',
|
||||||
hours=0, minutes=0, seconds=0)
|
hours=0, minutes=0, seconds=0)
|
||||||
|
|
||||||
|
if CONFIG.MONITOR_PMS_UPDATES:
|
||||||
|
schedule_job(activity_pinger.check_server_updates, 'Check for Plex updates',
|
||||||
|
hours=12, minutes=0, seconds=0)
|
||||||
|
else:
|
||||||
|
schedule_job(activity_pinger.check_server_updates, 'Check for Plex updates',
|
||||||
|
hours=0, minutes=0, seconds=0)
|
||||||
|
|
||||||
if CONFIG.MONITOR_REMOTE_ACCESS:
|
if CONFIG.MONITOR_REMOTE_ACCESS:
|
||||||
schedule_job(activity_pinger.check_server_response, 'Check for Plex remote access',
|
schedule_job(activity_pinger.check_server_response, 'Check for Plex remote access',
|
||||||
hours=0, minutes=0, seconds=seconds)
|
hours=0, minutes=0, seconds=seconds)
|
||||||
|
@ -390,7 +395,7 @@ def dbcheck():
|
||||||
# sessions table :: This is a temp table that logs currently active sessions
|
# sessions table :: This is a temp table that logs currently active sessions
|
||||||
c_db.execute(
|
c_db.execute(
|
||||||
'CREATE TABLE IF NOT EXISTS sessions (id INTEGER PRIMARY KEY AUTOINCREMENT, '
|
'CREATE TABLE IF NOT EXISTS sessions (id INTEGER PRIMARY KEY AUTOINCREMENT, '
|
||||||
'session_key INTEGER, rating_key INTEGER, section_id INTEGER, media_type TEXT, started INTEGER, '
|
'session_key INTEGER, rating_key INTEGER, section_id INTEGER, media_type TEXT, started INTEGER, stopped INTEGER, '
|
||||||
'paused_counter INTEGER DEFAULT 0, state TEXT, user_id INTEGER, user TEXT, friendly_name TEXT, '
|
'paused_counter INTEGER DEFAULT 0, state TEXT, user_id INTEGER, user TEXT, friendly_name TEXT, '
|
||||||
'ip_address TEXT, machine_id TEXT, player TEXT, platform TEXT, title TEXT, parent_title TEXT, '
|
'ip_address TEXT, machine_id TEXT, player TEXT, platform TEXT, title TEXT, parent_title TEXT, '
|
||||||
'grandparent_title TEXT, parent_rating_key INTEGER, grandparent_rating_key INTEGER, '
|
'grandparent_title TEXT, parent_rating_key INTEGER, grandparent_rating_key INTEGER, '
|
||||||
|
@ -413,8 +418,8 @@ def dbcheck():
|
||||||
|
|
||||||
# session_history_media_info table :: This is a table which logs each session's media info
|
# session_history_media_info table :: This is a table which logs each session's media info
|
||||||
c_db.execute(
|
c_db.execute(
|
||||||
'CREATE TABLE IF NOT EXISTS session_history_media_info (id INTEGER PRIMARY KEY, '
|
'CREATE TABLE IF NOT EXISTS session_history_media_info (id INTEGER PRIMARY KEY, rating_key INTEGER, '
|
||||||
'rating_key INTEGER, video_decision TEXT, audio_decision TEXT, duration INTEGER DEFAULT 0, width INTEGER, '
|
'video_decision TEXT, audio_decision TEXT, transcode_decision TEXT, duration INTEGER DEFAULT 0, width INTEGER, '
|
||||||
'height INTEGER, container TEXT, video_codec TEXT, audio_codec TEXT, bitrate INTEGER, video_resolution TEXT, '
|
'height INTEGER, container TEXT, video_codec TEXT, audio_codec TEXT, bitrate INTEGER, video_resolution TEXT, '
|
||||||
'video_framerate TEXT, aspect_ratio TEXT, audio_channels INTEGER, transcode_protocol TEXT, '
|
'video_framerate TEXT, aspect_ratio TEXT, audio_channels INTEGER, transcode_protocol TEXT, '
|
||||||
'transcode_container TEXT, transcode_video_codec TEXT, transcode_audio_codec TEXT, '
|
'transcode_container TEXT, transcode_video_codec TEXT, transcode_audio_codec TEXT, '
|
||||||
|
@ -614,6 +619,15 @@ def dbcheck():
|
||||||
'ALTER TABLE sessions ADD COLUMN section_id INTEGER'
|
'ALTER TABLE sessions ADD COLUMN section_id INTEGER'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Upgrade sessions table from earlier versions
|
||||||
|
try:
|
||||||
|
c_db.execute('SELECT stopped FROM sessions')
|
||||||
|
except sqlite3.OperationalError:
|
||||||
|
logger.debug(u"Altering database. Updating database table sessions.")
|
||||||
|
c_db.execute(
|
||||||
|
'ALTER TABLE sessions ADD COLUMN stopped INTEGER'
|
||||||
|
)
|
||||||
|
|
||||||
# Upgrade session_history table from earlier versions
|
# Upgrade session_history table from earlier versions
|
||||||
try:
|
try:
|
||||||
c_db.execute('SELECT reference_id FROM session_history')
|
c_db.execute('SELECT reference_id FROM session_history')
|
||||||
|
@ -664,6 +678,21 @@ def dbcheck():
|
||||||
'ALTER TABLE session_history_metadata ADD COLUMN section_id INTEGER'
|
'ALTER TABLE session_history_metadata ADD COLUMN section_id INTEGER'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Upgrade session_history_media_info table from earlier versions
|
||||||
|
try:
|
||||||
|
c_db.execute('SELECT transcode_decision FROM session_history_media_info')
|
||||||
|
except sqlite3.OperationalError:
|
||||||
|
logger.debug(u"Altering database. Updating database table session_history_media_info.")
|
||||||
|
c_db.execute(
|
||||||
|
'ALTER TABLE session_history_media_info ADD COLUMN transcode_decision TEXT'
|
||||||
|
)
|
||||||
|
c_db.execute(
|
||||||
|
'UPDATE session_history_media_info SET transcode_decision = (CASE '
|
||||||
|
'WHEN video_decision = "transcode" OR audio_decision = "transcode" THEN "transcode" '
|
||||||
|
'WHEN video_decision = "copy" OR audio_decision = "copy" THEN "copy" '
|
||||||
|
'WHEN video_decision = "direct play" OR audio_decision = "direct play" THEN "direct play" END)'
|
||||||
|
)
|
||||||
|
|
||||||
# Upgrade users table from earlier versions
|
# Upgrade users table from earlier versions
|
||||||
try:
|
try:
|
||||||
c_db.execute('SELECT do_notify FROM users')
|
c_db.execute('SELECT do_notify FROM users')
|
||||||
|
@ -890,7 +919,13 @@ def shutdown(restart=False, update=False):
|
||||||
if '--nolaunch' not in args:
|
if '--nolaunch' not in args:
|
||||||
args += ['--nolaunch']
|
args += ['--nolaunch']
|
||||||
logger.info('Restarting PlexPy with %s', args)
|
logger.info('Restarting PlexPy with %s', args)
|
||||||
os.execv(exe, args)
|
|
||||||
|
# os.execv fails with spaced names on Windows
|
||||||
|
# https://bugs.python.org/issue19066
|
||||||
|
if os.name == 'nt':
|
||||||
|
subprocess.Popen(args, cwd=os.getcwd())
|
||||||
|
else:
|
||||||
|
os.execv(exe, args)
|
||||||
|
|
||||||
os._exit(0)
|
os._exit(0)
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
import time
|
import time
|
||||||
import plexpy
|
import plexpy
|
||||||
|
|
||||||
from plexpy import logger, pmsconnect, activity_processor, threading, notification_handler, helpers
|
from plexpy import logger, pmsconnect, activity_processor, threading, notification_handler, helpers, notifiers
|
||||||
|
|
||||||
|
|
||||||
class ActivityHandler(object):
|
class ActivityHandler(object):
|
||||||
|
@ -57,9 +57,11 @@ class ActivityHandler(object):
|
||||||
if self.is_valid_session() and self.get_live_session():
|
if self.is_valid_session() and self.get_live_session():
|
||||||
logger.debug(u"PlexPy ActivityHandler :: Session %s has started." % str(self.get_session_key()))
|
logger.debug(u"PlexPy ActivityHandler :: Session %s has started." % str(self.get_session_key()))
|
||||||
|
|
||||||
# Fire off notifications
|
# Check if any notification agents have notifications enabled
|
||||||
threading.Thread(target=notification_handler.notify,
|
if any(d['on_play'] for d in notifiers.available_notification_agents()):
|
||||||
kwargs=dict(stream_data=self.get_live_session(), notify_action='play')).start()
|
# Fire off notifications
|
||||||
|
threading.Thread(target=notification_handler.notify,
|
||||||
|
kwargs=dict(stream_data=self.get_live_session(), notify_action='play')).start()
|
||||||
|
|
||||||
# Write the new session to our temp session table
|
# Write the new session to our temp session table
|
||||||
self.update_db_session()
|
self.update_db_session()
|
||||||
|
@ -77,20 +79,24 @@ class ActivityHandler(object):
|
||||||
if not force_stop:
|
if not force_stop:
|
||||||
ap.set_session_state(session_key=self.get_session_key(),
|
ap.set_session_state(session_key=self.get_session_key(),
|
||||||
state=self.timeline['state'],
|
state=self.timeline['state'],
|
||||||
view_offset=self.timeline['viewOffset'])
|
view_offset=self.timeline['viewOffset'],
|
||||||
|
stopped=int(time.time()))
|
||||||
|
|
||||||
# Retrieve the session data from our temp table
|
# Retrieve the session data from our temp table
|
||||||
db_session = ap.get_session_by_key(session_key=self.get_session_key())
|
db_session = ap.get_session_by_key(session_key=self.get_session_key())
|
||||||
|
|
||||||
# Fire off notifications
|
# Check if any notification agents have notifications enabled
|
||||||
threading.Thread(target=notification_handler.notify,
|
if any(d['on_stop'] for d in notifiers.available_notification_agents()):
|
||||||
kwargs=dict(stream_data=db_session, notify_action='stop')).start()
|
# Fire off notifications
|
||||||
|
threading.Thread(target=notification_handler.notify,
|
||||||
|
kwargs=dict(stream_data=db_session, notify_action='stop')).start()
|
||||||
|
|
||||||
# Write it to the history table
|
# Write it to the history table
|
||||||
monitor_proc = activity_processor.ActivityProcessor()
|
monitor_proc = activity_processor.ActivityProcessor()
|
||||||
monitor_proc.write_session_history(session=db_session)
|
monitor_proc.write_session_history(session=db_session)
|
||||||
|
|
||||||
# Remove the session from our temp session table
|
# Remove the session from our temp session table
|
||||||
|
logger.debug(u"PlexPy ActivityHandler :: Removing session %s from session queue" % str(self.get_session_key()))
|
||||||
ap.delete_session(session_key=self.get_session_key())
|
ap.delete_session(session_key=self.get_session_key())
|
||||||
|
|
||||||
def on_pause(self):
|
def on_pause(self):
|
||||||
|
@ -109,9 +115,11 @@ class ActivityHandler(object):
|
||||||
# Retrieve the session data from our temp table
|
# Retrieve the session data from our temp table
|
||||||
db_session = ap.get_session_by_key(session_key=self.get_session_key())
|
db_session = ap.get_session_by_key(session_key=self.get_session_key())
|
||||||
|
|
||||||
# Fire off notifications
|
# Check if any notification agents have notifications enabled
|
||||||
threading.Thread(target=notification_handler.notify,
|
if any(d['on_pause'] for d in notifiers.available_notification_agents()):
|
||||||
kwargs=dict(stream_data=db_session, notify_action='pause')).start()
|
# Fire off notifications
|
||||||
|
threading.Thread(target=notification_handler.notify,
|
||||||
|
kwargs=dict(stream_data=db_session, notify_action='pause')).start()
|
||||||
|
|
||||||
def on_resume(self):
|
def on_resume(self):
|
||||||
if self.is_valid_session():
|
if self.is_valid_session():
|
||||||
|
@ -129,9 +137,11 @@ class ActivityHandler(object):
|
||||||
# Retrieve the session data from our temp table
|
# Retrieve the session data from our temp table
|
||||||
db_session = ap.get_session_by_key(session_key=self.get_session_key())
|
db_session = ap.get_session_by_key(session_key=self.get_session_key())
|
||||||
|
|
||||||
# Fire off notifications
|
# Check if any notification agents have notifications enabled
|
||||||
threading.Thread(target=notification_handler.notify,
|
if any(d['on_resume'] for d in notifiers.available_notification_agents()):
|
||||||
kwargs=dict(stream_data=db_session, notify_action='resume')).start()
|
# Fire off notifications
|
||||||
|
threading.Thread(target=notification_handler.notify,
|
||||||
|
kwargs=dict(stream_data=db_session, notify_action='resume')).start()
|
||||||
|
|
||||||
def on_buffer(self):
|
def on_buffer(self):
|
||||||
if self.is_valid_session():
|
if self.is_valid_session():
|
||||||
|
@ -159,8 +169,11 @@ class ActivityHandler(object):
|
||||||
if plexpy.CONFIG.BUFFER_THRESHOLD > 0 and (current_buffer_count >= plexpy.CONFIG.BUFFER_THRESHOLD and \
|
if plexpy.CONFIG.BUFFER_THRESHOLD > 0 and (current_buffer_count >= plexpy.CONFIG.BUFFER_THRESHOLD and \
|
||||||
time_since_last_trigger == 0 or time_since_last_trigger >= plexpy.CONFIG.BUFFER_WAIT):
|
time_since_last_trigger == 0 or time_since_last_trigger >= plexpy.CONFIG.BUFFER_WAIT):
|
||||||
ap.set_session_buffer_trigger_time(session_key=self.get_session_key())
|
ap.set_session_buffer_trigger_time(session_key=self.get_session_key())
|
||||||
threading.Thread(target=notification_handler.notify,
|
|
||||||
kwargs=dict(stream_data=db_stream, notify_action='buffer')).start()
|
# Check if any notification agents have notifications enabled
|
||||||
|
if any(d['on_buffer'] for d in notifiers.available_notification_agents()):
|
||||||
|
threading.Thread(target=notification_handler.notify,
|
||||||
|
kwargs=dict(stream_data=db_stream, notify_action='buffer')).start()
|
||||||
|
|
||||||
# This function receives events from our websocket connection
|
# This function receives events from our websocket connection
|
||||||
def process(self):
|
def process(self):
|
||||||
|
@ -202,10 +215,17 @@ class ActivityHandler(object):
|
||||||
|
|
||||||
# Monitor if the stream has reached the watch percentage for notifications
|
# Monitor if the stream has reached the watch percentage for notifications
|
||||||
# The only purpose of this is for notifications
|
# The only purpose of this is for notifications
|
||||||
progress_percent = helpers.get_percent(self.timeline['viewOffset'], db_session['duration'])
|
# Check if any notification agents have notifications enabled
|
||||||
if progress_percent >= plexpy.CONFIG.NOTIFY_WATCHED_PERCENT and this_state != 'buffering':
|
notify_agents = [d['id'] for d in notifiers.available_notification_agents() if d['on_watched']]
|
||||||
threading.Thread(target=notification_handler.notify,
|
# Get the current states for notifications from our db
|
||||||
kwargs=dict(stream_data=db_session, notify_action='watched')).start()
|
notified_agents = [d['agent_id'] for d in notification_handler.get_notify_state(session=db_session)
|
||||||
|
if d['notify_action'] == 'watched'] if notify_agents else []
|
||||||
|
|
||||||
|
if any(a not in notified_agents for a in notify_agents):
|
||||||
|
progress_percent = helpers.get_percent(self.timeline['viewOffset'], db_session['duration'])
|
||||||
|
if progress_percent >= plexpy.CONFIG.NOTIFY_WATCHED_PERCENT and this_state != 'buffering':
|
||||||
|
# Rather not put this on it's own thread so we know it completes before our next event.
|
||||||
|
notification_handler.notify(stream_data=db_session, notify_action='watched')
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# We don't have this session in our table yet, start a new one.
|
# We don't have this session in our table yet, start a new one.
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
|
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
from plexpy import logger, pmsconnect, plextv, notification_handler, database, helpers, activity_processor, libraries
|
from plexpy import logger, pmsconnect, plextv, notification_handler, database, helpers, activity_processor, libraries, notifiers
|
||||||
|
|
||||||
import threading
|
import threading
|
||||||
import plexpy
|
import plexpy
|
||||||
|
@ -38,9 +38,12 @@ def check_active_sessions(ws_request=False):
|
||||||
if session_list:
|
if session_list:
|
||||||
if int_ping_count >= 3:
|
if int_ping_count >= 3:
|
||||||
logger.info(u"PlexPy Monitor :: The Plex Media Server is back up.")
|
logger.info(u"PlexPy Monitor :: The Plex Media Server is back up.")
|
||||||
# Fire off notifications
|
|
||||||
threading.Thread(target=notification_handler.notify_timeline,
|
# Check if any notification agents have notifications enabled
|
||||||
kwargs=dict(notify_action='intup')).start()
|
if any(d['on_intup'] for d in notifiers.available_notification_agents()):
|
||||||
|
# Fire off notifications
|
||||||
|
threading.Thread(target=notification_handler.notify_timeline,
|
||||||
|
kwargs=dict(notify_action='intup')).start()
|
||||||
int_ping_count = 0
|
int_ping_count = 0
|
||||||
|
|
||||||
media_container = session_list['sessions']
|
media_container = session_list['sessions']
|
||||||
|
@ -58,16 +61,24 @@ def check_active_sessions(ws_request=False):
|
||||||
# Here we can check the play states
|
# Here we can check the play states
|
||||||
if session['state'] != stream['state']:
|
if session['state'] != stream['state']:
|
||||||
if session['state'] == 'paused':
|
if session['state'] == 'paused':
|
||||||
# Push any notifications -
|
logger.debug(u"PlexPy Monitor :: Session %s has been paused." % stream['session_key'])
|
||||||
# Push it on it's own thread so we don't hold up our db actions
|
|
||||||
threading.Thread(target=notification_handler.notify,
|
# Check if any notification agents have notifications enabled
|
||||||
kwargs=dict(stream_data=stream, notify_action='pause')).start()
|
if any(d['on_pause'] for d in notifiers.available_notification_agents()):
|
||||||
|
# Push any notifications -
|
||||||
|
# Push it on it's own thread so we don't hold up our db actions
|
||||||
|
threading.Thread(target=notification_handler.notify,
|
||||||
|
kwargs=dict(stream_data=stream, notify_action='pause')).start()
|
||||||
|
|
||||||
if session['state'] == 'playing' and stream['state'] == 'paused':
|
if session['state'] == 'playing' and stream['state'] == 'paused':
|
||||||
# Push any notifications -
|
logger.debug(u"PlexPy Monitor :: Session %s has been resumed." % stream['session_key'])
|
||||||
# Push it on it's own thread so we don't hold up our db actions
|
|
||||||
threading.Thread(target=notification_handler.notify,
|
# Check if any notification agents have notifications enabled
|
||||||
kwargs=dict(stream_data=stream, notify_action='resume')).start()
|
if any(d['on_resume'] for d in notifiers.available_notification_agents()):
|
||||||
|
# Push any notifications -
|
||||||
|
# Push it on it's own thread so we don't hold up our db actions
|
||||||
|
threading.Thread(target=notification_handler.notify,
|
||||||
|
kwargs=dict(stream_data=stream, notify_action='resume')).start()
|
||||||
|
|
||||||
if stream['state'] == 'paused' and not ws_request:
|
if stream['state'] == 'paused' and not ws_request:
|
||||||
# The stream is still paused so we need to increment the paused_counter
|
# The stream is still paused so we need to increment the paused_counter
|
||||||
|
@ -105,8 +116,12 @@ def check_active_sessions(ws_request=False):
|
||||||
'WHERE session_key = ? AND rating_key = ?',
|
'WHERE session_key = ? AND rating_key = ?',
|
||||||
[stream['session_key'], stream['rating_key']])
|
[stream['session_key'], stream['rating_key']])
|
||||||
|
|
||||||
threading.Thread(target=notification_handler.notify,
|
# Check if any notification agents have notifications enabled
|
||||||
kwargs=dict(stream_data=stream, notify_action='buffer')).start()
|
if any(d['on_buffer'] for d in notifiers.available_notification_agents()):
|
||||||
|
# Push any notifications -
|
||||||
|
# Push it on it's own thread so we don't hold up our db actions
|
||||||
|
threading.Thread(target=notification_handler.notify,
|
||||||
|
kwargs=dict(stream_data=stream, notify_action='buffer')).start()
|
||||||
else:
|
else:
|
||||||
# Subsequent buffer notifications after wait time
|
# Subsequent buffer notifications after wait time
|
||||||
if int(time.time()) > buffer_values[0]['buffer_last_triggered'] + \
|
if int(time.time()) > buffer_values[0]['buffer_last_triggered'] + \
|
||||||
|
@ -119,11 +134,16 @@ def check_active_sessions(ws_request=False):
|
||||||
'WHERE session_key = ? AND rating_key = ?',
|
'WHERE session_key = ? AND rating_key = ?',
|
||||||
[stream['session_key'], stream['rating_key']])
|
[stream['session_key'], stream['rating_key']])
|
||||||
|
|
||||||
threading.Thread(target=notification_handler.notify,
|
# Check if any notification agents have notifications enabled
|
||||||
kwargs=dict(stream_data=stream, notify_action='buffer')).start()
|
if any(d['on_buffer'] for d in notifiers.available_notification_agents()):
|
||||||
|
# Push any notifications -
|
||||||
|
# Push it on it's own thread so we don't hold up our db actions
|
||||||
|
threading.Thread(target=notification_handler.notify,
|
||||||
|
kwargs=dict(stream_data=stream, notify_action='buffer')).start()
|
||||||
|
|
||||||
logger.debug(u"PlexPy Monitor :: Stream buffering. Count is now %s. Last triggered %s."
|
logger.debug(u"PlexPy Monitor :: Session %s is buffering. Count is now %s. Last triggered %s."
|
||||||
% (buffer_values[0]['buffer_count'],
|
% (stream['session_key'],
|
||||||
|
buffer_values[0]['buffer_count'],
|
||||||
buffer_values[0]['buffer_last_triggered']))
|
buffer_values[0]['buffer_last_triggered']))
|
||||||
|
|
||||||
# Check if the user has reached the offset in the media we defined as the "watched" percent
|
# Check if the user has reached the offset in the media we defined as the "watched" percent
|
||||||
|
@ -132,37 +152,61 @@ def check_active_sessions(ws_request=False):
|
||||||
if session['view_offset'] and session['duration'] and session['state'] != 'buffering':
|
if session['view_offset'] and session['duration'] and session['state'] != 'buffering':
|
||||||
if helpers.get_percent(session['view_offset'],
|
if helpers.get_percent(session['view_offset'],
|
||||||
session['duration']) > plexpy.CONFIG.NOTIFY_WATCHED_PERCENT:
|
session['duration']) > plexpy.CONFIG.NOTIFY_WATCHED_PERCENT:
|
||||||
|
# Check if any notification agents have notifications enabled
|
||||||
|
if any(d['on_watched'] for d in notifiers.available_notification_agents()):
|
||||||
|
# Push any notifications -
|
||||||
|
# Push it on it's own thread so we don't hold up our db actions
|
||||||
|
threading.Thread(target=notification_handler.notify,
|
||||||
|
kwargs=dict(stream_data=stream, notify_action='watched')).start()
|
||||||
|
|
||||||
|
else:
|
||||||
|
# The user has stopped playing a stream
|
||||||
|
if stream['state'] != 'stopped':
|
||||||
|
logger.debug(u"PlexPy Monitor :: Session %s has stopped." % stream['session_key'])
|
||||||
|
|
||||||
|
# Set the stream stop time
|
||||||
|
stream['stopped'] = int(time.time())
|
||||||
|
monitor_db.action('UPDATE sessions SET stopped = ?, state = ? '
|
||||||
|
'WHERE session_key = ? AND rating_key = ?',
|
||||||
|
[stream['stopped'], 'stopped', stream['session_key'], stream['rating_key']])
|
||||||
|
|
||||||
|
# Check if the user has reached the offset in the media we defined as the "watched" percent
|
||||||
|
if stream['view_offset'] and stream['duration']:
|
||||||
|
if helpers.get_percent(stream['view_offset'],
|
||||||
|
stream['duration']) > plexpy.CONFIG.NOTIFY_WATCHED_PERCENT:
|
||||||
|
# Check if any notification agents have notifications enabled
|
||||||
|
if any(d['on_watched'] for d in notifiers.available_notification_agents()):
|
||||||
# Push any notifications -
|
# Push any notifications -
|
||||||
# Push it on it's own thread so we don't hold up our db actions
|
# Push it on it's own thread so we don't hold up our db actions
|
||||||
threading.Thread(target=notification_handler.notify,
|
threading.Thread(target=notification_handler.notify,
|
||||||
kwargs=dict(stream_data=stream, notify_action='watched')).start()
|
kwargs=dict(stream_data=stream, notify_action='watched')).start()
|
||||||
|
|
||||||
else:
|
# Check if any notification agents have notifications enabled
|
||||||
# The user has stopped playing a stream
|
if any(d['on_stop'] for d in notifiers.available_notification_agents()):
|
||||||
logger.debug(u"PlexPy Monitor :: Removing sessionKey %s ratingKey %s from session queue"
|
# Push any notifications - Push it on it's own thread so we don't hold up our db actions
|
||||||
% (stream['session_key'], stream['rating_key']))
|
|
||||||
monitor_db.action('DELETE FROM sessions WHERE session_key = ? AND rating_key = ?',
|
|
||||||
[stream['session_key'], stream['rating_key']])
|
|
||||||
|
|
||||||
# Check if the user has reached the offset in the media we defined as the "watched" percent
|
|
||||||
if stream['view_offset'] and stream['duration']:
|
|
||||||
if helpers.get_percent(stream['view_offset'],
|
|
||||||
stream['duration']) > plexpy.CONFIG.NOTIFY_WATCHED_PERCENT:
|
|
||||||
# Push any notifications -
|
|
||||||
# Push it on it's own thread so we don't hold up our db actions
|
|
||||||
threading.Thread(target=notification_handler.notify,
|
threading.Thread(target=notification_handler.notify,
|
||||||
kwargs=dict(stream_data=stream, notify_action='watched')).start()
|
kwargs=dict(stream_data=stream, notify_action='stop')).start()
|
||||||
|
|
||||||
# Push any notifications - Push it on it's own thread so we don't hold up our db actions
|
|
||||||
threading.Thread(target=notification_handler.notify,
|
|
||||||
kwargs=dict(stream_data=stream, notify_action='stop')).start()
|
|
||||||
|
|
||||||
# Write the item history on playback stop
|
# Write the item history on playback stop
|
||||||
monitor_process.write_session_history(session=stream)
|
success = monitor_process.write_session_history(session=stream)
|
||||||
|
|
||||||
|
if success:
|
||||||
|
# If session is written to the databaase successfully, remove the session from the session table
|
||||||
|
logger.debug(u"PlexPy Monitor :: Removing sessionKey %s ratingKey %s from session queue"
|
||||||
|
% (stream['session_key'], stream['rating_key']))
|
||||||
|
monitor_db.action('DELETE FROM sessions WHERE session_key = ? AND rating_key = ?',
|
||||||
|
[stream['session_key'], stream['rating_key']])
|
||||||
|
else:
|
||||||
|
logger.warn(u"PlexPy Monitor :: Failed to write sessionKey %s ratingKey %s to the database. " \
|
||||||
|
"Will try again on the next pass." % (stream['session_key'], stream['rating_key']))
|
||||||
|
|
||||||
# Process the newly received session data
|
# Process the newly received session data
|
||||||
for session in media_container:
|
for session in media_container:
|
||||||
monitor_process.write_session(session)
|
new_session = monitor_process.write_session(session)
|
||||||
|
|
||||||
|
if new_session:
|
||||||
|
logger.debug(u"PlexPy Monitor :: Session %s has started." % session['session_key'])
|
||||||
|
|
||||||
else:
|
else:
|
||||||
logger.debug(u"PlexPy Monitor :: Unable to read session list.")
|
logger.debug(u"PlexPy Monitor :: Unable to read session list.")
|
||||||
|
|
||||||
|
@ -171,9 +215,11 @@ def check_active_sessions(ws_request=False):
|
||||||
% str(int_ping_count))
|
% str(int_ping_count))
|
||||||
|
|
||||||
if int_ping_count == 3:
|
if int_ping_count == 3:
|
||||||
# Fire off notifications
|
# Check if any notification agents have notifications enabled
|
||||||
threading.Thread(target=notification_handler.notify_timeline,
|
if any(d['on_intdown'] for d in notifiers.available_notification_agents()):
|
||||||
kwargs=dict(notify_action='intdown')).start()
|
# Fire off notifications
|
||||||
|
threading.Thread(target=notification_handler.notify_timeline,
|
||||||
|
kwargs=dict(notify_action='intdown')).start()
|
||||||
|
|
||||||
|
|
||||||
def check_recently_added():
|
def check_recently_added():
|
||||||
|
@ -225,9 +271,12 @@ def check_recently_added():
|
||||||
|
|
||||||
if 0 < time_threshold - int(item['added_at']) <= time_interval:
|
if 0 < time_threshold - int(item['added_at']) <= time_interval:
|
||||||
logger.debug(u"PlexPy Monitor :: Library item %s has been added to Plex." % str(item['rating_key']))
|
logger.debug(u"PlexPy Monitor :: Library item %s has been added to Plex." % str(item['rating_key']))
|
||||||
# Fire off notifications
|
|
||||||
threading.Thread(target=notification_handler.notify_timeline,
|
# Check if any notification agents have notifications enabled
|
||||||
kwargs=dict(timeline_data=item, notify_action='created')).start()
|
if any(d['on_created'] for d in notifiers.available_notification_agents()):
|
||||||
|
# Fire off notifications
|
||||||
|
threading.Thread(target=notification_handler.notify_timeline,
|
||||||
|
kwargs=dict(timeline_data=item, notify_action='created')).start()
|
||||||
|
|
||||||
else:
|
else:
|
||||||
item = max(metadata, key=lambda x:x['added_at'])
|
item = max(metadata, key=lambda x:x['added_at'])
|
||||||
|
@ -243,9 +292,12 @@ def check_recently_added():
|
||||||
% str(item['rating_key']))
|
% str(item['rating_key']))
|
||||||
|
|
||||||
logger.debug(u"PlexPy Monitor :: Library item %s has been added to Plex." % str(item['rating_key']))
|
logger.debug(u"PlexPy Monitor :: Library item %s has been added to Plex." % str(item['rating_key']))
|
||||||
# Fire off notifications
|
|
||||||
threading.Thread(target=notification_handler.notify_timeline,
|
# Check if any notification agents have notifications enabled
|
||||||
kwargs=dict(timeline_data=item, notify_action='created')).start()
|
if any(d['on_created'] for d in notifiers.available_notification_agents()):
|
||||||
|
# Fire off notifications
|
||||||
|
threading.Thread(target=notification_handler.notify_timeline,
|
||||||
|
kwargs=dict(timeline_data=item, notify_action='created')).start()
|
||||||
|
|
||||||
def check_server_response():
|
def check_server_response():
|
||||||
|
|
||||||
|
@ -275,12 +327,44 @@ def check_server_response():
|
||||||
else:
|
else:
|
||||||
if ext_ping_count >= 3:
|
if ext_ping_count >= 3:
|
||||||
logger.info(u"PlexPy Monitor :: Plex remote access is back up.")
|
logger.info(u"PlexPy Monitor :: Plex remote access is back up.")
|
||||||
# Fire off notifications
|
|
||||||
threading.Thread(target=notification_handler.notify_timeline,
|
# Check if any notification agents have notifications enabled
|
||||||
kwargs=dict(notify_action='extup')).start()
|
if any(d['on_extup'] for d in notifiers.available_notification_agents()):
|
||||||
|
# Fire off notifications
|
||||||
|
threading.Thread(target=notification_handler.notify_timeline,
|
||||||
|
kwargs=dict(notify_action='extup')).start()
|
||||||
ext_ping_count = 0
|
ext_ping_count = 0
|
||||||
|
|
||||||
if ext_ping_count == 3:
|
if ext_ping_count == 3:
|
||||||
# Fire off notifications
|
# Check if any notification agents have notifications enabled
|
||||||
threading.Thread(target=notification_handler.notify_timeline,
|
if any(d['on_extdown'] for d in notifiers.available_notification_agents()):
|
||||||
kwargs=dict(notify_action='extdown')).start()
|
# Fire off notifications
|
||||||
|
threading.Thread(target=notification_handler.notify_timeline,
|
||||||
|
kwargs=dict(notify_action='extdown')).start()
|
||||||
|
|
||||||
|
|
||||||
|
def check_server_updates():
|
||||||
|
|
||||||
|
with monitor_lock:
|
||||||
|
logger.info(u"PlexPy Monitor :: Checking for PMS updates...")
|
||||||
|
|
||||||
|
pms_connect = pmsconnect.PmsConnect()
|
||||||
|
|
||||||
|
server_identity = pms_connect.get_server_identity()
|
||||||
|
update_status = pms_connect.get_update_staus()
|
||||||
|
|
||||||
|
if server_identity and update_status:
|
||||||
|
version = server_identity['version']
|
||||||
|
logger.info(u"PlexPy Monitor :: Current PMS version: %s", version)
|
||||||
|
|
||||||
|
if update_status['state'] == 'available':
|
||||||
|
update_version = update_status['version']
|
||||||
|
logger.info(u"PlexPy Monitor :: PMS update available version: %s", update_version)
|
||||||
|
|
||||||
|
# Check if any notification agents have notifications enabled
|
||||||
|
if any(d['on_pmsupdate'] for d in notifiers.available_notification_agents()):
|
||||||
|
# Fire off notifications
|
||||||
|
threading.Thread(target=notification_handler.notify_timeline,
|
||||||
|
kwargs=dict(notify_action='pmsupdate')).start()
|
||||||
|
else:
|
||||||
|
logger.info(u"PlexPy Monitor :: No PMS update available.")
|
|
@ -13,7 +13,7 @@
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
|
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
from plexpy import logger, pmsconnect, notification_handler, log_reader, database
|
from plexpy import logger, pmsconnect, notification_handler, log_reader, database, notifiers
|
||||||
|
|
||||||
import threading
|
import threading
|
||||||
import plexpy
|
import plexpy
|
||||||
|
@ -78,9 +78,10 @@ class ActivityProcessor(object):
|
||||||
result = self.db.upsert('sessions', values, keys)
|
result = self.db.upsert('sessions', values, keys)
|
||||||
|
|
||||||
if result == 'insert':
|
if result == 'insert':
|
||||||
# Push any notifications - Push it on it's own thread so we don't hold up our db actions
|
# Check if any notification agents have notifications enabled
|
||||||
if notify:
|
if notify and any(d['on_play'] for d in notifiers.available_notification_agents()):
|
||||||
values.update({'ip_address': session['ip_address']})
|
values.update({'ip_address': session['ip_address']})
|
||||||
|
# Push any notifications - Push it on it's own thread so we don't hold up our db actions
|
||||||
threading.Thread(target=notification_handler.notify,
|
threading.Thread(target=notification_handler.notify,
|
||||||
kwargs=dict(stream_data=values, notify_action='play')).start()
|
kwargs=dict(stream_data=values, notify_action='play')).start()
|
||||||
|
|
||||||
|
@ -97,16 +98,23 @@ class ActivityProcessor(object):
|
||||||
ip_address = {'ip_address': ip_address}
|
ip_address = {'ip_address': ip_address}
|
||||||
self.db.upsert('sessions', ip_address, keys)
|
self.db.upsert('sessions', ip_address, keys)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
def write_session_history(self, session=None, import_metadata=None, is_import=False, import_ignore_interval=0):
|
def write_session_history(self, session=None, import_metadata=None, is_import=False, import_ignore_interval=0):
|
||||||
from plexpy import users, libraries
|
from plexpy import users, libraries
|
||||||
|
|
||||||
user_data = users.Users()
|
|
||||||
user_details = user_data.get_details(user_id=session['user_id'])
|
|
||||||
|
|
||||||
section_id = session['section_id'] if not is_import else import_metadata['section_id']
|
section_id = session['section_id'] if not is_import else import_metadata['section_id']
|
||||||
|
|
||||||
library_data = libraries.Libraries()
|
if not is_import:
|
||||||
library_details = library_data.get_details(section_id=section_id)
|
user_data = users.Users()
|
||||||
|
user_details = user_data.get_details(user_id=session['user_id'])
|
||||||
|
|
||||||
|
library_data = libraries.Libraries()
|
||||||
|
library_details = library_data.get_details(section_id=section_id)
|
||||||
|
|
||||||
|
# Return false if failed to retrieve user or library details
|
||||||
|
if not user_details or not library_details:
|
||||||
|
return False
|
||||||
|
|
||||||
if session:
|
if session:
|
||||||
logging_enabled = False
|
logging_enabled = False
|
||||||
|
@ -116,8 +124,14 @@ class ActivityProcessor(object):
|
||||||
stopped = int(session['stopped'])
|
stopped = int(session['stopped'])
|
||||||
else:
|
else:
|
||||||
stopped = int(time.time())
|
stopped = int(time.time())
|
||||||
|
elif session['stopped']:
|
||||||
|
stopped = int(session['stopped'])
|
||||||
else:
|
else:
|
||||||
stopped = int(time.time())
|
stopped = int(time.time())
|
||||||
|
self.set_session_state(session_key=session['session_key'],
|
||||||
|
state='stopped',
|
||||||
|
view_offset=session['viewOffset'],
|
||||||
|
stopped=stopped)
|
||||||
|
|
||||||
if plexpy.CONFIG.MOVIE_LOGGING_ENABLE and str(session['rating_key']).isdigit() and \
|
if plexpy.CONFIG.MOVIE_LOGGING_ENABLE and str(session['rating_key']).isdigit() and \
|
||||||
session['media_type'] == 'movie':
|
session['media_type'] == 'movie':
|
||||||
|
@ -137,14 +151,14 @@ class ActivityProcessor(object):
|
||||||
else:
|
else:
|
||||||
real_play_time = stopped - session['started']
|
real_play_time = stopped - session['started']
|
||||||
|
|
||||||
if plexpy.CONFIG.LOGGING_IGNORE_INTERVAL and not is_import:
|
if not is_import and plexpy.CONFIG.LOGGING_IGNORE_INTERVAL:
|
||||||
if (session['media_type'] == 'movie' or session['media_type'] == 'episode') and \
|
if (session['media_type'] == 'movie' or session['media_type'] == 'episode') and \
|
||||||
(real_play_time < int(plexpy.CONFIG.LOGGING_IGNORE_INTERVAL)):
|
(real_play_time < int(plexpy.CONFIG.LOGGING_IGNORE_INTERVAL)):
|
||||||
logging_enabled = False
|
logging_enabled = False
|
||||||
logger.debug(u"PlexPy ActivityProcessor :: Play duration for ratingKey %s is %s secs which is less than %s "
|
logger.debug(u"PlexPy ActivityProcessor :: Play duration for ratingKey %s is %s secs which is less than %s "
|
||||||
u"seconds, so we're not logging it." %
|
u"seconds, so we're not logging it." %
|
||||||
(session['rating_key'], str(real_play_time), plexpy.CONFIG.LOGGING_IGNORE_INTERVAL))
|
(session['rating_key'], str(real_play_time), plexpy.CONFIG.LOGGING_IGNORE_INTERVAL))
|
||||||
if session['media_type'] == 'track' and not is_import:
|
if not is_import and session['media_type'] == 'track':
|
||||||
if real_play_time < 15 and session['duration'] >= 30:
|
if real_play_time < 15 and session['duration'] >= 30:
|
||||||
logging_enabled = False
|
logging_enabled = False
|
||||||
logger.debug(u"PlexPy ActivityProcessor :: Play duration for ratingKey %s is %s secs, "
|
logger.debug(u"PlexPy ActivityProcessor :: Play duration for ratingKey %s is %s secs, "
|
||||||
|
@ -156,17 +170,29 @@ class ActivityProcessor(object):
|
||||||
logging_enabled = False
|
logging_enabled = False
|
||||||
logger.debug(u"PlexPy ActivityProcessor :: Play duration for ratingKey %s is %s secs which is less than %s "
|
logger.debug(u"PlexPy ActivityProcessor :: Play duration for ratingKey %s is %s secs which is less than %s "
|
||||||
u"seconds, so we're not logging it." %
|
u"seconds, so we're not logging it." %
|
||||||
(session['rating_key'], str(real_play_time),
|
(session['rating_key'], str(real_play_time), import_ignore_interval))
|
||||||
import_ignore_interval))
|
|
||||||
|
|
||||||
if not user_details['keep_history'] and not is_import:
|
if not is_import and not user_details['keep_history']:
|
||||||
logging_enabled = False
|
logging_enabled = False
|
||||||
logger.debug(u"PlexPy ActivityProcessor :: History logging for user '%s' is disabled." % user_details['username'])
|
logger.debug(u"PlexPy ActivityProcessor :: History logging for user '%s' is disabled." % user_details['username'])
|
||||||
elif not library_details['keep_history'] and not is_import:
|
elif not is_import and not library_details['keep_history']:
|
||||||
logging_enabled = False
|
logging_enabled = False
|
||||||
logger.debug(u"PlexPy ActivityProcessor :: History logging for library '%s' is disabled." % library_details['section_name'])
|
logger.debug(u"PlexPy ActivityProcessor :: History logging for library '%s' is disabled." % library_details['section_name'])
|
||||||
|
|
||||||
if logging_enabled:
|
if logging_enabled:
|
||||||
|
|
||||||
|
# Fetch metadata first so we can return false if it fails
|
||||||
|
if not is_import:
|
||||||
|
logger.debug(u"PlexPy ActivityProcessor :: Fetching metadata for item ratingKey %s" % session['rating_key'])
|
||||||
|
pms_connect = pmsconnect.PmsConnect()
|
||||||
|
result = pms_connect.get_metadata_details(rating_key=str(session['rating_key']))
|
||||||
|
if result:
|
||||||
|
metadata = result['metadata']
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
metadata = import_metadata
|
||||||
|
|
||||||
# logger.debug(u"PlexPy ActivityProcessor :: Attempting to write to session_history table...")
|
# logger.debug(u"PlexPy ActivityProcessor :: Attempting to write to session_history table...")
|
||||||
query = 'INSERT INTO session_history (started, stopped, rating_key, parent_rating_key, ' \
|
query = 'INSERT INTO session_history (started, stopped, rating_key, parent_rating_key, ' \
|
||||||
'grandparent_rating_key, media_type, user_id, user, ip_address, paused_counter, player, ' \
|
'grandparent_rating_key, media_type, user_id, user, ip_address, paused_counter, player, ' \
|
||||||
|
@ -218,13 +244,22 @@ class ActivityProcessor(object):
|
||||||
# % last_id)
|
# % last_id)
|
||||||
|
|
||||||
# Write the session_history_media_info table
|
# Write the session_history_media_info table
|
||||||
|
|
||||||
|
# Generate a combined transcode decision value
|
||||||
|
if session['video_decision'] == 'transcode' or session['audio_decision'] == 'transcode':
|
||||||
|
transcode_decision = 'transcode'
|
||||||
|
elif session['video_decision'] == 'copy' or session['audio_decision'] == 'copy':
|
||||||
|
transcode_decision = 'copy'
|
||||||
|
else:
|
||||||
|
transcode_decision = 'direct play'
|
||||||
|
|
||||||
# logger.debug(u"PlexPy ActivityProcessor :: Attempting to write to session_history_media_info table...")
|
# logger.debug(u"PlexPy ActivityProcessor :: Attempting to write to session_history_media_info table...")
|
||||||
query = 'INSERT INTO session_history_media_info (id, rating_key, video_decision, audio_decision, ' \
|
query = 'INSERT INTO session_history_media_info (id, rating_key, video_decision, audio_decision, ' \
|
||||||
'duration, width, height, container, video_codec, audio_codec, bitrate, video_resolution, ' \
|
'duration, width, height, container, video_codec, audio_codec, bitrate, video_resolution, ' \
|
||||||
'video_framerate, aspect_ratio, audio_channels, transcode_protocol, transcode_container, ' \
|
'video_framerate, aspect_ratio, audio_channels, transcode_protocol, transcode_container, ' \
|
||||||
'transcode_video_codec, transcode_audio_codec, transcode_audio_channels, transcode_width, ' \
|
'transcode_video_codec, transcode_audio_codec, transcode_audio_channels, transcode_width, ' \
|
||||||
'transcode_height) VALUES ' \
|
'transcode_height, transcode_decision) VALUES ' \
|
||||||
'(last_insert_rowid(), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'
|
'(last_insert_rowid(), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'
|
||||||
|
|
||||||
args = [session['rating_key'], session['video_decision'], session['audio_decision'],
|
args = [session['rating_key'], session['video_decision'], session['audio_decision'],
|
||||||
session['duration'], session['width'], session['height'], session['container'],
|
session['duration'], session['width'], session['height'], session['container'],
|
||||||
|
@ -232,19 +267,12 @@ class ActivityProcessor(object):
|
||||||
session['video_resolution'], session['video_framerate'], session['aspect_ratio'],
|
session['video_resolution'], session['video_framerate'], session['aspect_ratio'],
|
||||||
session['audio_channels'], session['transcode_protocol'], session['transcode_container'],
|
session['audio_channels'], session['transcode_protocol'], session['transcode_container'],
|
||||||
session['transcode_video_codec'], session['transcode_audio_codec'],
|
session['transcode_video_codec'], session['transcode_audio_codec'],
|
||||||
session['transcode_audio_channels'], session['transcode_width'], session['transcode_height']]
|
session['transcode_audio_channels'], session['transcode_width'], session['transcode_height'],
|
||||||
|
transcode_decision]
|
||||||
|
|
||||||
# logger.debug(u"PlexPy ActivityProcessor :: Writing session_history_media_info transaction...")
|
# logger.debug(u"PlexPy ActivityProcessor :: Writing session_history_media_info transaction...")
|
||||||
self.db.action(query=query, args=args)
|
self.db.action(query=query, args=args)
|
||||||
|
|
||||||
if not is_import:
|
|
||||||
logger.debug(u"PlexPy ActivityProcessor :: Fetching metadata for item ratingKey %s" % session['rating_key'])
|
|
||||||
pms_connect = pmsconnect.PmsConnect()
|
|
||||||
result = pms_connect.get_metadata_details(rating_key=str(session['rating_key']))
|
|
||||||
metadata = result['metadata']
|
|
||||||
else:
|
|
||||||
metadata = import_metadata
|
|
||||||
|
|
||||||
# Write the session_history_metadata table
|
# Write the session_history_metadata table
|
||||||
directors = ";".join(metadata['directors'])
|
directors = ";".join(metadata['directors'])
|
||||||
writers = ";".join(metadata['writers'])
|
writers = ";".join(metadata['writers'])
|
||||||
|
@ -280,6 +308,9 @@ class ActivityProcessor(object):
|
||||||
# logger.debug(u"PlexPy ActivityProcessor :: Writing session_history_metadata transaction...")
|
# logger.debug(u"PlexPy ActivityProcessor :: Writing session_history_metadata transaction...")
|
||||||
self.db.action(query=query, args=args)
|
self.db.action(query=query, args=args)
|
||||||
|
|
||||||
|
# Return true when the session is successfully written to the database
|
||||||
|
return True
|
||||||
|
|
||||||
def find_session_ip(self, rating_key=None, machine_id=None):
|
def find_session_ip(self, rating_key=None, machine_id=None):
|
||||||
|
|
||||||
logger.debug(u"PlexPy ActivityProcessor :: Requesting log lines...")
|
logger.debug(u"PlexPy ActivityProcessor :: Requesting log lines...")
|
||||||
|
@ -351,12 +382,15 @@ class ActivityProcessor(object):
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def set_session_state(self, session_key=None, state=None, view_offset=0):
|
def set_session_state(self, session_key=None, state=None, view_offset=0, **kwargs):
|
||||||
if str(session_key).isdigit() and str(view_offset).isdigit():
|
if str(session_key).isdigit() and str(view_offset).isdigit():
|
||||||
values = {'view_offset': int(view_offset)}
|
values = {'view_offset': int(view_offset)}
|
||||||
if state:
|
if state:
|
||||||
values['state'] = state
|
values['state'] = state
|
||||||
|
|
||||||
|
for k,v in kwargs.iteritems():
|
||||||
|
values[k] = v
|
||||||
|
|
||||||
keys = {'session_key': session_key}
|
keys = {'session_key': session_key}
|
||||||
result = self.db.upsert('sessions', values, keys)
|
result = self.db.upsert('sessions', values, keys)
|
||||||
|
|
||||||
|
|
|
@ -62,6 +62,7 @@ MEDIA_FLAGS_VIDEO = {'avc1': 'h264',
|
||||||
SCHEDULER_LIST = ['Check GitHub for updates',
|
SCHEDULER_LIST = ['Check GitHub for updates',
|
||||||
'Check for active sessions',
|
'Check for active sessions',
|
||||||
'Check for recently added items',
|
'Check for recently added items',
|
||||||
|
'Check for Plex updates',
|
||||||
'Check for Plex remote access',
|
'Check for Plex remote access',
|
||||||
'Refresh users list',
|
'Refresh users list',
|
||||||
'Refresh libraries list',
|
'Refresh libraries list',
|
||||||
|
|
|
@ -48,6 +48,7 @@ _CONFIG_DEFINITIONS = {
|
||||||
'BOXCAR_ON_INTDOWN': (int, 'Boxcar', 0),
|
'BOXCAR_ON_INTDOWN': (int, 'Boxcar', 0),
|
||||||
'BOXCAR_ON_EXTUP': (int, 'Boxcar', 0),
|
'BOXCAR_ON_EXTUP': (int, 'Boxcar', 0),
|
||||||
'BOXCAR_ON_INTUP': (int, 'Boxcar', 0),
|
'BOXCAR_ON_INTUP': (int, 'Boxcar', 0),
|
||||||
|
'BOXCAR_ON_PMSUPDATE': (int, 'Boxcar', 0),
|
||||||
'BUFFER_THRESHOLD': (int, 'Monitoring', 3),
|
'BUFFER_THRESHOLD': (int, 'Monitoring', 3),
|
||||||
'BUFFER_WAIT': (int, 'Monitoring', 900),
|
'BUFFER_WAIT': (int, 'Monitoring', 900),
|
||||||
'BACKUP_DIR': (str, 'General', ''),
|
'BACKUP_DIR': (str, 'General', ''),
|
||||||
|
@ -81,6 +82,7 @@ _CONFIG_DEFINITIONS = {
|
||||||
'EMAIL_ON_INTDOWN': (int, 'Email', 0),
|
'EMAIL_ON_INTDOWN': (int, 'Email', 0),
|
||||||
'EMAIL_ON_EXTUP': (int, 'Email', 0),
|
'EMAIL_ON_EXTUP': (int, 'Email', 0),
|
||||||
'EMAIL_ON_INTUP': (int, 'Email', 0),
|
'EMAIL_ON_INTUP': (int, 'Email', 0),
|
||||||
|
'EMAIL_ON_PMSUPDATE': (int, 'Email', 0),
|
||||||
'ENABLE_HTTPS': (int, 'General', 0),
|
'ENABLE_HTTPS': (int, 'General', 0),
|
||||||
'FACEBOOK_ENABLED': (int, 'Facebook', 0),
|
'FACEBOOK_ENABLED': (int, 'Facebook', 0),
|
||||||
'FACEBOOK_REDIRECT_URI': (str, 'Facebook', ''),
|
'FACEBOOK_REDIRECT_URI': (str, 'Facebook', ''),
|
||||||
|
@ -88,6 +90,7 @@ _CONFIG_DEFINITIONS = {
|
||||||
'FACEBOOK_APP_SECRET': (str, 'Facebook', ''),
|
'FACEBOOK_APP_SECRET': (str, 'Facebook', ''),
|
||||||
'FACEBOOK_TOKEN': (str, 'Facebook', ''),
|
'FACEBOOK_TOKEN': (str, 'Facebook', ''),
|
||||||
'FACEBOOK_GROUP': (str, 'Facebook', ''),
|
'FACEBOOK_GROUP': (str, 'Facebook', ''),
|
||||||
|
'FACEBOOK_INCL_PMSLINK': (int, 'Facebook', 0),
|
||||||
'FACEBOOK_INCL_POSTER': (int, 'Facebook', 1),
|
'FACEBOOK_INCL_POSTER': (int, 'Facebook', 1),
|
||||||
'FACEBOOK_INCL_SUBJECT': (int, 'Facebook', 1),
|
'FACEBOOK_INCL_SUBJECT': (int, 'Facebook', 1),
|
||||||
'FACEBOOK_ON_PLAY': (int, 'Facebook', 0),
|
'FACEBOOK_ON_PLAY': (int, 'Facebook', 0),
|
||||||
|
@ -101,6 +104,7 @@ _CONFIG_DEFINITIONS = {
|
||||||
'FACEBOOK_ON_INTDOWN': (int, 'Facebook', 0),
|
'FACEBOOK_ON_INTDOWN': (int, 'Facebook', 0),
|
||||||
'FACEBOOK_ON_EXTUP': (int, 'Facebook', 0),
|
'FACEBOOK_ON_EXTUP': (int, 'Facebook', 0),
|
||||||
'FACEBOOK_ON_INTUP': (int, 'Facebook', 0),
|
'FACEBOOK_ON_INTUP': (int, 'Facebook', 0),
|
||||||
|
'FACEBOOK_ON_PMSUPDATE': (int, 'Facebook', 0),
|
||||||
'FIRST_RUN_COMPLETE': (int, 'General', 0),
|
'FIRST_RUN_COMPLETE': (int, 'General', 0),
|
||||||
'FREEZE_DB': (int, 'General', 0),
|
'FREEZE_DB': (int, 'General', 0),
|
||||||
'GET_FILE_SIZES': (int, 'General', 0),
|
'GET_FILE_SIZES': (int, 'General', 0),
|
||||||
|
@ -126,6 +130,7 @@ _CONFIG_DEFINITIONS = {
|
||||||
'GROWL_ON_INTDOWN': (int, 'Growl', 0),
|
'GROWL_ON_INTDOWN': (int, 'Growl', 0),
|
||||||
'GROWL_ON_EXTUP': (int, 'Growl', 0),
|
'GROWL_ON_EXTUP': (int, 'Growl', 0),
|
||||||
'GROWL_ON_INTUP': (int, 'Growl', 0),
|
'GROWL_ON_INTUP': (int, 'Growl', 0),
|
||||||
|
'GROWL_ON_PMSUPDATE': (int, 'Growl', 0),
|
||||||
'HOME_LIBRARY_CARDS': (list, 'General', ['first_run']),
|
'HOME_LIBRARY_CARDS': (list, 'General', ['first_run']),
|
||||||
'HOME_STATS_LENGTH': (int, 'General', 30),
|
'HOME_STATS_LENGTH': (int, 'General', 30),
|
||||||
'HOME_STATS_TYPE': (int, 'General', 0),
|
'HOME_STATS_TYPE': (int, 'General', 0),
|
||||||
|
@ -159,6 +164,7 @@ _CONFIG_DEFINITIONS = {
|
||||||
'IFTTT_ON_INTDOWN': (int, 'IFTTT', 0),
|
'IFTTT_ON_INTDOWN': (int, 'IFTTT', 0),
|
||||||
'IFTTT_ON_EXTUP': (int, 'IFTTT', 0),
|
'IFTTT_ON_EXTUP': (int, 'IFTTT', 0),
|
||||||
'IFTTT_ON_INTUP': (int, 'IFTTT', 0),
|
'IFTTT_ON_INTUP': (int, 'IFTTT', 0),
|
||||||
|
'IFTTT_ON_PMSUPDATE': (int, 'IFTTT', 0),
|
||||||
'JOURNAL_MODE': (str, 'Advanced', 'wal'),
|
'JOURNAL_MODE': (str, 'Advanced', 'wal'),
|
||||||
'LAUNCH_BROWSER': (int, 'General', 1),
|
'LAUNCH_BROWSER': (int, 'General', 1),
|
||||||
'LOG_DIR': (str, 'General', ''),
|
'LOG_DIR': (str, 'General', ''),
|
||||||
|
@ -173,6 +179,7 @@ _CONFIG_DEFINITIONS = {
|
||||||
'MUSIC_NOTIFY_ON_START': (int, 'Monitoring', 1),
|
'MUSIC_NOTIFY_ON_START': (int, 'Monitoring', 1),
|
||||||
'MUSIC_NOTIFY_ON_STOP': (int, 'Monitoring', 0),
|
'MUSIC_NOTIFY_ON_STOP': (int, 'Monitoring', 0),
|
||||||
'MUSIC_NOTIFY_ON_PAUSE': (int, 'Monitoring', 0),
|
'MUSIC_NOTIFY_ON_PAUSE': (int, 'Monitoring', 0),
|
||||||
|
'MONITOR_PMS_UPDATES': (int, 'Monitoring', 0),
|
||||||
'MONITOR_REMOTE_ACCESS': (int, 'Monitoring', 0),
|
'MONITOR_REMOTE_ACCESS': (int, 'Monitoring', 0),
|
||||||
'MONITORING_INTERVAL': (int, 'Monitoring', 60),
|
'MONITORING_INTERVAL': (int, 'Monitoring', 60),
|
||||||
'MONITORING_USE_WEBSOCKET': (int, 'Monitoring', 0),
|
'MONITORING_USE_WEBSOCKET': (int, 'Monitoring', 0),
|
||||||
|
@ -190,6 +197,7 @@ _CONFIG_DEFINITIONS = {
|
||||||
'NMA_ON_INTDOWN': (int, 'NMA', 0),
|
'NMA_ON_INTDOWN': (int, 'NMA', 0),
|
||||||
'NMA_ON_EXTUP': (int, 'NMA', 0),
|
'NMA_ON_EXTUP': (int, 'NMA', 0),
|
||||||
'NMA_ON_INTUP': (int, 'NMA', 0),
|
'NMA_ON_INTUP': (int, 'NMA', 0),
|
||||||
|
'NMA_ON_PMSUPDATE': (int, 'NMA', 0),
|
||||||
'NOTIFY_CONSECUTIVE': (int, 'Monitoring', 1),
|
'NOTIFY_CONSECUTIVE': (int, 'Monitoring', 1),
|
||||||
'NOTIFY_UPLOAD_POSTERS': (int, 'Monitoring', 0),
|
'NOTIFY_UPLOAD_POSTERS': (int, 'Monitoring', 0),
|
||||||
'NOTIFY_RECENTLY_ADDED': (int, 'Monitoring', 0),
|
'NOTIFY_RECENTLY_ADDED': (int, 'Monitoring', 0),
|
||||||
|
@ -218,6 +226,8 @@ _CONFIG_DEFINITIONS = {
|
||||||
'NOTIFY_ON_EXTUP_BODY_TEXT': (unicode, 'Monitoring', 'The Plex Media Server remote access is back up.'),
|
'NOTIFY_ON_EXTUP_BODY_TEXT': (unicode, 'Monitoring', 'The Plex Media Server remote access is back up.'),
|
||||||
'NOTIFY_ON_INTUP_SUBJECT_TEXT': (unicode, 'Monitoring', 'PlexPy ({server_name})'),
|
'NOTIFY_ON_INTUP_SUBJECT_TEXT': (unicode, 'Monitoring', 'PlexPy ({server_name})'),
|
||||||
'NOTIFY_ON_INTUP_BODY_TEXT': (unicode, 'Monitoring', 'The Plex Media Server is back up.'),
|
'NOTIFY_ON_INTUP_BODY_TEXT': (unicode, 'Monitoring', 'The Plex Media Server is back up.'),
|
||||||
|
'NOTIFY_ON_PMSUPDATE_SUBJECT_TEXT': (unicode, 'Monitoring', 'PlexPy ({server_name})'),
|
||||||
|
'NOTIFY_ON_PMSUPDATE_BODY_TEXT': (unicode, 'Monitoring', 'An update is available for the Plex Media Server (version {update_version}).'),
|
||||||
'NOTIFY_SCRIPTS_ARGS_TEXT': (unicode, 'Monitoring', ''),
|
'NOTIFY_SCRIPTS_ARGS_TEXT': (unicode, 'Monitoring', ''),
|
||||||
'OSX_NOTIFY_APP': (str, 'OSX_Notify', '/Applications/PlexPy'),
|
'OSX_NOTIFY_APP': (str, 'OSX_Notify', '/Applications/PlexPy'),
|
||||||
'OSX_NOTIFY_ENABLED': (int, 'OSX_Notify', 0),
|
'OSX_NOTIFY_ENABLED': (int, 'OSX_Notify', 0),
|
||||||
|
@ -232,6 +242,7 @@ _CONFIG_DEFINITIONS = {
|
||||||
'OSX_NOTIFY_ON_INTDOWN': (int, 'OSX_Notify', 0),
|
'OSX_NOTIFY_ON_INTDOWN': (int, 'OSX_Notify', 0),
|
||||||
'OSX_NOTIFY_ON_EXTUP': (int, 'OSX_Notify', 0),
|
'OSX_NOTIFY_ON_EXTUP': (int, 'OSX_Notify', 0),
|
||||||
'OSX_NOTIFY_ON_INTUP': (int, 'OSX_Notify', 0),
|
'OSX_NOTIFY_ON_INTUP': (int, 'OSX_Notify', 0),
|
||||||
|
'OSX_NOTIFY_ON_PMSUPDATE': (int, 'OSX_Notify', 0),
|
||||||
'PLEX_CLIENT_HOST': (str, 'Plex', ''),
|
'PLEX_CLIENT_HOST': (str, 'Plex', ''),
|
||||||
'PLEX_ENABLED': (int, 'Plex', 0),
|
'PLEX_ENABLED': (int, 'Plex', 0),
|
||||||
'PLEX_PASSWORD': (str, 'Plex', ''),
|
'PLEX_PASSWORD': (str, 'Plex', ''),
|
||||||
|
@ -247,6 +258,7 @@ _CONFIG_DEFINITIONS = {
|
||||||
'PLEX_ON_INTDOWN': (int, 'Plex', 0),
|
'PLEX_ON_INTDOWN': (int, 'Plex', 0),
|
||||||
'PLEX_ON_EXTUP': (int, 'Plex', 0),
|
'PLEX_ON_EXTUP': (int, 'Plex', 0),
|
||||||
'PLEX_ON_INTUP': (int, 'Plex', 0),
|
'PLEX_ON_INTUP': (int, 'Plex', 0),
|
||||||
|
'PLEX_ON_PMSUPDATE': (int, 'Plex', 0),
|
||||||
'PROWL_ENABLED': (int, 'Prowl', 0),
|
'PROWL_ENABLED': (int, 'Prowl', 0),
|
||||||
'PROWL_KEYS': (str, 'Prowl', ''),
|
'PROWL_KEYS': (str, 'Prowl', ''),
|
||||||
'PROWL_PRIORITY': (int, 'Prowl', 0),
|
'PROWL_PRIORITY': (int, 'Prowl', 0),
|
||||||
|
@ -261,6 +273,7 @@ _CONFIG_DEFINITIONS = {
|
||||||
'PROWL_ON_INTDOWN': (int, 'Prowl', 0),
|
'PROWL_ON_INTDOWN': (int, 'Prowl', 0),
|
||||||
'PROWL_ON_EXTUP': (int, 'Prowl', 0),
|
'PROWL_ON_EXTUP': (int, 'Prowl', 0),
|
||||||
'PROWL_ON_INTUP': (int, 'Prowl', 0),
|
'PROWL_ON_INTUP': (int, 'Prowl', 0),
|
||||||
|
'PROWL_ON_PMSUPDATE': (int, 'Prowl', 0),
|
||||||
'PUSHALOT_APIKEY': (str, 'Pushalot', ''),
|
'PUSHALOT_APIKEY': (str, 'Pushalot', ''),
|
||||||
'PUSHALOT_ENABLED': (int, 'Pushalot', 0),
|
'PUSHALOT_ENABLED': (int, 'Pushalot', 0),
|
||||||
'PUSHALOT_ON_PLAY': (int, 'Pushalot', 0),
|
'PUSHALOT_ON_PLAY': (int, 'Pushalot', 0),
|
||||||
|
@ -274,6 +287,7 @@ _CONFIG_DEFINITIONS = {
|
||||||
'PUSHALOT_ON_INTDOWN': (int, 'Pushalot', 0),
|
'PUSHALOT_ON_INTDOWN': (int, 'Pushalot', 0),
|
||||||
'PUSHALOT_ON_EXTUP': (int, 'Pushalot', 0),
|
'PUSHALOT_ON_EXTUP': (int, 'Pushalot', 0),
|
||||||
'PUSHALOT_ON_INTUP': (int, 'Pushalot', 0),
|
'PUSHALOT_ON_INTUP': (int, 'Pushalot', 0),
|
||||||
|
'PUSHALOT_ON_PMSUPDATE': (int, 'Pushalot', 0),
|
||||||
'PUSHBULLET_APIKEY': (str, 'PushBullet', ''),
|
'PUSHBULLET_APIKEY': (str, 'PushBullet', ''),
|
||||||
'PUSHBULLET_DEVICEID': (str, 'PushBullet', ''),
|
'PUSHBULLET_DEVICEID': (str, 'PushBullet', ''),
|
||||||
'PUSHBULLET_CHANNEL_TAG': (str, 'PushBullet', ''),
|
'PUSHBULLET_CHANNEL_TAG': (str, 'PushBullet', ''),
|
||||||
|
@ -289,6 +303,7 @@ _CONFIG_DEFINITIONS = {
|
||||||
'PUSHBULLET_ON_INTDOWN': (int, 'PushBullet', 0),
|
'PUSHBULLET_ON_INTDOWN': (int, 'PushBullet', 0),
|
||||||
'PUSHBULLET_ON_EXTUP': (int, 'PushBullet', 0),
|
'PUSHBULLET_ON_EXTUP': (int, 'PushBullet', 0),
|
||||||
'PUSHBULLET_ON_INTUP': (int, 'PushBullet', 0),
|
'PUSHBULLET_ON_INTUP': (int, 'PushBullet', 0),
|
||||||
|
'PUSHBULLET_ON_PMSUPDATE': (int, 'PushBullet', 0),
|
||||||
'PUSHOVER_APITOKEN': (str, 'Pushover', ''),
|
'PUSHOVER_APITOKEN': (str, 'Pushover', ''),
|
||||||
'PUSHOVER_ENABLED': (int, 'Pushover', 0),
|
'PUSHOVER_ENABLED': (int, 'Pushover', 0),
|
||||||
'PUSHOVER_HTML_SUPPORT': (int, 'Pushover', 1),
|
'PUSHOVER_HTML_SUPPORT': (int, 'Pushover', 1),
|
||||||
|
@ -306,6 +321,7 @@ _CONFIG_DEFINITIONS = {
|
||||||
'PUSHOVER_ON_INTDOWN': (int, 'Pushover', 0),
|
'PUSHOVER_ON_INTDOWN': (int, 'Pushover', 0),
|
||||||
'PUSHOVER_ON_EXTUP': (int, 'Pushover', 0),
|
'PUSHOVER_ON_EXTUP': (int, 'Pushover', 0),
|
||||||
'PUSHOVER_ON_INTUP': (int, 'Pushover', 0),
|
'PUSHOVER_ON_INTUP': (int, 'Pushover', 0),
|
||||||
|
'PUSHOVER_ON_PMSUPDATE': (int, 'Pushover', 0),
|
||||||
'REFRESH_LIBRARIES_INTERVAL': (int, 'Monitoring', 12),
|
'REFRESH_LIBRARIES_INTERVAL': (int, 'Monitoring', 12),
|
||||||
'REFRESH_LIBRARIES_ON_STARTUP': (int, 'Monitoring', 1),
|
'REFRESH_LIBRARIES_ON_STARTUP': (int, 'Monitoring', 1),
|
||||||
'REFRESH_USERS_INTERVAL': (int, 'Monitoring', 12),
|
'REFRESH_USERS_INTERVAL': (int, 'Monitoring', 12),
|
||||||
|
@ -327,6 +343,7 @@ _CONFIG_DEFINITIONS = {
|
||||||
'SLACK_ON_INTDOWN': (int, 'Slack', 0),
|
'SLACK_ON_INTDOWN': (int, 'Slack', 0),
|
||||||
'SLACK_ON_EXTUP': (int, 'Slack', 0),
|
'SLACK_ON_EXTUP': (int, 'Slack', 0),
|
||||||
'SLACK_ON_INTUP': (int, 'Slack', 0),
|
'SLACK_ON_INTUP': (int, 'Slack', 0),
|
||||||
|
'SLACK_ON_PMSUPDATE': (int, 'Slack', 0),
|
||||||
'SCRIPTS_ENABLED': (int, 'Scripts', 0),
|
'SCRIPTS_ENABLED': (int, 'Scripts', 0),
|
||||||
'SCRIPTS_FOLDER': (unicode, 'Scripts', ''),
|
'SCRIPTS_FOLDER': (unicode, 'Scripts', ''),
|
||||||
'SCRIPTS_ON_PLAY': (int, 'Scripts', 0),
|
'SCRIPTS_ON_PLAY': (int, 'Scripts', 0),
|
||||||
|
@ -340,6 +357,7 @@ _CONFIG_DEFINITIONS = {
|
||||||
'SCRIPTS_ON_EXTUP': (int, 'Scripts', 0),
|
'SCRIPTS_ON_EXTUP': (int, 'Scripts', 0),
|
||||||
'SCRIPTS_ON_INTDOWN': (int, 'Scripts', 0),
|
'SCRIPTS_ON_INTDOWN': (int, 'Scripts', 0),
|
||||||
'SCRIPTS_ON_INTUP': (int, 'Scripts', 0),
|
'SCRIPTS_ON_INTUP': (int, 'Scripts', 0),
|
||||||
|
'SCRIPTS_ON_PMSUPDATE': (int, 'Scripts', 0),
|
||||||
'SCRIPTS_ON_PLAY_SCRIPT': (unicode, 'Scripts', ''),
|
'SCRIPTS_ON_PLAY_SCRIPT': (unicode, 'Scripts', ''),
|
||||||
'SCRIPTS_ON_STOP_SCRIPT': (unicode, 'Scripts', ''),
|
'SCRIPTS_ON_STOP_SCRIPT': (unicode, 'Scripts', ''),
|
||||||
'SCRIPTS_ON_PAUSE_SCRIPT': (unicode, 'Scripts', ''),
|
'SCRIPTS_ON_PAUSE_SCRIPT': (unicode, 'Scripts', ''),
|
||||||
|
@ -351,6 +369,7 @@ _CONFIG_DEFINITIONS = {
|
||||||
'SCRIPTS_ON_EXTUP_SCRIPT': (unicode, 'Scripts', ''),
|
'SCRIPTS_ON_EXTUP_SCRIPT': (unicode, 'Scripts', ''),
|
||||||
'SCRIPTS_ON_INTDOWN_SCRIPT': (unicode, 'Scripts', ''),
|
'SCRIPTS_ON_INTDOWN_SCRIPT': (unicode, 'Scripts', ''),
|
||||||
'SCRIPTS_ON_INTUP_SCRIPT': (unicode, 'Scripts', ''),
|
'SCRIPTS_ON_INTUP_SCRIPT': (unicode, 'Scripts', ''),
|
||||||
|
'SCRIPTS_ON_PMSUPDATE_SCRIPT': (unicode, 'Scripts', ''),
|
||||||
'TELEGRAM_BOT_TOKEN': (str, 'Telegram', ''),
|
'TELEGRAM_BOT_TOKEN': (str, 'Telegram', ''),
|
||||||
'TELEGRAM_ENABLED': (int, 'Telegram', 0),
|
'TELEGRAM_ENABLED': (int, 'Telegram', 0),
|
||||||
'TELEGRAM_CHAT_ID': (str, 'Telegram', ''),
|
'TELEGRAM_CHAT_ID': (str, 'Telegram', ''),
|
||||||
|
@ -366,6 +385,7 @@ _CONFIG_DEFINITIONS = {
|
||||||
'TELEGRAM_ON_INTDOWN': (int, 'Telegram', 0),
|
'TELEGRAM_ON_INTDOWN': (int, 'Telegram', 0),
|
||||||
'TELEGRAM_ON_EXTUP': (int, 'Telegram', 0),
|
'TELEGRAM_ON_EXTUP': (int, 'Telegram', 0),
|
||||||
'TELEGRAM_ON_INTUP': (int, 'Telegram', 0),
|
'TELEGRAM_ON_INTUP': (int, 'Telegram', 0),
|
||||||
|
'TELEGRAM_ON_PMSUPDATE': (int, 'Telegram', 0),
|
||||||
'TV_LOGGING_ENABLE': (int, 'Monitoring', 1),
|
'TV_LOGGING_ENABLE': (int, 'Monitoring', 1),
|
||||||
'TV_NOTIFY_ENABLE': (int, 'Monitoring', 0),
|
'TV_NOTIFY_ENABLE': (int, 'Monitoring', 0),
|
||||||
'TV_NOTIFY_ON_START': (int, 'Monitoring', 1),
|
'TV_NOTIFY_ON_START': (int, 'Monitoring', 1),
|
||||||
|
@ -388,6 +408,7 @@ _CONFIG_DEFINITIONS = {
|
||||||
'TWITTER_ON_INTDOWN': (int, 'Twitter', 0),
|
'TWITTER_ON_INTDOWN': (int, 'Twitter', 0),
|
||||||
'TWITTER_ON_EXTUP': (int, 'Twitter', 0),
|
'TWITTER_ON_EXTUP': (int, 'Twitter', 0),
|
||||||
'TWITTER_ON_INTUP': (int, 'Twitter', 0),
|
'TWITTER_ON_INTUP': (int, 'Twitter', 0),
|
||||||
|
'TWITTER_ON_PMSUPDATE': (int, 'Twitter', 0),
|
||||||
'UPDATE_DB_INTERVAL': (int, 'General', 24),
|
'UPDATE_DB_INTERVAL': (int, 'General', 24),
|
||||||
'UPDATE_SECTION_IDS': (int, 'General', 1),
|
'UPDATE_SECTION_IDS': (int, 'General', 1),
|
||||||
'VERIFY_SSL_CERT': (bool_int, 'Advanced', 1),
|
'VERIFY_SSL_CERT': (bool_int, 'Advanced', 1),
|
||||||
|
@ -406,7 +427,8 @@ _CONFIG_DEFINITIONS = {
|
||||||
'XBMC_ON_EXTDOWN': (int, 'XBMC', 0),
|
'XBMC_ON_EXTDOWN': (int, 'XBMC', 0),
|
||||||
'XBMC_ON_INTDOWN': (int, 'XBMC', 0),
|
'XBMC_ON_INTDOWN': (int, 'XBMC', 0),
|
||||||
'XBMC_ON_EXTUP': (int, 'XBMC', 0),
|
'XBMC_ON_EXTUP': (int, 'XBMC', 0),
|
||||||
'XBMC_ON_INTUP': (int, 'XBMC', 0)
|
'XBMC_ON_INTUP': (int, 'XBMC', 0),
|
||||||
|
'XBMC_ON_PMSUPDATE': (int, 'XBMC', 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@ import os
|
||||||
import sqlite3
|
import sqlite3
|
||||||
import shutil
|
import shutil
|
||||||
import threading
|
import threading
|
||||||
|
import time
|
||||||
|
|
||||||
import logger
|
import logger
|
||||||
import plexpy
|
import plexpy
|
||||||
|
@ -37,9 +38,21 @@ def clear_history_tables():
|
||||||
monitor_db.action('DELETE FROM session_history')
|
monitor_db.action('DELETE FROM session_history')
|
||||||
monitor_db.action('DELETE FROM session_history_media_info')
|
monitor_db.action('DELETE FROM session_history_media_info')
|
||||||
monitor_db.action('DELETE FROM session_history_metadata')
|
monitor_db.action('DELETE FROM session_history_metadata')
|
||||||
monitor_db.action('VACUUM;')
|
monitor_db.action('VACUUM')
|
||||||
|
|
||||||
|
|
||||||
|
def delete_sessions():
|
||||||
|
logger.debug(u"PlexPy Database :: Clearing temporary sessions from database.")
|
||||||
|
monitor_db = MonitorDatabase()
|
||||||
|
|
||||||
|
try:
|
||||||
|
monitor_db.action('DELETE FROM sessions')
|
||||||
|
monitor_db.action('VACUUM')
|
||||||
|
return 'Cleared temporary sessions.'
|
||||||
|
except Exception as e:
|
||||||
|
logger.warn(u"PlexPy Database :: Unable to clear temporary sessions from database: %s." % e)
|
||||||
|
return 'Unable to clear temporary sessions.'
|
||||||
|
|
||||||
def db_filename(filename="plexpy.db"):
|
def db_filename(filename="plexpy.db"):
|
||||||
""" Returns the filepath to the db """
|
""" Returns the filepath to the db """
|
||||||
|
|
||||||
|
|
|
@ -58,11 +58,10 @@ class DataFactory(object):
|
||||||
'session_history_metadata.thumb',
|
'session_history_metadata.thumb',
|
||||||
'session_history_metadata.parent_thumb',
|
'session_history_metadata.parent_thumb',
|
||||||
'session_history_metadata.grandparent_thumb',
|
'session_history_metadata.grandparent_thumb',
|
||||||
'MAX((CASE WHEN view_offset IS NULL THEN 0.1 ELSE view_offset * 1.0 END) / \
|
'MAX((CASE WHEN (view_offset IS NULL OR view_offset = "") THEN 0.1 ELSE view_offset * 1.0 END) / \
|
||||||
(CASE WHEN session_history_metadata.duration IS NULL THEN 1.0 \
|
(CASE WHEN (session_history_metadata.duration IS NULL OR session_history_metadata.duration = "") \
|
||||||
ELSE session_history_metadata.duration * 1.0 END) * 100) AS percent_complete',
|
THEN 1.0 ELSE session_history_metadata.duration * 1.0 END) * 100) AS percent_complete',
|
||||||
'session_history_media_info.video_decision',
|
'session_history_media_info.transcode_decision',
|
||||||
'session_history_media_info.audio_decision',
|
|
||||||
'COUNT(*) AS group_count',
|
'COUNT(*) AS group_count',
|
||||||
'GROUP_CONCAT(session_history.id) AS group_ids'
|
'GROUP_CONCAT(session_history.id) AS group_ids'
|
||||||
]
|
]
|
||||||
|
@ -138,8 +137,7 @@ class DataFactory(object):
|
||||||
'media_index': item['media_index'],
|
'media_index': item['media_index'],
|
||||||
'parent_media_index': item['parent_media_index'],
|
'parent_media_index': item['parent_media_index'],
|
||||||
'thumb': thumb,
|
'thumb': thumb,
|
||||||
'video_decision': item['video_decision'],
|
'transcode_decision': item['transcode_decision'],
|
||||||
'audio_decision': item['audio_decision'],
|
|
||||||
'percent_complete': int(round(item['percent_complete'])),
|
'percent_complete': int(round(item['percent_complete'])),
|
||||||
'watched_status': watched_status,
|
'watched_status': watched_status,
|
||||||
'group_count': item['group_count'],
|
'group_count': item['group_count'],
|
||||||
|
@ -626,24 +624,21 @@ class DataFactory(object):
|
||||||
|
|
||||||
title = 'Concurrent Transcodes'
|
title = 'Concurrent Transcodes'
|
||||||
query = base_query \
|
query = base_query \
|
||||||
+ 'AND (session_history_media_info.video_decision = "transcode" ' \
|
+ 'AND session_history_media_info.transcode_decision = "transcode" '
|
||||||
'OR session_history_media_info.audio_decision = "transcode") '
|
|
||||||
result = monitor_db.select(query)
|
result = monitor_db.select(query)
|
||||||
if result:
|
if result:
|
||||||
most_concurrent.append(calc_most_concurrent(title, result))
|
most_concurrent.append(calc_most_concurrent(title, result))
|
||||||
|
|
||||||
title = 'Concurrent Direct Streams'
|
title = 'Concurrent Direct Streams'
|
||||||
query = base_query \
|
query = base_query \
|
||||||
+ 'AND (session_history_media_info.video_decision != "transcode" ' \
|
+ 'AND session_history_media_info.transcode_decision = "copy" '
|
||||||
'AND session_history_media_info.audio_decision = "copy") '
|
|
||||||
result = monitor_db.select(query)
|
result = monitor_db.select(query)
|
||||||
if result:
|
if result:
|
||||||
most_concurrent.append(calc_most_concurrent(title, result))
|
most_concurrent.append(calc_most_concurrent(title, result))
|
||||||
|
|
||||||
title = 'Concurrent Direct Plays'
|
title = 'Concurrent Direct Plays'
|
||||||
query = base_query \
|
query = base_query \
|
||||||
+ 'AND (session_history_media_info.video_decision = "direct play" ' \
|
+ 'AND session_history_media_info.transcode_decision = "direct play" '
|
||||||
'OR session_history_media_info.audio_decision = "direct play") '
|
|
||||||
result = monitor_db.select(query)
|
result = monitor_db.select(query)
|
||||||
if result:
|
if result:
|
||||||
most_concurrent.append(calc_most_concurrent(title, result))
|
most_concurrent.append(calc_most_concurrent(title, result))
|
||||||
|
@ -828,6 +823,7 @@ class DataFactory(object):
|
||||||
'SUM(CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) AS total_duration ' \
|
'SUM(CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) AS total_duration ' \
|
||||||
'FROM session_history ' \
|
'FROM session_history ' \
|
||||||
'JOIN session_history_metadata ON session_history_metadata.id = session_history.id ' \
|
'JOIN session_history_metadata ON session_history_metadata.id = session_history.id ' \
|
||||||
|
'JOIN session_history_media_info ON session_history_media_info.id = session_history.id ' \
|
||||||
'%s ' % where
|
'%s ' % where
|
||||||
result = monitor_db.select(query)
|
result = monitor_db.select(query)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
@ -860,16 +856,28 @@ class DataFactory(object):
|
||||||
|
|
||||||
return ip_address
|
return ip_address
|
||||||
|
|
||||||
def get_poster_url(self, rating_key=''):
|
def get_poster_url(self, rating_key='', metadata=None):
|
||||||
monitor_db = database.MonitorDatabase()
|
monitor_db = database.MonitorDatabase()
|
||||||
|
|
||||||
poster_url = ''
|
poster_url = ''
|
||||||
|
poster_key = ''
|
||||||
|
|
||||||
if rating_key:
|
if rating_key:
|
||||||
|
poster_key = rating_key
|
||||||
|
elif metadata:
|
||||||
|
if metadata['media_type'] == 'movie' or metadata['media_type'] == 'show' or \
|
||||||
|
metadata['media_type'] == 'artist' or metadata['media_type'] == 'album':
|
||||||
|
poster_key = metadata['rating_key']
|
||||||
|
elif metadata['media_type'] == 'episode':
|
||||||
|
poster_key = metadata['grandparent_rating_key']
|
||||||
|
elif metadata['media_type'] == 'season' or metadata['media_type'] == 'track':
|
||||||
|
poster_key = metadata['parent_rating_key']
|
||||||
|
|
||||||
|
if poster_key:
|
||||||
try:
|
try:
|
||||||
query = 'SELECT id, poster_url FROM notify_log ' \
|
query = 'SELECT id, poster_url FROM notify_log ' \
|
||||||
'WHERE rating_key = %d OR parent_rating_key = %d OR grandparent_rating_key = %d ' \
|
'WHERE rating_key = %d OR parent_rating_key = %d OR grandparent_rating_key = %d ' \
|
||||||
'ORDER BY id DESC LIMIT 1' % (int(rating_key), int(rating_key), int(rating_key))
|
'ORDER BY id DESC LIMIT 1' % (int(poster_key), int(poster_key), int(poster_key))
|
||||||
result = monitor_db.select(query)
|
result = monitor_db.select(query)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy DataFactory :: Unable to execute database query for get_poster_url: %s." % e)
|
logger.warn(u"PlexPy DataFactory :: Unable to execute database query for get_poster_url: %s." % e)
|
||||||
|
@ -882,6 +890,16 @@ class DataFactory(object):
|
||||||
|
|
||||||
return poster_url
|
return poster_url
|
||||||
|
|
||||||
|
def delete_poster_url(self, poster_url=''):
|
||||||
|
monitor_db = database.MonitorDatabase()
|
||||||
|
|
||||||
|
if poster_url:
|
||||||
|
logger.info(u"PlexPy DataFactory :: Deleting poster_url %s from the notify log database." % poster_url)
|
||||||
|
monitor_db.upsert('notify_log', {'poster_url': None}, {'poster_url': poster_url})
|
||||||
|
return 'Deleted poster_url %s.' % poster_url
|
||||||
|
else:
|
||||||
|
return 'Unable to delete poster_url.'
|
||||||
|
|
||||||
def get_search_query(self, rating_key=''):
|
def get_search_query(self, rating_key=''):
|
||||||
monitor_db = database.MonitorDatabase()
|
monitor_db = database.MonitorDatabase()
|
||||||
|
|
||||||
|
@ -1189,3 +1207,15 @@ class DataFactory(object):
|
||||||
}
|
}
|
||||||
|
|
||||||
return dict
|
return dict
|
||||||
|
|
||||||
|
def delete_notification_log(self):
|
||||||
|
monitor_db = database.MonitorDatabase()
|
||||||
|
|
||||||
|
try:
|
||||||
|
logger.info(u"PlexPy DataFactory :: Clearing notification logs from database.")
|
||||||
|
monitor_db.action('DELETE FROM notify_log')
|
||||||
|
monitor_db.action('VACUUM')
|
||||||
|
return 'Cleared notification logs.'
|
||||||
|
except Exception as e:
|
||||||
|
logger.warn(u"PlexPy DataFactory :: Unable to execute database query for delete_notification_log: %s." % e)
|
||||||
|
return 'Unable to clear notification logs.'
|
111
plexpy/graphs.py
111
plexpy/graphs.py
|
@ -490,40 +490,39 @@ class Graphs(object):
|
||||||
try:
|
try:
|
||||||
if y_axis == 'plays':
|
if y_axis == 'plays':
|
||||||
query = 'SELECT date(session_history.started, "unixepoch", "localtime") AS date_played, ' \
|
query = 'SELECT date(session_history.started, "unixepoch", "localtime") AS date_played, ' \
|
||||||
'SUM(CASE WHEN (session_history_media_info.video_decision = "direct play" ' \
|
'SUM(CASE WHEN session_history_media_info.transcode_decision = "direct play" ' \
|
||||||
'OR session_history_media_info.audio_decision = "direct play") THEN 1 ELSE 0 END) AS dp_count, ' \
|
'THEN 1 ELSE 0 END) AS dp_count, ' \
|
||||||
'SUM(CASE WHEN (session_history_media_info.video_decision != "transcode" ' \
|
'SUM(CASE WHEN session_history_media_info.transcode_decision = "copy" ' \
|
||||||
'AND session_history_media_info.audio_decision = "copy") THEN 1 ELSE 0 END) AS ds_count, ' \
|
'THEN 1 ELSE 0 END) AS ds_count, ' \
|
||||||
'SUM(CASE WHEN (session_history_media_info.video_decision = "transcode" ' \
|
'SUM(CASE WHEN session_history_media_info.transcode_decision = "transcode" ' \
|
||||||
'OR session_history_media_info.audio_decision = "transcode") THEN 1 ELSE 0 END) AS tc_count ' \
|
'THEN 1 ELSE 0 END) AS tc_count ' \
|
||||||
'FROM session_history ' \
|
'FROM session_history ' \
|
||||||
'JOIN session_history_media_info ON session_history.id = session_history_media_info.id ' \
|
'JOIN session_history_media_info ON session_history.id = session_history_media_info.id ' \
|
||||||
'WHERE (datetime(session_history.stopped, "unixepoch", "localtime") >= ' \
|
'WHERE (datetime(session_history.stopped, "unixepoch", "localtime") >= ' \
|
||||||
'datetime("now", "-%s days", "localtime")) AND ' \
|
'datetime("now", "-%s days", "localtime")) AND ' \
|
||||||
'(session_history.media_type = "episode" OR session_history.media_type = "movie" OR session_history.media_type = "track") ' \
|
'(session_history.media_type = "episode" OR session_history.media_type = "movie" OR ' \
|
||||||
|
'session_history.media_type = "track") ' \
|
||||||
'GROUP BY date_played ' \
|
'GROUP BY date_played ' \
|
||||||
'ORDER BY started ASC' % time_range
|
'ORDER BY started ASC' % time_range
|
||||||
|
|
||||||
result = monitor_db.select(query)
|
result = monitor_db.select(query)
|
||||||
else:
|
else:
|
||||||
query = 'SELECT date(session_history.started, "unixepoch", "localtime") AS date_played, ' \
|
query = 'SELECT date(session_history.started, "unixepoch", "localtime") AS date_played, ' \
|
||||||
'SUM(CASE WHEN (session_history_media_info.video_decision = "direct play" ' \
|
'SUM(CASE WHEN session_history_media_info.transcode_decision = "direct play" ' \
|
||||||
'OR session_history_media_info.audio_decision = "direct play") ' \
|
|
||||||
'AND session_history.stopped > 0 THEN (session_history.stopped - session_history.started) ' \
|
'AND session_history.stopped > 0 THEN (session_history.stopped - session_history.started) ' \
|
||||||
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS dp_count, ' \
|
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS dp_count, ' \
|
||||||
'SUM(CASE WHEN (session_history_media_info.video_decision != "transcode" ' \
|
'SUM(CASE WHEN session_history_media_info.transcode_decision = "copy" ' \
|
||||||
'AND session_history_media_info.audio_decision = "copy") ' \
|
|
||||||
'AND session_history.stopped > 0 THEN (session_history.stopped - session_history.started) ' \
|
'AND session_history.stopped > 0 THEN (session_history.stopped - session_history.started) ' \
|
||||||
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS ds_count, ' \
|
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS ds_count, ' \
|
||||||
'SUM(CASE WHEN (session_history_media_info.video_decision = "transcode" ' \
|
'SUM(CASE WHEN session_history_media_info.transcode_decision = "transcode" ' \
|
||||||
'OR session_history_media_info.audio_decision = "transcode") ' \
|
|
||||||
'AND session_history.stopped > 0 THEN (session_history.stopped - session_history.started) ' \
|
'AND session_history.stopped > 0 THEN (session_history.stopped - session_history.started) ' \
|
||||||
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS tc_count ' \
|
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS tc_count ' \
|
||||||
'FROM session_history ' \
|
'FROM session_history ' \
|
||||||
'JOIN session_history_media_info ON session_history.id = session_history_media_info.id ' \
|
'JOIN session_history_media_info ON session_history.id = session_history_media_info.id ' \
|
||||||
'WHERE datetime(session_history.stopped, "unixepoch", "localtime") >= ' \
|
'WHERE datetime(session_history.stopped, "unixepoch", "localtime") >= ' \
|
||||||
'datetime("now", "-%s days", "localtime") AND ' \
|
'datetime("now", "-%s days", "localtime") AND ' \
|
||||||
'(session_history.media_type = "episode" OR session_history.media_type = "movie" OR session_history.media_type = "track") ' \
|
'(session_history.media_type = "episode" OR session_history.media_type = "movie" OR ' \
|
||||||
|
'session_history.media_type = "track") ' \
|
||||||
'GROUP BY date_played ' \
|
'GROUP BY date_played ' \
|
||||||
'ORDER BY started ASC' % time_range
|
'ORDER BY started ASC' % time_range
|
||||||
|
|
||||||
|
@ -583,12 +582,12 @@ class Graphs(object):
|
||||||
try:
|
try:
|
||||||
if y_axis == 'plays':
|
if y_axis == 'plays':
|
||||||
query = 'SELECT session_history_media_info.video_resolution AS resolution, ' \
|
query = 'SELECT session_history_media_info.video_resolution AS resolution, ' \
|
||||||
'SUM(CASE WHEN (session_history_media_info.video_decision = "direct play" ' \
|
'SUM(CASE WHEN session_history_media_info.transcode_decision = "direct play" ' \
|
||||||
'OR session_history_media_info.audio_decision = "direct play") THEN 1 ELSE 0 END) AS dp_count, ' \
|
'THEN 1 ELSE 0 END) AS dp_count, ' \
|
||||||
'SUM(CASE WHEN (session_history_media_info.video_decision != "transcode" ' \
|
'SUM(CASE WHEN session_history_media_info.transcode_decision = "copy" ' \
|
||||||
'AND session_history_media_info.audio_decision = "copy") THEN 1 ELSE 0 END) AS ds_count, ' \
|
'THEN 1 ELSE 0 END) AS ds_count, ' \
|
||||||
'SUM(CASE WHEN (session_history_media_info.video_decision = "transcode" ' \
|
'SUM(CASE WHEN session_history_media_info.transcode_decision = "transcode" ' \
|
||||||
'OR session_history_media_info.audio_decision = "transcode") THEN 1 ELSE 0 END) AS tc_count, ' \
|
'THEN 1 ELSE 0 END) AS tc_count, ' \
|
||||||
'COUNT(session_history.id) AS total_count ' \
|
'COUNT(session_history.id) AS total_count ' \
|
||||||
'FROM session_history ' \
|
'FROM session_history ' \
|
||||||
'JOIN session_history_media_info ON session_history.id = session_history_media_info.id ' \
|
'JOIN session_history_media_info ON session_history.id = session_history_media_info.id ' \
|
||||||
|
@ -602,16 +601,13 @@ class Graphs(object):
|
||||||
result = monitor_db.select(query)
|
result = monitor_db.select(query)
|
||||||
else:
|
else:
|
||||||
query = 'SELECT session_history_media_info.video_resolution AS resolution,' \
|
query = 'SELECT session_history_media_info.video_resolution AS resolution,' \
|
||||||
'SUM(CASE WHEN (session_history_media_info.video_decision = "direct play" ' \
|
'SUM(CASE WHEN session_history_media_info.transcode_decision = "direct play" ' \
|
||||||
'OR session_history_media_info.audio_decision = "direct play") ' \
|
|
||||||
'AND session_history.stopped > 0 THEN (session_history.stopped - session_history.started) ' \
|
'AND session_history.stopped > 0 THEN (session_history.stopped - session_history.started) ' \
|
||||||
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS dp_count, ' \
|
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS dp_count, ' \
|
||||||
'SUM(CASE WHEN (session_history_media_info.video_decision != "transcode" ' \
|
'SUM(CASE WHEN session_history_media_info.transcode_decision = "copy" ' \
|
||||||
'AND session_history_media_info.audio_decision = "copy") ' \
|
|
||||||
'AND session_history.stopped > 0 THEN (session_history.stopped - session_history.started) ' \
|
'AND session_history.stopped > 0 THEN (session_history.stopped - session_history.started) ' \
|
||||||
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS ds_count, ' \
|
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS ds_count, ' \
|
||||||
'SUM(CASE WHEN (session_history_media_info.video_decision = "transcode" ' \
|
'SUM(CASE WHEN session_history_media_info.transcode_decision = "transcode" ' \
|
||||||
'OR session_history_media_info.audio_decision = "transcode") ' \
|
|
||||||
'AND session_history.stopped > 0 THEN (session_history.stopped - session_history.started) ' \
|
'AND session_history.stopped > 0 THEN (session_history.stopped - session_history.started) ' \
|
||||||
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS tc_count, ' \
|
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS tc_count, ' \
|
||||||
'SUM(CASE WHEN stopped > 0 THEN (stopped - started) ' \
|
'SUM(CASE WHEN stopped > 0 THEN (stopped - started) ' \
|
||||||
|
@ -671,12 +667,12 @@ class Graphs(object):
|
||||||
'WHEN session_history_media_info.transcode_height <= 1440 THEN "QHD" ' \
|
'WHEN session_history_media_info.transcode_height <= 1440 THEN "QHD" ' \
|
||||||
'WHEN session_history_media_info.transcode_height <= 2160 THEN "4K" ' \
|
'WHEN session_history_media_info.transcode_height <= 2160 THEN "4K" ' \
|
||||||
'ELSE "unknown" END) ELSE session_history_media_info.video_resolution END) AS resolution, ' \
|
'ELSE "unknown" END) ELSE session_history_media_info.video_resolution END) AS resolution, ' \
|
||||||
'SUM(CASE WHEN (session_history_media_info.video_decision = "direct play" ' \
|
'SUM(CASE WHEN session_history_media_info.transcode_decision = "direct play" ' \
|
||||||
'OR session_history_media_info.audio_decision = "direct play") THEN 1 ELSE 0 END) AS dp_count, ' \
|
'THEN 1 ELSE 0 END) AS dp_count, ' \
|
||||||
'SUM(CASE WHEN (session_history_media_info.video_decision != "transcode" ' \
|
'SUM(CASE WHEN session_history_media_info.transcode_decision = "copy" ' \
|
||||||
'AND session_history_media_info.audio_decision = "copy") THEN 1 ELSE 0 END) AS ds_count, ' \
|
'THEN 1 ELSE 0 END) AS ds_count, ' \
|
||||||
'SUM(CASE WHEN (session_history_media_info.video_decision = "transcode" '\
|
'SUM(CASE WHEN session_history_media_info.transcode_decision = "transcode" '\
|
||||||
'OR session_history_media_info.audio_decision = "transcode") THEN 1 ELSE 0 END) AS tc_count, ' \
|
'THEN 1 ELSE 0 END) AS tc_count, ' \
|
||||||
'COUNT(session_history.id) AS total_count ' \
|
'COUNT(session_history.id) AS total_count ' \
|
||||||
'FROM session_history ' \
|
'FROM session_history ' \
|
||||||
'JOIN session_history_media_info ON session_history.id = session_history_media_info.id ' \
|
'JOIN session_history_media_info ON session_history.id = session_history_media_info.id ' \
|
||||||
|
@ -700,16 +696,13 @@ class Graphs(object):
|
||||||
'WHEN session_history_media_info.transcode_height <= 1440 THEN "QHD" ' \
|
'WHEN session_history_media_info.transcode_height <= 1440 THEN "QHD" ' \
|
||||||
'WHEN session_history_media_info.transcode_height <= 2160 THEN "4K" ' \
|
'WHEN session_history_media_info.transcode_height <= 2160 THEN "4K" ' \
|
||||||
'ELSE "unknown" END) ELSE session_history_media_info.video_resolution END) AS resolution, ' \
|
'ELSE "unknown" END) ELSE session_history_media_info.video_resolution END) AS resolution, ' \
|
||||||
'SUM(CASE WHEN (session_history_media_info.video_decision = "direct play" ' \
|
'SUM(CASE WHEN session_history_media_info.transcode_decision = "direct play" ' \
|
||||||
'OR session_history_media_info.audio_decision = "direct play") ' \
|
|
||||||
'AND session_history.stopped > 0 THEN (session_history.stopped - session_history.started) ' \
|
'AND session_history.stopped > 0 THEN (session_history.stopped - session_history.started) ' \
|
||||||
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS dp_count, ' \
|
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS dp_count, ' \
|
||||||
'SUM(CASE WHEN (session_history_media_info.video_decision != "transcode" ' \
|
'SUM(CASE WHEN session_history_media_info.transcode_decision = "copy" ' \
|
||||||
'AND session_history_media_info.audio_decision = "copy") ' \
|
|
||||||
'AND session_history.stopped > 0 THEN (session_history.stopped - session_history.started) ' \
|
'AND session_history.stopped > 0 THEN (session_history.stopped - session_history.started) ' \
|
||||||
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS ds_count, ' \
|
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS ds_count, ' \
|
||||||
'SUM(CASE WHEN (session_history_media_info.video_decision = "transcode" ' \
|
'SUM(CASE WHEN session_history_media_info.transcode_decision = "transcode" ' \
|
||||||
'OR session_history_media_info.audio_decision = "transcode") ' \
|
|
||||||
'AND session_history.stopped > 0 THEN (session_history.stopped - session_history.started) ' \
|
'AND session_history.stopped > 0 THEN (session_history.stopped - session_history.started) ' \
|
||||||
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS tc_count, ' \
|
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS tc_count, ' \
|
||||||
'SUM(CASE WHEN stopped > 0 THEN (stopped - started) ' \
|
'SUM(CASE WHEN stopped > 0 THEN (stopped - started) ' \
|
||||||
|
@ -759,12 +752,12 @@ class Graphs(object):
|
||||||
try:
|
try:
|
||||||
if y_axis == 'plays':
|
if y_axis == 'plays':
|
||||||
query = 'SELECT session_history.platform AS platform, ' \
|
query = 'SELECT session_history.platform AS platform, ' \
|
||||||
'SUM(CASE WHEN (session_history_media_info.video_decision = "direct play" ' \
|
'SUM(CASE WHEN session_history_media_info.transcode_decision = "direct play" ' \
|
||||||
'OR session_history_media_info.audio_decision = "direct play") THEN 1 ELSE 0 END) AS dp_count, ' \
|
'THEN 1 ELSE 0 END) AS dp_count, ' \
|
||||||
'SUM(CASE WHEN (session_history_media_info.video_decision != "transcode" ' \
|
'SUM(CASE WHEN session_history_media_info.transcode_decision = "copy" ' \
|
||||||
'AND session_history_media_info.audio_decision = "copy") THEN 1 ELSE 0 END) AS ds_count, ' \
|
'THEN 1 ELSE 0 END) AS ds_count, ' \
|
||||||
'SUM(CASE WHEN (session_history_media_info.video_decision = "transcode" ' \
|
'SUM(CASE WHEN session_history_media_info.transcode_decision = "transcode" ' \
|
||||||
'OR session_history_media_info.audio_decision = "transcode") THEN 1 ELSE 0 END) AS tc_count, ' \
|
'THEN 1 ELSE 0 END) AS tc_count, ' \
|
||||||
'COUNT(session_history.id) AS total_count ' \
|
'COUNT(session_history.id) AS total_count ' \
|
||||||
'FROM session_history ' \
|
'FROM session_history ' \
|
||||||
'JOIN session_history_media_info ON session_history.id = session_history_media_info.id ' \
|
'JOIN session_history_media_info ON session_history.id = session_history_media_info.id ' \
|
||||||
|
@ -777,16 +770,13 @@ class Graphs(object):
|
||||||
result = monitor_db.select(query)
|
result = monitor_db.select(query)
|
||||||
else:
|
else:
|
||||||
query = 'SELECT session_history.platform AS platform, ' \
|
query = 'SELECT session_history.platform AS platform, ' \
|
||||||
'SUM(CASE WHEN (session_history_media_info.video_decision = "direct play" ' \
|
'SUM(CASE WHEN session_history_media_info.transcode_decision = "direct play" ' \
|
||||||
'OR session_history_media_info.audio_decision = "direct play") ' \
|
|
||||||
'AND session_history.stopped > 0 THEN (session_history.stopped - session_history.started) ' \
|
'AND session_history.stopped > 0 THEN (session_history.stopped - session_history.started) ' \
|
||||||
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS dp_count, ' \
|
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS dp_count, ' \
|
||||||
'SUM(CASE WHEN (session_history_media_info.video_decision != "transcode" ' \
|
'SUM(CASE WHEN session_history_media_info.transcode_decision = "copy" ' \
|
||||||
'AND session_history_media_info.audio_decision = "copy") ' \
|
|
||||||
'AND session_history.stopped > 0 THEN (session_history.stopped - session_history.started) ' \
|
'AND session_history.stopped > 0 THEN (session_history.stopped - session_history.started) ' \
|
||||||
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS ds_count, ' \
|
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS ds_count, ' \
|
||||||
'SUM(CASE WHEN (session_history_media_info.video_decision = "transcode" ' \
|
'SUM(CASE WHEN session_history_media_info.transcode_decision = "transcode" ' \
|
||||||
'AND session_history_media_info.audio_decision = "transcode") ' \
|
|
||||||
'AND session_history.stopped > 0 THEN (session_history.stopped - session_history.started) ' \
|
'AND session_history.stopped > 0 THEN (session_history.stopped - session_history.started) ' \
|
||||||
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS tc_count, ' \
|
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS tc_count, ' \
|
||||||
'SUM(CASE WHEN session_history.stopped > 0 ' \
|
'SUM(CASE WHEN session_history.stopped > 0 ' \
|
||||||
|
@ -838,12 +828,12 @@ class Graphs(object):
|
||||||
if y_axis == 'plays':
|
if y_axis == 'plays':
|
||||||
query = 'SELECT ' \
|
query = 'SELECT ' \
|
||||||
'(CASE WHEN users.friendly_name IS NULL THEN users.username ELSE users.friendly_name END) AS username, ' \
|
'(CASE WHEN users.friendly_name IS NULL THEN users.username ELSE users.friendly_name END) AS username, ' \
|
||||||
'SUM(CASE WHEN (session_history_media_info.video_decision = "direct play" ' \
|
'SUM(CASE WHEN session_history_media_info.transcode_decision = "direct play" ' \
|
||||||
'OR session_history_media_info.audio_decision = "direct play") THEN 1 ELSE 0 END) AS dp_count, ' \
|
'THEN 1 ELSE 0 END) AS dp_count, ' \
|
||||||
'SUM(CASE WHEN (session_history_media_info.video_decision != "transcode" ' \
|
'SUM(CASE WHEN session_history_media_info.transcode_decision = "copy" ' \
|
||||||
'AND session_history_media_info.audio_decision = "copy") THEN 1 ELSE 0 END) AS ds_count, ' \
|
'THEN 1 ELSE 0 END) AS ds_count, ' \
|
||||||
'SUM(CASE WHEN (session_history_media_info.video_decision = "transcode" ' \
|
'SUM(CASE WHEN session_history_media_info.transcode_decision = "transcode" ' \
|
||||||
'OR session_history_media_info.audio_decision = "transcode") THEN 1 ELSE 0 END) AS tc_count, ' \
|
'THEN 1 ELSE 0 END) AS tc_count, ' \
|
||||||
'COUNT(session_history.id) AS total_count ' \
|
'COUNT(session_history.id) AS total_count ' \
|
||||||
'FROM session_history ' \
|
'FROM session_history ' \
|
||||||
'JOIN users ON session_history.user_id = users.user_id ' \
|
'JOIN users ON session_history.user_id = users.user_id ' \
|
||||||
|
@ -858,16 +848,13 @@ class Graphs(object):
|
||||||
else:
|
else:
|
||||||
query = 'SELECT ' \
|
query = 'SELECT ' \
|
||||||
'(CASE WHEN users.friendly_name IS NULL THEN users.username ELSE users.friendly_name END) AS username, ' \
|
'(CASE WHEN users.friendly_name IS NULL THEN users.username ELSE users.friendly_name END) AS username, ' \
|
||||||
'SUM(CASE WHEN (session_history_media_info.video_decision = "direct play" ' \
|
'SUM(CASE WHEN session_history_media_info.transcode_decision = "direct play" ' \
|
||||||
'OR session_history_media_info.audio_decision = "direct play") ' \
|
|
||||||
'AND session_history.stopped > 0 THEN (session_history.stopped - session_history.started) ' \
|
'AND session_history.stopped > 0 THEN (session_history.stopped - session_history.started) ' \
|
||||||
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS dp_count, ' \
|
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS dp_count, ' \
|
||||||
'SUM(CASE WHEN (session_history_media_info.video_decision != "transcode" ' \
|
'SUM(CASE WHEN session_history_media_info.transcode_decision = "copy" ' \
|
||||||
'AND session_history_media_info.audio_decision = "copy") ' \
|
|
||||||
'AND session_history.stopped > 0 THEN (session_history.stopped - session_history.started) ' \
|
'AND session_history.stopped > 0 THEN (session_history.stopped - session_history.started) ' \
|
||||||
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS ds_count, ' \
|
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS ds_count, ' \
|
||||||
'SUM(CASE WHEN (session_history_media_info.video_decision = "transcode" ' \
|
'SUM(CASE WHEN session_history_media_info.transcode_decision = "transcode" ' \
|
||||||
'AND session_history_media_info.audio_decision = "transcode") ' \
|
|
||||||
'AND session_history.stopped > 0 THEN (session_history.stopped - session_history.started) ' \
|
'AND session_history.stopped > 0 THEN (session_history.stopped - session_history.started) ' \
|
||||||
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS tc_count, ' \
|
' - (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) AS tc_count, ' \
|
||||||
'SUM(CASE WHEN session_history.stopped > 0 ' \
|
'SUM(CASE WHEN session_history.stopped > 0 ' \
|
||||||
|
|
|
@ -148,7 +148,6 @@ class Libraries(object):
|
||||||
'session_history_metadata.year',
|
'session_history_metadata.year',
|
||||||
'session_history_metadata.media_index',
|
'session_history_metadata.media_index',
|
||||||
'session_history_metadata.parent_media_index',
|
'session_history_metadata.parent_media_index',
|
||||||
'session_history_media_info.video_decision',
|
|
||||||
'library_sections.do_notify',
|
'library_sections.do_notify',
|
||||||
'library_sections.do_notify_created',
|
'library_sections.do_notify_created',
|
||||||
'library_sections.keep_history'
|
'library_sections.keep_history'
|
||||||
|
@ -540,7 +539,7 @@ class Libraries(object):
|
||||||
def get_details(self, section_id=None):
|
def get_details(self, section_id=None):
|
||||||
from plexpy import pmsconnect
|
from plexpy import pmsconnect
|
||||||
|
|
||||||
default_return = {'section_id': None,
|
default_return = {'section_id': 0,
|
||||||
'section_name': 'Local',
|
'section_name': 'Local',
|
||||||
'section_type': '',
|
'section_type': '',
|
||||||
'library_thumb': common.DEFAULT_COVER_THUMB,
|
'library_thumb': common.DEFAULT_COVER_THUMB,
|
||||||
|
@ -550,7 +549,7 @@ class Libraries(object):
|
||||||
'child_count': 0,
|
'child_count': 0,
|
||||||
'do_notify': 0,
|
'do_notify': 0,
|
||||||
'do_notify_created': 0,
|
'do_notify_created': 0,
|
||||||
'keep_history': 0
|
'keep_history': 1
|
||||||
}
|
}
|
||||||
|
|
||||||
if not section_id:
|
if not section_id:
|
||||||
|
@ -603,7 +602,8 @@ class Libraries(object):
|
||||||
return library_details
|
return library_details
|
||||||
|
|
||||||
else:
|
else:
|
||||||
logger.warn(u"PlexPy Libraries :: Unable to retrieve library from local database. Requesting library list refresh.")
|
logger.warn(u"PlexPy Libraries :: Unable to retrieve library %s from database. Requesting library list refresh."
|
||||||
|
% section_id)
|
||||||
# Let's first refresh the libraries list to make sure the library isn't newly added and not in the db yet
|
# Let's first refresh the libraries list to make sure the library isn't newly added and not in the db yet
|
||||||
pmsconnect.refresh_libraries()
|
pmsconnect.refresh_libraries()
|
||||||
|
|
||||||
|
@ -613,9 +613,9 @@ class Libraries(object):
|
||||||
return library_details
|
return library_details
|
||||||
|
|
||||||
else:
|
else:
|
||||||
logger.warn(u"PlexPy Users :: Unable to retrieve user from local database. Returning 'Local' library.")
|
logger.warn(u"PlexPy Users :: Unable to retrieve library %s from database. Returning 'Local' library."
|
||||||
|
% section_id)
|
||||||
# If there is no library data we must return something
|
# If there is no library data we must return something
|
||||||
# Use "Local" library to retain compatibility with PlexWatch database value
|
|
||||||
return default_return
|
return default_return
|
||||||
|
|
||||||
def get_watch_time_stats(self, section_id=None):
|
def get_watch_time_stats(self, section_id=None):
|
||||||
|
|
|
@ -50,7 +50,10 @@ def notify(stream_data=None, notify_action=None):
|
||||||
for agent in notifiers.available_notification_agents():
|
for agent in notifiers.available_notification_agents():
|
||||||
if agent['on_play'] and notify_action == 'play':
|
if agent['on_play'] and notify_action == 'play':
|
||||||
# Build and send notification
|
# Build and send notification
|
||||||
notify_strings, metadata = build_notify_text(session=stream_data, notify_action=notify_action)
|
notify_strings, metadata = build_notify_text(session=stream_data,
|
||||||
|
notify_action=notify_action,
|
||||||
|
agent_id=agent['id'])
|
||||||
|
|
||||||
notifiers.send_notification(agent_id=agent['id'],
|
notifiers.send_notification(agent_id=agent['id'],
|
||||||
subject=notify_strings[0],
|
subject=notify_strings[0],
|
||||||
body=notify_strings[1],
|
body=notify_strings[1],
|
||||||
|
@ -68,7 +71,10 @@ def notify(stream_data=None, notify_action=None):
|
||||||
elif agent['on_stop'] and notify_action == 'stop' \
|
elif agent['on_stop'] and notify_action == 'stop' \
|
||||||
and (plexpy.CONFIG.NOTIFY_CONSECUTIVE or progress_percent < plexpy.CONFIG.NOTIFY_WATCHED_PERCENT):
|
and (plexpy.CONFIG.NOTIFY_CONSECUTIVE or progress_percent < plexpy.CONFIG.NOTIFY_WATCHED_PERCENT):
|
||||||
# Build and send notification
|
# Build and send notification
|
||||||
notify_strings, metadata = build_notify_text(session=stream_data, notify_action=notify_action)
|
notify_strings, metadata = build_notify_text(session=stream_data,
|
||||||
|
notify_action=notify_action,
|
||||||
|
agent_id=agent['id'])
|
||||||
|
|
||||||
notifiers.send_notification(agent_id=agent['id'],
|
notifiers.send_notification(agent_id=agent['id'],
|
||||||
subject=notify_strings[0],
|
subject=notify_strings[0],
|
||||||
body=notify_strings[1],
|
body=notify_strings[1],
|
||||||
|
@ -86,7 +92,10 @@ def notify(stream_data=None, notify_action=None):
|
||||||
elif agent['on_pause'] and notify_action == 'pause' \
|
elif agent['on_pause'] and notify_action == 'pause' \
|
||||||
and (plexpy.CONFIG.NOTIFY_CONSECUTIVE or progress_percent < 99):
|
and (plexpy.CONFIG.NOTIFY_CONSECUTIVE or progress_percent < 99):
|
||||||
# Build and send notification
|
# Build and send notification
|
||||||
notify_strings, metadata = build_notify_text(session=stream_data, notify_action=notify_action)
|
notify_strings, metadata = build_notify_text(session=stream_data,
|
||||||
|
notify_action=notify_action,
|
||||||
|
agent_id=agent['id'])
|
||||||
|
|
||||||
notifiers.send_notification(agent_id=agent['id'],
|
notifiers.send_notification(agent_id=agent['id'],
|
||||||
subject=notify_strings[0],
|
subject=notify_strings[0],
|
||||||
body=notify_strings[1],
|
body=notify_strings[1],
|
||||||
|
@ -104,7 +113,10 @@ def notify(stream_data=None, notify_action=None):
|
||||||
elif agent['on_resume'] and notify_action == 'resume' \
|
elif agent['on_resume'] and notify_action == 'resume' \
|
||||||
and (plexpy.CONFIG.NOTIFY_CONSECUTIVE or progress_percent < 99):
|
and (plexpy.CONFIG.NOTIFY_CONSECUTIVE or progress_percent < 99):
|
||||||
# Build and send notification
|
# Build and send notification
|
||||||
notify_strings, metadata = build_notify_text(session=stream_data, notify_action=notify_action)
|
notify_strings, metadata = build_notify_text(session=stream_data,
|
||||||
|
notify_action=notify_action,
|
||||||
|
agent_id=agent['id'])
|
||||||
|
|
||||||
notifiers.send_notification(agent_id=agent['id'],
|
notifiers.send_notification(agent_id=agent['id'],
|
||||||
subject=notify_strings[0],
|
subject=notify_strings[0],
|
||||||
body=notify_strings[1],
|
body=notify_strings[1],
|
||||||
|
@ -121,7 +133,10 @@ def notify(stream_data=None, notify_action=None):
|
||||||
|
|
||||||
elif agent['on_buffer'] and notify_action == 'buffer':
|
elif agent['on_buffer'] and notify_action == 'buffer':
|
||||||
# Build and send notification
|
# Build and send notification
|
||||||
notify_strings, metadata = build_notify_text(session=stream_data, notify_action=notify_action)
|
notify_strings, metadata = build_notify_text(session=stream_data,
|
||||||
|
notify_action=notify_action,
|
||||||
|
agent_id=agent['id'])
|
||||||
|
|
||||||
notifiers.send_notification(agent_id=agent['id'],
|
notifiers.send_notification(agent_id=agent['id'],
|
||||||
subject=notify_strings[0],
|
subject=notify_strings[0],
|
||||||
body=notify_strings[1],
|
body=notify_strings[1],
|
||||||
|
@ -143,7 +158,10 @@ def notify(stream_data=None, notify_action=None):
|
||||||
# If there is nothing in the notify_log for our agent id but it is enabled we should notify
|
# If there is nothing in the notify_log for our agent id but it is enabled we should notify
|
||||||
if not any(d['agent_id'] == agent['id'] and d['notify_action'] == notify_action for d in notify_states):
|
if not any(d['agent_id'] == agent['id'] and d['notify_action'] == notify_action for d in notify_states):
|
||||||
# Build and send notification
|
# Build and send notification
|
||||||
notify_strings, metadata = build_notify_text(session=stream_data, notify_action=notify_action)
|
notify_strings, metadata = build_notify_text(session=stream_data,
|
||||||
|
notify_action=notify_action,
|
||||||
|
agent_id=agent['id'])
|
||||||
|
|
||||||
notifiers.send_notification(agent_id=agent['id'],
|
notifiers.send_notification(agent_id=agent['id'],
|
||||||
subject=notify_strings[0],
|
subject=notify_strings[0],
|
||||||
body=notify_strings[1],
|
body=notify_strings[1],
|
||||||
|
@ -163,7 +181,10 @@ def notify(stream_data=None, notify_action=None):
|
||||||
for agent in notifiers.available_notification_agents():
|
for agent in notifiers.available_notification_agents():
|
||||||
if agent['on_play'] and notify_action == 'play':
|
if agent['on_play'] and notify_action == 'play':
|
||||||
# Build and send notification
|
# Build and send notification
|
||||||
notify_strings, metadata = build_notify_text(session=stream_data, notify_action=notify_action)
|
notify_strings, metadata = build_notify_text(session=stream_data,
|
||||||
|
notify_action=notify_action,
|
||||||
|
agent_id=agent['id'])
|
||||||
|
|
||||||
notifiers.send_notification(agent_id=agent['id'],
|
notifiers.send_notification(agent_id=agent['id'],
|
||||||
subject=notify_strings[0],
|
subject=notify_strings[0],
|
||||||
body=notify_strings[1],
|
body=notify_strings[1],
|
||||||
|
@ -180,7 +201,10 @@ def notify(stream_data=None, notify_action=None):
|
||||||
|
|
||||||
elif agent['on_stop'] and notify_action == 'stop':
|
elif agent['on_stop'] and notify_action == 'stop':
|
||||||
# Build and send notification
|
# Build and send notification
|
||||||
notify_strings, metadata = build_notify_text(session=stream_data, notify_action=notify_action)
|
notify_strings, metadata = build_notify_text(session=stream_data,
|
||||||
|
notify_action=notify_action,
|
||||||
|
agent_id=agent['id'])
|
||||||
|
|
||||||
notifiers.send_notification(agent_id=agent['id'],
|
notifiers.send_notification(agent_id=agent['id'],
|
||||||
subject=notify_strings[0],
|
subject=notify_strings[0],
|
||||||
body=notify_strings[1],
|
body=notify_strings[1],
|
||||||
|
@ -197,7 +221,10 @@ def notify(stream_data=None, notify_action=None):
|
||||||
|
|
||||||
elif agent['on_pause'] and notify_action == 'pause':
|
elif agent['on_pause'] and notify_action == 'pause':
|
||||||
# Build and send notification
|
# Build and send notification
|
||||||
notify_strings, metadata = build_notify_text(session=stream_data, notify_action=notify_action)
|
notify_strings, metadata = build_notify_text(session=stream_data,
|
||||||
|
notify_action=notify_action,
|
||||||
|
agent_id=agent['id'])
|
||||||
|
|
||||||
notifiers.send_notification(agent_id=agent['id'],
|
notifiers.send_notification(agent_id=agent['id'],
|
||||||
subject=notify_strings[0],
|
subject=notify_strings[0],
|
||||||
body=notify_strings[1],
|
body=notify_strings[1],
|
||||||
|
@ -214,7 +241,10 @@ def notify(stream_data=None, notify_action=None):
|
||||||
|
|
||||||
elif agent['on_resume'] and notify_action == 'resume':
|
elif agent['on_resume'] and notify_action == 'resume':
|
||||||
# Build and send notification
|
# Build and send notification
|
||||||
notify_strings, metadata = build_notify_text(session=stream_data, notify_action=notify_action)
|
notify_strings, metadata = build_notify_text(session=stream_data,
|
||||||
|
notify_action=notify_action,
|
||||||
|
agent_id=agent['id'])
|
||||||
|
|
||||||
notifiers.send_notification(agent_id=agent['id'],
|
notifiers.send_notification(agent_id=agent['id'],
|
||||||
subject=notify_strings[0],
|
subject=notify_strings[0],
|
||||||
body=notify_strings[1],
|
body=notify_strings[1],
|
||||||
|
@ -231,7 +261,10 @@ def notify(stream_data=None, notify_action=None):
|
||||||
|
|
||||||
elif agent['on_buffer'] and notify_action == 'buffer':
|
elif agent['on_buffer'] and notify_action == 'buffer':
|
||||||
# Build and send notification
|
# Build and send notification
|
||||||
notify_strings, metadata = build_notify_text(session=stream_data, notify_action=notify_action)
|
notify_strings, metadata = build_notify_text(session=stream_data,
|
||||||
|
notify_action=notify_action,
|
||||||
|
agent_id=agent['id'])
|
||||||
|
|
||||||
notifiers.send_notification(agent_id=agent['id'],
|
notifiers.send_notification(agent_id=agent['id'],
|
||||||
subject=notify_strings[0],
|
subject=notify_strings[0],
|
||||||
body=notify_strings[1],
|
body=notify_strings[1],
|
||||||
|
@ -260,7 +293,10 @@ def notify_timeline(timeline_data=None, notify_action=None):
|
||||||
for agent in notifiers.available_notification_agents():
|
for agent in notifiers.available_notification_agents():
|
||||||
if agent['on_created'] and notify_action == 'created':
|
if agent['on_created'] and notify_action == 'created':
|
||||||
# Build and send notification
|
# Build and send notification
|
||||||
notify_strings, metadata = build_notify_text(timeline=timeline_data, notify_action=notify_action)
|
notify_strings, metadata = build_notify_text(timeline=timeline_data,
|
||||||
|
notify_action=notify_action,
|
||||||
|
agent_id=agent['id'])
|
||||||
|
|
||||||
notifiers.send_notification(agent_id=agent['id'],
|
notifiers.send_notification(agent_id=agent['id'],
|
||||||
subject=notify_strings[0],
|
subject=notify_strings[0],
|
||||||
body=notify_strings[1],
|
body=notify_strings[1],
|
||||||
|
@ -279,7 +315,9 @@ def notify_timeline(timeline_data=None, notify_action=None):
|
||||||
for agent in notifiers.available_notification_agents():
|
for agent in notifiers.available_notification_agents():
|
||||||
if agent['on_extdown'] and notify_action == 'extdown':
|
if agent['on_extdown'] and notify_action == 'extdown':
|
||||||
# Build and send notification
|
# Build and send notification
|
||||||
notify_strings = build_server_notify_text(notify_action=notify_action)
|
notify_strings = build_server_notify_text(notify_action=notify_action,
|
||||||
|
agent_id=agent['id'])
|
||||||
|
|
||||||
notifiers.send_notification(agent_id=agent['id'],
|
notifiers.send_notification(agent_id=agent['id'],
|
||||||
subject=notify_strings[0],
|
subject=notify_strings[0],
|
||||||
body=notify_strings[1],
|
body=notify_strings[1],
|
||||||
|
@ -295,7 +333,9 @@ def notify_timeline(timeline_data=None, notify_action=None):
|
||||||
|
|
||||||
if agent['on_intdown'] and notify_action == 'intdown':
|
if agent['on_intdown'] and notify_action == 'intdown':
|
||||||
# Build and send notification
|
# Build and send notification
|
||||||
notify_strings = build_server_notify_text(notify_action=notify_action)
|
notify_strings = build_server_notify_text(notify_action=notify_action,
|
||||||
|
agent_id=agent['id'])
|
||||||
|
|
||||||
notifiers.send_notification(agent_id=agent['id'],
|
notifiers.send_notification(agent_id=agent['id'],
|
||||||
subject=notify_strings[0],
|
subject=notify_strings[0],
|
||||||
body=notify_strings[1],
|
body=notify_strings[1],
|
||||||
|
@ -311,7 +351,9 @@ def notify_timeline(timeline_data=None, notify_action=None):
|
||||||
|
|
||||||
if agent['on_extup'] and notify_action == 'extup':
|
if agent['on_extup'] and notify_action == 'extup':
|
||||||
# Build and send notification
|
# Build and send notification
|
||||||
notify_strings = build_server_notify_text(notify_action=notify_action)
|
notify_strings = build_server_notify_text(notify_action=notify_action,
|
||||||
|
agent_id=agent['id'])
|
||||||
|
|
||||||
notifiers.send_notification(agent_id=agent['id'],
|
notifiers.send_notification(agent_id=agent['id'],
|
||||||
subject=notify_strings[0],
|
subject=notify_strings[0],
|
||||||
body=notify_strings[1],
|
body=notify_strings[1],
|
||||||
|
@ -327,7 +369,27 @@ def notify_timeline(timeline_data=None, notify_action=None):
|
||||||
|
|
||||||
if agent['on_intup'] and notify_action == 'intup':
|
if agent['on_intup'] and notify_action == 'intup':
|
||||||
# Build and send notification
|
# Build and send notification
|
||||||
notify_strings = build_server_notify_text(notify_action=notify_action)
|
notify_strings = build_server_notify_text(notify_action=notify_action,
|
||||||
|
agent_id=agent['id'])
|
||||||
|
|
||||||
|
notifiers.send_notification(agent_id=agent['id'],
|
||||||
|
subject=notify_strings[0],
|
||||||
|
body=notify_strings[1],
|
||||||
|
script_args=notify_strings[2],
|
||||||
|
notify_action=notify_action)
|
||||||
|
|
||||||
|
# Set the notification state in the db
|
||||||
|
set_notify_state(session={},
|
||||||
|
notify_action=notify_action,
|
||||||
|
agent_info=agent,
|
||||||
|
notify_strings=notify_strings,
|
||||||
|
metadata={})
|
||||||
|
|
||||||
|
if agent['on_pmsupdate'] and notify_action == 'pmsupdate':
|
||||||
|
# Build and send notification
|
||||||
|
notify_strings = build_server_notify_text(notify_action=notify_action,
|
||||||
|
agent_id=agent['id'])
|
||||||
|
|
||||||
notifiers.send_notification(agent_id=agent['id'],
|
notifiers.send_notification(agent_id=agent['id'],
|
||||||
subject=notify_strings[0],
|
subject=notify_strings[0],
|
||||||
body=notify_strings[1],
|
body=notify_strings[1],
|
||||||
|
@ -395,11 +457,11 @@ def set_notify_state(session, notify_action, agent_info, notify_strings, metadat
|
||||||
logger.error(u"PlexPy NotificationHandler :: Unable to set notify state.")
|
logger.error(u"PlexPy NotificationHandler :: Unable to set notify state.")
|
||||||
|
|
||||||
|
|
||||||
def build_notify_text(session=None, timeline=None, notify_action=None):
|
def build_notify_text(session=None, timeline=None, notify_action=None, agent_id=None):
|
||||||
# Get time formats
|
# Get time formats
|
||||||
date_format = plexpy.CONFIG.DATE_FORMAT.replace('Do','').replace('zz','')
|
date_format = plexpy.CONFIG.DATE_FORMAT.replace('Do','')
|
||||||
time_format = plexpy.CONFIG.TIME_FORMAT.replace('Do','').replace('zz','')
|
time_format = plexpy.CONFIG.TIME_FORMAT.replace('Do','')
|
||||||
duration_format = plexpy.CONFIG.TIME_FORMAT.replace('Do','').replace('zz','').replace('a','').replace('A','')
|
duration_format = plexpy.CONFIG.TIME_FORMAT.replace('Do','').replace('a','').replace('A','')
|
||||||
|
|
||||||
# Get the server name
|
# Get the server name
|
||||||
server_name = plexpy.CONFIG.PMS_NAME
|
server_name = plexpy.CONFIG.PMS_NAME
|
||||||
|
@ -408,6 +470,10 @@ def build_notify_text(session=None, timeline=None, notify_action=None):
|
||||||
plex_tv = plextv.PlexTV()
|
plex_tv = plextv.PlexTV()
|
||||||
server_times = plex_tv.get_server_times()
|
server_times = plex_tv.get_server_times()
|
||||||
|
|
||||||
|
# Get the server version
|
||||||
|
pms_connect = pmsconnect.PmsConnect()
|
||||||
|
server_identity = pms_connect.get_server_identity()
|
||||||
|
|
||||||
if server_times:
|
if server_times:
|
||||||
updated_at = server_times[0]['updated_at']
|
updated_at = server_times[0]['updated_at']
|
||||||
server_uptime = helpers.human_duration(int(time.time() - helpers.cast_to_int(updated_at)))
|
server_uptime = helpers.human_duration(int(time.time() - helpers.cast_to_int(updated_at)))
|
||||||
|
@ -435,13 +501,13 @@ def build_notify_text(session=None, timeline=None, notify_action=None):
|
||||||
# Check for exclusion tags
|
# Check for exclusion tags
|
||||||
if metadata['media_type'] == 'movie':
|
if metadata['media_type'] == 'movie':
|
||||||
# Regex pattern to remove the text in the tags we don't want
|
# Regex pattern to remove the text in the tags we don't want
|
||||||
pattern = re.compile('\n*<tv>[^>]+.</tv>\n*|\n*<music>[^>]+.</music>\n*', re.IGNORECASE | re.DOTALL)
|
pattern = re.compile(r'<tv>[^>]+.<\/tv>|<music>[^>]+.<\/music>', re.IGNORECASE | re.DOTALL)
|
||||||
elif metadata['media_type'] == 'show' or metadata['media_type'] == 'episode':
|
elif metadata['media_type'] == 'show' or metadata['media_type'] == 'episode':
|
||||||
# Regex pattern to remove the text in the tags we don't want
|
# Regex pattern to remove the text in the tags we don't want
|
||||||
pattern = re.compile('\n*<movie>[^>]+.</movie>\n*|\n*?<music>[^>]+.</music>\n*', re.IGNORECASE | re.DOTALL)
|
pattern = re.compile(r'<movie>[^>]+.<\/movie>|<music>[^>]+.<\/music>', re.IGNORECASE | re.DOTALL)
|
||||||
elif metadata['media_type'] == 'artist' or metadata['media_type'] == 'track':
|
elif metadata['media_type'] == 'artist' or metadata['media_type'] == 'track':
|
||||||
# Regex pattern to remove the text in the tags we don't want
|
# Regex pattern to remove the text in the tags we don't want
|
||||||
pattern = re.compile('\n*<tv>[^>]+.</tv>\n*|\n*<movie>[^>]+.</movie>\n*', re.IGNORECASE | re.DOTALL)
|
pattern = re.compile(r'<tv>[^>]+.<\/tv>|<movie>[^>]+.<\/movie>', re.IGNORECASE | re.DOTALL)
|
||||||
else:
|
else:
|
||||||
pattern = None
|
pattern = None
|
||||||
|
|
||||||
|
@ -450,37 +516,37 @@ def build_notify_text(session=None, timeline=None, notify_action=None):
|
||||||
or metadata['media_type'] == 'artist' or metadata['media_type'] == 'track' \
|
or metadata['media_type'] == 'artist' or metadata['media_type'] == 'track' \
|
||||||
and pattern:
|
and pattern:
|
||||||
# Remove the unwanted tags and strip any unmatch tags too.
|
# Remove the unwanted tags and strip any unmatch tags too.
|
||||||
on_start_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_START_SUBJECT_TEXT))
|
on_start_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_START_SUBJECT_TEXT), agent_id)
|
||||||
on_start_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_START_BODY_TEXT))
|
on_start_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_START_BODY_TEXT), agent_id)
|
||||||
on_stop_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_STOP_SUBJECT_TEXT))
|
on_stop_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_STOP_SUBJECT_TEXT), agent_id)
|
||||||
on_stop_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_STOP_BODY_TEXT))
|
on_stop_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_STOP_BODY_TEXT), agent_id)
|
||||||
on_pause_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_PAUSE_SUBJECT_TEXT))
|
on_pause_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_PAUSE_SUBJECT_TEXT), agent_id)
|
||||||
on_pause_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_PAUSE_BODY_TEXT))
|
on_pause_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_PAUSE_BODY_TEXT), agent_id)
|
||||||
on_resume_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_RESUME_SUBJECT_TEXT))
|
on_resume_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_RESUME_SUBJECT_TEXT), agent_id)
|
||||||
on_resume_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_RESUME_BODY_TEXT))
|
on_resume_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_RESUME_BODY_TEXT), agent_id)
|
||||||
on_buffer_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_BUFFER_SUBJECT_TEXT))
|
on_buffer_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_BUFFER_SUBJECT_TEXT), agent_id)
|
||||||
on_buffer_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_BUFFER_BODY_TEXT))
|
on_buffer_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_BUFFER_BODY_TEXT), agent_id)
|
||||||
on_watched_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_WATCHED_SUBJECT_TEXT))
|
on_watched_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_WATCHED_SUBJECT_TEXT), agent_id)
|
||||||
on_watched_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_WATCHED_BODY_TEXT))
|
on_watched_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_WATCHED_BODY_TEXT), agent_id)
|
||||||
on_created_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_CREATED_SUBJECT_TEXT))
|
on_created_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_CREATED_SUBJECT_TEXT), agent_id)
|
||||||
on_created_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_CREATED_BODY_TEXT))
|
on_created_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_CREATED_BODY_TEXT), agent_id)
|
||||||
script_args_text = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_SCRIPTS_ARGS_TEXT))
|
script_args_text = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_SCRIPTS_ARGS_TEXT), agent_id)
|
||||||
else:
|
else:
|
||||||
on_start_subject = plexpy.CONFIG.NOTIFY_ON_START_SUBJECT_TEXT
|
on_start_subject = strip_tag(plexpy.CONFIG.NOTIFY_ON_START_SUBJECT_TEXT, agent_id)
|
||||||
on_start_body = plexpy.CONFIG.NOTIFY_ON_START_BODY_TEXT
|
on_start_body = strip_tag(plexpy.CONFIG.NOTIFY_ON_START_BODY_TEXT, agent_id)
|
||||||
on_stop_subject = plexpy.CONFIG.NOTIFY_ON_STOP_SUBJECT_TEXT
|
on_stop_subject = strip_tag(plexpy.CONFIG.NOTIFY_ON_STOP_SUBJECT_TEXT, agent_id)
|
||||||
on_stop_body = plexpy.CONFIG.NOTIFY_ON_STOP_BODY_TEXT
|
on_stop_body = strip_tag(plexpy.CONFIG.NOTIFY_ON_STOP_BODY_TEXT, agent_id)
|
||||||
on_pause_subject = plexpy.CONFIG.NOTIFY_ON_PAUSE_SUBJECT_TEXT
|
on_pause_subject = strip_tag(plexpy.CONFIG.NOTIFY_ON_PAUSE_SUBJECT_TEXT, agent_id)
|
||||||
on_pause_body = plexpy.CONFIG.NOTIFY_ON_PAUSE_BODY_TEXT
|
on_pause_body = strip_tag(plexpy.CONFIG.NOTIFY_ON_PAUSE_BODY_TEXT, agent_id)
|
||||||
on_resume_subject = plexpy.CONFIG.NOTIFY_ON_RESUME_SUBJECT_TEXT
|
on_resume_subject = strip_tag(plexpy.CONFIG.NOTIFY_ON_RESUME_SUBJECT_TEXT, agent_id)
|
||||||
on_resume_body = plexpy.CONFIG.NOTIFY_ON_RESUME_BODY_TEXT
|
on_resume_body = strip_tag(plexpy.CONFIG.NOTIFY_ON_RESUME_BODY_TEXT, agent_id)
|
||||||
on_buffer_subject = plexpy.CONFIG.NOTIFY_ON_BUFFER_SUBJECT_TEXT
|
on_buffer_subject = strip_tag(plexpy.CONFIG.NOTIFY_ON_BUFFER_SUBJECT_TEXT, agent_id)
|
||||||
on_buffer_body = plexpy.CONFIG.NOTIFY_ON_BUFFER_BODY_TEXT
|
on_buffer_body = strip_tag(plexpy.CONFIG.NOTIFY_ON_BUFFER_BODY_TEXT, agent_id)
|
||||||
on_watched_subject = plexpy.CONFIG.NOTIFY_ON_WATCHED_SUBJECT_TEXT
|
on_watched_subject = strip_tag(plexpy.CONFIG.NOTIFY_ON_WATCHED_SUBJECT_TEXT, agent_id)
|
||||||
on_watched_body = plexpy.CONFIG.NOTIFY_ON_WATCHED_BODY_TEXT
|
on_watched_body = strip_tag(plexpy.CONFIG.NOTIFY_ON_WATCHED_BODY_TEXT, agent_id)
|
||||||
on_created_subject = plexpy.CONFIG.NOTIFY_ON_CREATED_SUBJECT_TEXT
|
on_created_subject = strip_tag(plexpy.CONFIG.NOTIFY_ON_CREATED_SUBJECT_TEXT, agent_id)
|
||||||
on_created_body = plexpy.CONFIG.NOTIFY_ON_CREATED_BODY_TEXT
|
on_created_body = strip_tag(plexpy.CONFIG.NOTIFY_ON_CREATED_BODY_TEXT, agent_id)
|
||||||
script_args_text = plexpy.CONFIG.NOTIFY_SCRIPTS_ARGS_TEXT
|
script_args_text = strip_tag(plexpy.CONFIG.NOTIFY_SCRIPTS_ARGS_TEXT, agent_id)
|
||||||
|
|
||||||
# Create a title
|
# Create a title
|
||||||
if metadata['media_type'] == 'episode' or metadata['media_type'] == 'track':
|
if metadata['media_type'] == 'episode' or metadata['media_type'] == 'track':
|
||||||
|
@ -591,6 +657,7 @@ def build_notify_text(session=None, timeline=None, notify_action=None):
|
||||||
available_params = {# Global paramaters
|
available_params = {# Global paramaters
|
||||||
'server_name': server_name,
|
'server_name': server_name,
|
||||||
'server_uptime': server_uptime,
|
'server_uptime': server_uptime,
|
||||||
|
'server_version': server_identity.get('version',''),
|
||||||
'action': notify_action.title(),
|
'action': notify_action.title(),
|
||||||
'datestamp': arrow.now().format(date_format),
|
'datestamp': arrow.now().format(date_format),
|
||||||
'timestamp': arrow.now().format(time_format),
|
'timestamp': arrow.now().format(time_format),
|
||||||
|
@ -854,10 +921,10 @@ def build_notify_text(session=None, timeline=None, notify_action=None):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def build_server_notify_text(notify_action=None):
|
def build_server_notify_text(notify_action=None, agent_id=None):
|
||||||
# Get time formats
|
# Get time formats
|
||||||
date_format = plexpy.CONFIG.DATE_FORMAT.replace('Do','').replace('zz','')
|
date_format = plexpy.CONFIG.DATE_FORMAT.replace('Do','')
|
||||||
time_format = plexpy.CONFIG.TIME_FORMAT.replace('Do','').replace('zz','')
|
time_format = plexpy.CONFIG.TIME_FORMAT.replace('Do','')
|
||||||
|
|
||||||
# Get the server name
|
# Get the server name
|
||||||
server_name = plexpy.CONFIG.PMS_NAME
|
server_name = plexpy.CONFIG.PMS_NAME
|
||||||
|
@ -866,6 +933,14 @@ def build_server_notify_text(notify_action=None):
|
||||||
plex_tv = plextv.PlexTV()
|
plex_tv = plextv.PlexTV()
|
||||||
server_times = plex_tv.get_server_times()
|
server_times = plex_tv.get_server_times()
|
||||||
|
|
||||||
|
# Get the server version
|
||||||
|
pms_connect = pmsconnect.PmsConnect()
|
||||||
|
server_identity = pms_connect.get_server_identity()
|
||||||
|
|
||||||
|
update_status = {}
|
||||||
|
if notify_action == 'pmsupdate':
|
||||||
|
update_status = pms_connect.get_update_staus()
|
||||||
|
|
||||||
if server_times:
|
if server_times:
|
||||||
updated_at = server_times[0]['updated_at']
|
updated_at = server_times[0]['updated_at']
|
||||||
server_uptime = helpers.human_duration(int(time.time() - helpers.cast_to_int(updated_at)))
|
server_uptime = helpers.human_duration(int(time.time() - helpers.cast_to_int(updated_at)))
|
||||||
|
@ -875,22 +950,29 @@ def build_server_notify_text(notify_action=None):
|
||||||
|
|
||||||
pattern = re.compile('\n*<tv>[^>]+.</tv>\n*|\n*<movie>[^>]+.</movie>\n*|\n*?<music>[^>]+.</music>\n*', re.IGNORECASE | re.DOTALL)
|
pattern = re.compile('\n*<tv>[^>]+.</tv>\n*|\n*<movie>[^>]+.</movie>\n*|\n*?<music>[^>]+.</music>\n*', re.IGNORECASE | re.DOTALL)
|
||||||
|
|
||||||
on_extdown_subject = plexpy.CONFIG.NOTIFY_ON_EXTDOWN_SUBJECT_TEXT
|
on_extdown_subject = strip_tag(plexpy.CONFIG.NOTIFY_ON_EXTDOWN_SUBJECT_TEXT, agent_id)
|
||||||
on_extdown_body = plexpy.CONFIG.NOTIFY_ON_EXTDOWN_BODY_TEXT
|
on_extdown_body = strip_tag(plexpy.CONFIG.NOTIFY_ON_EXTDOWN_BODY_TEXT, agent_id)
|
||||||
on_intdown_subject = plexpy.CONFIG.NOTIFY_ON_INTDOWN_SUBJECT_TEXT
|
on_intdown_subject = strip_tag(plexpy.CONFIG.NOTIFY_ON_INTDOWN_SUBJECT_TEXT, agent_id)
|
||||||
on_intdown_body = plexpy.CONFIG.NOTIFY_ON_INTDOWN_BODY_TEXT
|
on_intdown_body = strip_tag(plexpy.CONFIG.NOTIFY_ON_INTDOWN_BODY_TEXT, agent_id)
|
||||||
on_extup_subject = plexpy.CONFIG.NOTIFY_ON_EXTUP_SUBJECT_TEXT
|
on_extup_subject = strip_tag(plexpy.CONFIG.NOTIFY_ON_EXTUP_SUBJECT_TEXT, agent_id)
|
||||||
on_extup_body = plexpy.CONFIG.NOTIFY_ON_EXTUP_BODY_TEXT
|
on_extup_body = strip_tag(plexpy.CONFIG.NOTIFY_ON_EXTUP_BODY_TEXT, agent_id)
|
||||||
on_intup_subject = plexpy.CONFIG.NOTIFY_ON_INTUP_SUBJECT_TEXT
|
on_intup_subject = strip_tag(plexpy.CONFIG.NOTIFY_ON_INTUP_SUBJECT_TEXT, agent_id)
|
||||||
on_intup_body = plexpy.CONFIG.NOTIFY_ON_INTUP_BODY_TEXT
|
on_intup_body = strip_tag(plexpy.CONFIG.NOTIFY_ON_INTUP_BODY_TEXT, agent_id)
|
||||||
script_args_text = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_SCRIPTS_ARGS_TEXT))
|
on_pmsupdate_subject = strip_tag(plexpy.CONFIG.NOTIFY_ON_PMSUPDATE_SUBJECT_TEXT, agent_id)
|
||||||
|
on_pmsupdate_body = strip_tag(plexpy.CONFIG.NOTIFY_ON_PMSUPDATE_BODY_TEXT, agent_id)
|
||||||
|
script_args_text = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_SCRIPTS_ARGS_TEXT), agent_id)
|
||||||
|
|
||||||
available_params = {# Global paramaters
|
available_params = {# Global paramaters
|
||||||
'server_name': server_name,
|
'server_name': server_name,
|
||||||
'server_uptime': server_uptime,
|
'server_uptime': server_uptime,
|
||||||
|
'server_version': server_identity.get('version',''),
|
||||||
'action': notify_action.title(),
|
'action': notify_action.title(),
|
||||||
'datestamp': arrow.now().format(date_format),
|
'datestamp': arrow.now().format(date_format),
|
||||||
'timestamp': arrow.now().format(time_format)}
|
'timestamp': arrow.now().format(time_format),
|
||||||
|
# Update parameters
|
||||||
|
'update_version': update_status.get('version',''),
|
||||||
|
'update_url': update_status.get('download_url',''),
|
||||||
|
'update_changelog': update_status.get('changelog','')}
|
||||||
|
|
||||||
# Default text
|
# Default text
|
||||||
subject_text = 'PlexPy (%s)' % server_name
|
subject_text = 'PlexPy (%s)' % server_name
|
||||||
|
@ -996,10 +1078,39 @@ def build_server_notify_text(notify_action=None):
|
||||||
else:
|
else:
|
||||||
return [subject_text, body_text, script_args]
|
return [subject_text, body_text, script_args]
|
||||||
|
|
||||||
|
elif notify_action == 'pmsupdate':
|
||||||
|
# Default body text
|
||||||
|
body_text = 'An update is available for the Plex Media Server (version {update_version}).'
|
||||||
|
|
||||||
|
if on_pmsupdate_subject and on_pmsupdate_body:
|
||||||
|
try:
|
||||||
|
subject_text = unicode(on_pmsupdate_subject).format(**available_params)
|
||||||
|
except LookupError, e:
|
||||||
|
logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification subject. Using fallback." % e)
|
||||||
|
except:
|
||||||
|
logger.error(u"PlexPy NotificationHandler :: Unable to parse custom notification subject. Using fallback.")
|
||||||
|
|
||||||
|
try:
|
||||||
|
body_text = unicode(on_pmsupdate_body).format(**available_params)
|
||||||
|
except LookupError, e:
|
||||||
|
logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification body. Using fallback." % e)
|
||||||
|
except:
|
||||||
|
logger.error(u"PlexPy NotificationHandler :: Unable to parse custom notification body. Using fallback.")
|
||||||
|
|
||||||
|
return [subject_text, body_text, script_args]
|
||||||
|
else:
|
||||||
|
return [subject_text, body_text, script_args]
|
||||||
|
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def strip_tag(data):
|
def strip_tag(data, agent_id=None):
|
||||||
p = re.compile(r'<.*?>')
|
# Allow tags b, i, u, a[href], font[color] for Pushover
|
||||||
|
if agent_id == 7:
|
||||||
|
p = re.compile(r'<(?!/?(b>|i>|u>)|(a\shref=\"[^\"\'\s]+\"|/a>|font\scolor=\"[^\"\'\s]+\"|/font>)).*?>',
|
||||||
|
re.IGNORECASE | re.DOTALL)
|
||||||
|
else:
|
||||||
|
p = re.compile(r'<.*?>', re.IGNORECASE | re.DOTALL)
|
||||||
|
|
||||||
return p.sub('', data)
|
return p.sub('', data)
|
|
@ -75,7 +75,8 @@ def available_notification_agents():
|
||||||
'on_extdown': plexpy.CONFIG.GROWL_ON_EXTDOWN,
|
'on_extdown': plexpy.CONFIG.GROWL_ON_EXTDOWN,
|
||||||
'on_intdown': plexpy.CONFIG.GROWL_ON_INTDOWN,
|
'on_intdown': plexpy.CONFIG.GROWL_ON_INTDOWN,
|
||||||
'on_extup': plexpy.CONFIG.GROWL_ON_EXTUP,
|
'on_extup': plexpy.CONFIG.GROWL_ON_EXTUP,
|
||||||
'on_intup': plexpy.CONFIG.GROWL_ON_INTUP
|
'on_intup': plexpy.CONFIG.GROWL_ON_INTUP,
|
||||||
|
'on_pmsupdate': plexpy.CONFIG.GROWL_ON_PMSUPDATE
|
||||||
},
|
},
|
||||||
{'name': 'Prowl',
|
{'name': 'Prowl',
|
||||||
'id': AGENT_IDS['Prowl'],
|
'id': AGENT_IDS['Prowl'],
|
||||||
|
@ -92,7 +93,8 @@ def available_notification_agents():
|
||||||
'on_extdown': plexpy.CONFIG.PROWL_ON_EXTDOWN,
|
'on_extdown': plexpy.CONFIG.PROWL_ON_EXTDOWN,
|
||||||
'on_intdown': plexpy.CONFIG.PROWL_ON_INTDOWN,
|
'on_intdown': plexpy.CONFIG.PROWL_ON_INTDOWN,
|
||||||
'on_extup': plexpy.CONFIG.PROWL_ON_EXTUP,
|
'on_extup': plexpy.CONFIG.PROWL_ON_EXTUP,
|
||||||
'on_intup': plexpy.CONFIG.PROWL_ON_INTUP
|
'on_intup': plexpy.CONFIG.PROWL_ON_INTUP,
|
||||||
|
'on_pmsupdate': plexpy.CONFIG.PROWL_ON_PMSUPDATE
|
||||||
},
|
},
|
||||||
{'name': 'XBMC',
|
{'name': 'XBMC',
|
||||||
'id': AGENT_IDS['XBMC'],
|
'id': AGENT_IDS['XBMC'],
|
||||||
|
@ -109,7 +111,8 @@ def available_notification_agents():
|
||||||
'on_extdown': plexpy.CONFIG.XBMC_ON_EXTDOWN,
|
'on_extdown': plexpy.CONFIG.XBMC_ON_EXTDOWN,
|
||||||
'on_intdown': plexpy.CONFIG.XBMC_ON_INTDOWN,
|
'on_intdown': plexpy.CONFIG.XBMC_ON_INTDOWN,
|
||||||
'on_extup': plexpy.CONFIG.XBMC_ON_EXTUP,
|
'on_extup': plexpy.CONFIG.XBMC_ON_EXTUP,
|
||||||
'on_intup': plexpy.CONFIG.XBMC_ON_INTUP
|
'on_intup': plexpy.CONFIG.XBMC_ON_INTUP,
|
||||||
|
'on_pmsupdate': plexpy.CONFIG.XBMC_ON_PMSUPDATE
|
||||||
},
|
},
|
||||||
{'name': 'Plex',
|
{'name': 'Plex',
|
||||||
'id': AGENT_IDS['Plex'],
|
'id': AGENT_IDS['Plex'],
|
||||||
|
@ -126,7 +129,8 @@ def available_notification_agents():
|
||||||
'on_extdown': plexpy.CONFIG.PLEX_ON_EXTDOWN,
|
'on_extdown': plexpy.CONFIG.PLEX_ON_EXTDOWN,
|
||||||
'on_intdown': plexpy.CONFIG.PLEX_ON_INTDOWN,
|
'on_intdown': plexpy.CONFIG.PLEX_ON_INTDOWN,
|
||||||
'on_extup': plexpy.CONFIG.PLEX_ON_EXTUP,
|
'on_extup': plexpy.CONFIG.PLEX_ON_EXTUP,
|
||||||
'on_intup': plexpy.CONFIG.PLEX_ON_INTUP
|
'on_intup': plexpy.CONFIG.PLEX_ON_INTUP,
|
||||||
|
'on_pmsupdate': plexpy.CONFIG.PLEX_ON_PMSUPDATE
|
||||||
},
|
},
|
||||||
{'name': 'NotifyMyAndroid',
|
{'name': 'NotifyMyAndroid',
|
||||||
'id': AGENT_IDS['NMA'],
|
'id': AGENT_IDS['NMA'],
|
||||||
|
@ -143,7 +147,8 @@ def available_notification_agents():
|
||||||
'on_extdown': plexpy.CONFIG.NMA_ON_EXTDOWN,
|
'on_extdown': plexpy.CONFIG.NMA_ON_EXTDOWN,
|
||||||
'on_intdown': plexpy.CONFIG.NMA_ON_INTDOWN,
|
'on_intdown': plexpy.CONFIG.NMA_ON_INTDOWN,
|
||||||
'on_extup': plexpy.CONFIG.NMA_ON_EXTUP,
|
'on_extup': plexpy.CONFIG.NMA_ON_EXTUP,
|
||||||
'on_intup': plexpy.CONFIG.NMA_ON_INTUP
|
'on_intup': plexpy.CONFIG.NMA_ON_INTUP,
|
||||||
|
'on_pmsupdate': plexpy.CONFIG.NMA_ON_PMSUPDATE
|
||||||
},
|
},
|
||||||
{'name': 'Pushalot',
|
{'name': 'Pushalot',
|
||||||
'id': AGENT_IDS['Pushalot'],
|
'id': AGENT_IDS['Pushalot'],
|
||||||
|
@ -160,7 +165,8 @@ def available_notification_agents():
|
||||||
'on_extdown': plexpy.CONFIG.PUSHALOT_ON_EXTDOWN,
|
'on_extdown': plexpy.CONFIG.PUSHALOT_ON_EXTDOWN,
|
||||||
'on_intdown': plexpy.CONFIG.PUSHALOT_ON_INTDOWN,
|
'on_intdown': plexpy.CONFIG.PUSHALOT_ON_INTDOWN,
|
||||||
'on_extup': plexpy.CONFIG.PUSHALOT_ON_EXTUP,
|
'on_extup': plexpy.CONFIG.PUSHALOT_ON_EXTUP,
|
||||||
'on_intup': plexpy.CONFIG.PUSHALOT_ON_INTUP
|
'on_intup': plexpy.CONFIG.PUSHALOT_ON_INTUP,
|
||||||
|
'on_pmsupdate': plexpy.CONFIG.PUSHALOT_ON_PMSUPDATE
|
||||||
},
|
},
|
||||||
{'name': 'Pushbullet',
|
{'name': 'Pushbullet',
|
||||||
'id': AGENT_IDS['Pushbullet'],
|
'id': AGENT_IDS['Pushbullet'],
|
||||||
|
@ -177,7 +183,8 @@ def available_notification_agents():
|
||||||
'on_extdown': plexpy.CONFIG.PUSHBULLET_ON_EXTDOWN,
|
'on_extdown': plexpy.CONFIG.PUSHBULLET_ON_EXTDOWN,
|
||||||
'on_intdown': plexpy.CONFIG.PUSHBULLET_ON_INTDOWN,
|
'on_intdown': plexpy.CONFIG.PUSHBULLET_ON_INTDOWN,
|
||||||
'on_extup': plexpy.CONFIG.PUSHBULLET_ON_EXTUP,
|
'on_extup': plexpy.CONFIG.PUSHBULLET_ON_EXTUP,
|
||||||
'on_intup': plexpy.CONFIG.PUSHBULLET_ON_INTUP
|
'on_intup': plexpy.CONFIG.PUSHBULLET_ON_INTUP,
|
||||||
|
'on_pmsupdate': plexpy.CONFIG.PUSHBULLET_ON_PMSUPDATE
|
||||||
},
|
},
|
||||||
{'name': 'Pushover',
|
{'name': 'Pushover',
|
||||||
'id': AGENT_IDS['Pushover'],
|
'id': AGENT_IDS['Pushover'],
|
||||||
|
@ -194,7 +201,8 @@ def available_notification_agents():
|
||||||
'on_extdown': plexpy.CONFIG.PUSHOVER_ON_EXTDOWN,
|
'on_extdown': plexpy.CONFIG.PUSHOVER_ON_EXTDOWN,
|
||||||
'on_intdown': plexpy.CONFIG.PUSHOVER_ON_INTDOWN,
|
'on_intdown': plexpy.CONFIG.PUSHOVER_ON_INTDOWN,
|
||||||
'on_extup': plexpy.CONFIG.PUSHOVER_ON_EXTUP,
|
'on_extup': plexpy.CONFIG.PUSHOVER_ON_EXTUP,
|
||||||
'on_intup': plexpy.CONFIG.PUSHOVER_ON_INTUP
|
'on_intup': plexpy.CONFIG.PUSHOVER_ON_INTUP,
|
||||||
|
'on_pmsupdate': plexpy.CONFIG.PUSHOVER_ON_PMSUPDATE
|
||||||
},
|
},
|
||||||
{'name': 'Boxcar2',
|
{'name': 'Boxcar2',
|
||||||
'id': AGENT_IDS['Boxcar2'],
|
'id': AGENT_IDS['Boxcar2'],
|
||||||
|
@ -211,7 +219,8 @@ def available_notification_agents():
|
||||||
'on_extdown': plexpy.CONFIG.BOXCAR_ON_EXTDOWN,
|
'on_extdown': plexpy.CONFIG.BOXCAR_ON_EXTDOWN,
|
||||||
'on_intdown': plexpy.CONFIG.BOXCAR_ON_INTDOWN,
|
'on_intdown': plexpy.CONFIG.BOXCAR_ON_INTDOWN,
|
||||||
'on_extup': plexpy.CONFIG.BOXCAR_ON_EXTUP,
|
'on_extup': plexpy.CONFIG.BOXCAR_ON_EXTUP,
|
||||||
'on_intup': plexpy.CONFIG.BOXCAR_ON_INTUP
|
'on_intup': plexpy.CONFIG.BOXCAR_ON_INTUP,
|
||||||
|
'on_pmsupdate': plexpy.CONFIG.BOXCAR_ON_PMSUPDATE
|
||||||
},
|
},
|
||||||
{'name': 'E-mail',
|
{'name': 'E-mail',
|
||||||
'id': AGENT_IDS['Email'],
|
'id': AGENT_IDS['Email'],
|
||||||
|
@ -228,7 +237,8 @@ def available_notification_agents():
|
||||||
'on_extdown': plexpy.CONFIG.EMAIL_ON_EXTDOWN,
|
'on_extdown': plexpy.CONFIG.EMAIL_ON_EXTDOWN,
|
||||||
'on_intdown': plexpy.CONFIG.EMAIL_ON_INTDOWN,
|
'on_intdown': plexpy.CONFIG.EMAIL_ON_INTDOWN,
|
||||||
'on_extup': plexpy.CONFIG.EMAIL_ON_EXTUP,
|
'on_extup': plexpy.CONFIG.EMAIL_ON_EXTUP,
|
||||||
'on_intup': plexpy.CONFIG.EMAIL_ON_INTUP
|
'on_intup': plexpy.CONFIG.EMAIL_ON_INTUP,
|
||||||
|
'on_pmsupdate': plexpy.CONFIG.EMAIL_ON_PMSUPDATE
|
||||||
},
|
},
|
||||||
{'name': 'Twitter',
|
{'name': 'Twitter',
|
||||||
'id': AGENT_IDS['Twitter'],
|
'id': AGENT_IDS['Twitter'],
|
||||||
|
@ -245,7 +255,8 @@ def available_notification_agents():
|
||||||
'on_extdown': plexpy.CONFIG.TWITTER_ON_EXTDOWN,
|
'on_extdown': plexpy.CONFIG.TWITTER_ON_EXTDOWN,
|
||||||
'on_intdown': plexpy.CONFIG.TWITTER_ON_INTDOWN,
|
'on_intdown': plexpy.CONFIG.TWITTER_ON_INTDOWN,
|
||||||
'on_extup': plexpy.CONFIG.TWITTER_ON_EXTUP,
|
'on_extup': plexpy.CONFIG.TWITTER_ON_EXTUP,
|
||||||
'on_intup': plexpy.CONFIG.TWITTER_ON_INTUP
|
'on_intup': plexpy.CONFIG.TWITTER_ON_INTUP,
|
||||||
|
'on_pmsupdate': plexpy.CONFIG.TWITTER_ON_PMSUPDATE
|
||||||
},
|
},
|
||||||
{'name': 'IFTTT',
|
{'name': 'IFTTT',
|
||||||
'id': AGENT_IDS['IFTTT'],
|
'id': AGENT_IDS['IFTTT'],
|
||||||
|
@ -262,7 +273,8 @@ def available_notification_agents():
|
||||||
'on_extdown': plexpy.CONFIG.IFTTT_ON_EXTDOWN,
|
'on_extdown': plexpy.CONFIG.IFTTT_ON_EXTDOWN,
|
||||||
'on_intdown': plexpy.CONFIG.IFTTT_ON_INTDOWN,
|
'on_intdown': plexpy.CONFIG.IFTTT_ON_INTDOWN,
|
||||||
'on_extup': plexpy.CONFIG.IFTTT_ON_EXTUP,
|
'on_extup': plexpy.CONFIG.IFTTT_ON_EXTUP,
|
||||||
'on_intup': plexpy.CONFIG.IFTTT_ON_INTUP
|
'on_intup': plexpy.CONFIG.IFTTT_ON_INTUP,
|
||||||
|
'on_pmsupdate': plexpy.CONFIG.IFTTT_ON_PMSUPDATE
|
||||||
},
|
},
|
||||||
{'name': 'Telegram',
|
{'name': 'Telegram',
|
||||||
'id': AGENT_IDS['Telegram'],
|
'id': AGENT_IDS['Telegram'],
|
||||||
|
@ -279,7 +291,8 @@ def available_notification_agents():
|
||||||
'on_extdown': plexpy.CONFIG.TELEGRAM_ON_EXTDOWN,
|
'on_extdown': plexpy.CONFIG.TELEGRAM_ON_EXTDOWN,
|
||||||
'on_intdown': plexpy.CONFIG.TELEGRAM_ON_INTDOWN,
|
'on_intdown': plexpy.CONFIG.TELEGRAM_ON_INTDOWN,
|
||||||
'on_extup': plexpy.CONFIG.TELEGRAM_ON_EXTUP,
|
'on_extup': plexpy.CONFIG.TELEGRAM_ON_EXTUP,
|
||||||
'on_intup': plexpy.CONFIG.TELEGRAM_ON_INTUP
|
'on_intup': plexpy.CONFIG.TELEGRAM_ON_INTUP,
|
||||||
|
'on_pmsupdate': plexpy.CONFIG.TELEGRAM_ON_PMSUPDATE
|
||||||
},
|
},
|
||||||
{'name': 'Slack',
|
{'name': 'Slack',
|
||||||
'id': AGENT_IDS['Slack'],
|
'id': AGENT_IDS['Slack'],
|
||||||
|
@ -296,7 +309,8 @@ def available_notification_agents():
|
||||||
'on_extdown': plexpy.CONFIG.SLACK_ON_EXTDOWN,
|
'on_extdown': plexpy.CONFIG.SLACK_ON_EXTDOWN,
|
||||||
'on_intdown': plexpy.CONFIG.SLACK_ON_INTDOWN,
|
'on_intdown': plexpy.CONFIG.SLACK_ON_INTDOWN,
|
||||||
'on_extup': plexpy.CONFIG.SLACK_ON_EXTUP,
|
'on_extup': plexpy.CONFIG.SLACK_ON_EXTUP,
|
||||||
'on_intup': plexpy.CONFIG.SLACK_ON_INTUP
|
'on_intup': plexpy.CONFIG.SLACK_ON_INTUP,
|
||||||
|
'on_pmsupdate': plexpy.CONFIG.SLACK_ON_PMSUPDATE
|
||||||
},
|
},
|
||||||
{'name': 'Scripts',
|
{'name': 'Scripts',
|
||||||
'id': AGENT_IDS['Scripts'],
|
'id': AGENT_IDS['Scripts'],
|
||||||
|
@ -313,7 +327,8 @@ def available_notification_agents():
|
||||||
'on_extdown': plexpy.CONFIG.SCRIPTS_ON_EXTDOWN,
|
'on_extdown': plexpy.CONFIG.SCRIPTS_ON_EXTDOWN,
|
||||||
'on_extup': plexpy.CONFIG.SCRIPTS_ON_EXTUP,
|
'on_extup': plexpy.CONFIG.SCRIPTS_ON_EXTUP,
|
||||||
'on_intdown': plexpy.CONFIG.SCRIPTS_ON_INTDOWN,
|
'on_intdown': plexpy.CONFIG.SCRIPTS_ON_INTDOWN,
|
||||||
'on_intup': plexpy.CONFIG.SCRIPTS_ON_INTUP
|
'on_intup': plexpy.CONFIG.SCRIPTS_ON_INTUP,
|
||||||
|
'on_pmsupdate': plexpy.CONFIG.SCRIPTS_ON_PMSUPDATE
|
||||||
},
|
},
|
||||||
{'name': 'Facebook',
|
{'name': 'Facebook',
|
||||||
'id': AGENT_IDS['Facebook'],
|
'id': AGENT_IDS['Facebook'],
|
||||||
|
@ -330,7 +345,8 @@ def available_notification_agents():
|
||||||
'on_extdown': plexpy.CONFIG.FACEBOOK_ON_EXTDOWN,
|
'on_extdown': plexpy.CONFIG.FACEBOOK_ON_EXTDOWN,
|
||||||
'on_intdown': plexpy.CONFIG.FACEBOOK_ON_INTDOWN,
|
'on_intdown': plexpy.CONFIG.FACEBOOK_ON_INTDOWN,
|
||||||
'on_extup': plexpy.CONFIG.FACEBOOK_ON_EXTUP,
|
'on_extup': plexpy.CONFIG.FACEBOOK_ON_EXTUP,
|
||||||
'on_intup': plexpy.CONFIG.FACEBOOK_ON_INTUP
|
'on_intup': plexpy.CONFIG.FACEBOOK_ON_INTUP,
|
||||||
|
'on_pmsupdate': plexpy.CONFIG.FACEBOOK_ON_PMSUPDATE
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -352,7 +368,8 @@ def available_notification_agents():
|
||||||
'on_extdown': plexpy.CONFIG.OSX_NOTIFY_ON_EXTDOWN,
|
'on_extdown': plexpy.CONFIG.OSX_NOTIFY_ON_EXTDOWN,
|
||||||
'on_intdown': plexpy.CONFIG.OSX_NOTIFY_ON_INTDOWN,
|
'on_intdown': plexpy.CONFIG.OSX_NOTIFY_ON_INTDOWN,
|
||||||
'on_extup': plexpy.CONFIG.OSX_NOTIFY_ON_EXTUP,
|
'on_extup': plexpy.CONFIG.OSX_NOTIFY_ON_EXTUP,
|
||||||
'on_intup': plexpy.CONFIG.OSX_NOTIFY_ON_INTUP
|
'on_intup': plexpy.CONFIG.OSX_NOTIFY_ON_INTUP,
|
||||||
|
'on_pmsupdate': plexpy.CONFIG.OSX_NOTIFY_ON_PMSUPDATE
|
||||||
})
|
})
|
||||||
|
|
||||||
return agents
|
return agents
|
||||||
|
@ -1266,7 +1283,7 @@ class TwitterNotifier(object):
|
||||||
|
|
||||||
def return_config_options(self):
|
def return_config_options(self):
|
||||||
config_option = [{'label': 'Instructions',
|
config_option = [{'label': 'Instructions',
|
||||||
'description': 'Step 1: Visit <a href="https://apps.twitter.com/" target="_blank"> \
|
'description': 'Step 1: Visit <a href="' + helpers.anon_url('https://apps.twitter.com') + '" target="_blank"> \
|
||||||
Twitter Apps</a> to <strong>Create New App</strong>. A vaild "Website" is not required.<br>\
|
Twitter Apps</a> to <strong>Create New App</strong>. A vaild "Website" is not required.<br>\
|
||||||
Step 2: Go to <strong>Keys and Access Tokens</strong> and click \
|
Step 2: Go to <strong>Keys and Access Tokens</strong> and click \
|
||||||
<strong>Create my access token</strong>.<br>\
|
<strong>Create my access token</strong>.<br>\
|
||||||
|
@ -1301,7 +1318,7 @@ class TwitterNotifier(object):
|
||||||
{'label': 'Include Subject Line',
|
{'label': 'Include Subject Line',
|
||||||
'value': self.incl_subject,
|
'value': self.incl_subject,
|
||||||
'name': 'twitter_incl_subject',
|
'name': 'twitter_incl_subject',
|
||||||
'description': 'Include the subject line in the notifications.',
|
'description': 'Include the subject line with the notifications.',
|
||||||
'input_type': 'checkbox'
|
'input_type': 'checkbox'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -1625,7 +1642,8 @@ class IFTTT(object):
|
||||||
config_option = [{'label': 'Ifttt Maker Channel Key',
|
config_option = [{'label': 'Ifttt Maker Channel Key',
|
||||||
'value': self.apikey,
|
'value': self.apikey,
|
||||||
'name': 'ifttt_key',
|
'name': 'ifttt_key',
|
||||||
'description': 'Your Ifttt key. You can get a key from <a href="https://ifttt.com/maker" target="_blank">here</a>.',
|
'description': 'Your Ifttt key. You can get a key from'
|
||||||
|
' <a href="' + helpers.anon_url('https://ifttt.com/maker') + '" target="_blank">here</a>.',
|
||||||
'input_type': 'text'
|
'input_type': 'text'
|
||||||
},
|
},
|
||||||
{'label': 'Ifttt Event',
|
{'label': 'Ifttt Event',
|
||||||
|
@ -1699,19 +1717,23 @@ class TELEGRAM(object):
|
||||||
config_option = [{'label': 'Telegram Bot Token',
|
config_option = [{'label': 'Telegram Bot Token',
|
||||||
'value': self.bot_token,
|
'value': self.bot_token,
|
||||||
'name': 'telegram_bot_token',
|
'name': 'telegram_bot_token',
|
||||||
'description': 'Your Telegram bot token. Contact <a href="http://telegram.me/BotFather" target="_blank">@BotFather</a> on Telegram to get one.',
|
'description': 'Your Telegram bot token. '
|
||||||
|
'Contact <a href="' + helpers.anon_url('https://telegram.me/BotFather') + '" target="_blank">@BotFather</a>'
|
||||||
|
' on Telegram to get one.',
|
||||||
'input_type': 'text'
|
'input_type': 'text'
|
||||||
},
|
},
|
||||||
{'label': 'Telegram Chat ID, Group ID, or Channel Username',
|
{'label': 'Telegram Chat ID, Group ID, or Channel Username',
|
||||||
'value': self.chat_id,
|
'value': self.chat_id,
|
||||||
'name': 'telegram_chat_id',
|
'name': 'telegram_chat_id',
|
||||||
'description': 'Your Telegram Chat ID, Group ID, or @channelusername. Contact <a href="http://telegram.me/myidbot" target="_blank">@myidbot</a> on Telegram to get an ID.',
|
'description': 'Your Telegram Chat ID, Group ID, or @channelusername. '
|
||||||
|
'Contact <a href="' + helpers.anon_url('https://telegram.me/myidbot') + '" target="_blank">@myidbot</a>'
|
||||||
|
' on Telegram to get an ID.',
|
||||||
'input_type': 'text'
|
'input_type': 'text'
|
||||||
},
|
},
|
||||||
{'label': 'Include Subject Line',
|
{'label': 'Include Subject Line',
|
||||||
'value': self.incl_subject,
|
'value': self.incl_subject,
|
||||||
'name': 'telegram_incl_subject',
|
'name': 'telegram_incl_subject',
|
||||||
'description': 'Include the subject line in the notifications.',
|
'description': 'Include the subject line with the notifications.',
|
||||||
'input_type': 'checkbox'
|
'input_type': 'checkbox'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -1809,7 +1831,7 @@ class SLACK(object):
|
||||||
{'label': 'Include Subject Line',
|
{'label': 'Include Subject Line',
|
||||||
'value': self.incl_subject,
|
'value': self.incl_subject,
|
||||||
'name': 'slack_incl_subject',
|
'name': 'slack_incl_subject',
|
||||||
'description': 'Include the subject line in the notifications.',
|
'description': 'Include the subject line with the notifications.',
|
||||||
'input_type': 'checkbox'
|
'input_type': 'checkbox'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -1880,14 +1902,14 @@ class Scripts(object):
|
||||||
elif notify_action == 'resume':
|
elif notify_action == 'resume':
|
||||||
script = plexpy.CONFIG.SCRIPTS_ON_RESUME_SCRIPT
|
script = plexpy.CONFIG.SCRIPTS_ON_RESUME_SCRIPT
|
||||||
|
|
||||||
|
elif notify_action == 'watched':
|
||||||
|
script = plexpy.CONFIG.SCRIPTS_ON_WATCHED_SCRIPT
|
||||||
|
|
||||||
elif notify_action == 'buffer':
|
elif notify_action == 'buffer':
|
||||||
script = plexpy.CONFIG.SCRIPTS_ON_BUFFER_SCRIPT
|
script = plexpy.CONFIG.SCRIPTS_ON_BUFFER_SCRIPT
|
||||||
|
|
||||||
elif notify_action == 'extdown':
|
elif notify_action == 'created':
|
||||||
script = plexpy.CONFIG.SCRIPTS_ON_EXTDOWN_SCRIPT
|
script = plexpy.CONFIG.SCRIPTS_ON_CREATED_SCRIPT
|
||||||
|
|
||||||
elif notify_action == 'extup':
|
|
||||||
script = plexpy.CONFIG.SCRIPTS_ON_EXTUP_SCRIPT
|
|
||||||
|
|
||||||
elif notify_action == 'intdown':
|
elif notify_action == 'intdown':
|
||||||
script = plexpy.CONFIG.SCRIPTS_ON_INTDOWN_SCRIPT
|
script = plexpy.CONFIG.SCRIPTS_ON_INTDOWN_SCRIPT
|
||||||
|
@ -1895,11 +1917,14 @@ class Scripts(object):
|
||||||
elif notify_action == 'intup':
|
elif notify_action == 'intup':
|
||||||
script = plexpy.CONFIG.SCRIPTS_ON_INTUP_SCRIPT
|
script = plexpy.CONFIG.SCRIPTS_ON_INTUP_SCRIPT
|
||||||
|
|
||||||
elif notify_action == 'created':
|
elif notify_action == 'extdown':
|
||||||
script = plexpy.CONFIG.SCRIPTS_ON_CREATED_SCRIPT
|
script = plexpy.CONFIG.SCRIPTS_ON_EXTDOWN_SCRIPT
|
||||||
|
|
||||||
elif notify_action == 'watched':
|
elif notify_action == 'extup':
|
||||||
script = plexpy.CONFIG.SCRIPTS_ON_WATCHED_SCRIPT
|
script = plexpy.CONFIG.SCRIPTS_ON_EXTUP_SCRIPT
|
||||||
|
|
||||||
|
elif notify_action == 'pmsupdate':
|
||||||
|
script = plexpy.CONFIG.SCRIPTS_ON_PMSUPDATE_SCRIPT
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# For manual scripts
|
# For manual scripts
|
||||||
|
@ -2041,13 +2066,6 @@ class Scripts(object):
|
||||||
'input_type': 'select',
|
'input_type': 'select',
|
||||||
'select_options': self.list_scripts()
|
'select_options': self.list_scripts()
|
||||||
},
|
},
|
||||||
{'label': 'Plex Remote Access Down',
|
|
||||||
'value': plexpy.CONFIG.SCRIPTS_ON_EXTDOWN_SCRIPT,
|
|
||||||
'name': 'scripts_on_extdown_script',
|
|
||||||
'description': 'Choose the script for Plex remote access down.',
|
|
||||||
'input_type': 'select',
|
|
||||||
'select_options': self.list_scripts()
|
|
||||||
},
|
|
||||||
{'label': 'Plex Server Down',
|
{'label': 'Plex Server Down',
|
||||||
'value': plexpy.CONFIG.SCRIPTS_ON_INTDOWN_SCRIPT,
|
'value': plexpy.CONFIG.SCRIPTS_ON_INTDOWN_SCRIPT,
|
||||||
'name': 'scripts_on_intdown_script',
|
'name': 'scripts_on_intdown_script',
|
||||||
|
@ -2055,6 +2073,20 @@ class Scripts(object):
|
||||||
'input_type': 'select',
|
'input_type': 'select',
|
||||||
'select_options': self.list_scripts()
|
'select_options': self.list_scripts()
|
||||||
},
|
},
|
||||||
|
{'label': 'Plex Server Back Up',
|
||||||
|
'value': plexpy.CONFIG.SCRIPTS_ON_INTUP_SCRIPT,
|
||||||
|
'name': 'scripts_on_intup_script',
|
||||||
|
'description': 'Choose the script for Plex server back up.',
|
||||||
|
'input_type': 'select',
|
||||||
|
'select_options': self.list_scripts()
|
||||||
|
},
|
||||||
|
{'label': 'Plex Remote Access Down',
|
||||||
|
'value': plexpy.CONFIG.SCRIPTS_ON_EXTDOWN_SCRIPT,
|
||||||
|
'name': 'scripts_on_extdown_script',
|
||||||
|
'description': 'Choose the script for Plex remote access down.',
|
||||||
|
'input_type': 'select',
|
||||||
|
'select_options': self.list_scripts()
|
||||||
|
},
|
||||||
{'label': 'Plex Remote Access Back Up',
|
{'label': 'Plex Remote Access Back Up',
|
||||||
'value': plexpy.CONFIG.SCRIPTS_ON_EXTUP_SCRIPT,
|
'value': plexpy.CONFIG.SCRIPTS_ON_EXTUP_SCRIPT,
|
||||||
'name': 'scripts_on_extup_script',
|
'name': 'scripts_on_extup_script',
|
||||||
|
@ -2062,10 +2094,10 @@ class Scripts(object):
|
||||||
'input_type': 'select',
|
'input_type': 'select',
|
||||||
'select_options': self.list_scripts()
|
'select_options': self.list_scripts()
|
||||||
},
|
},
|
||||||
{'label': 'Plex Server Back Up',
|
{'label': 'Plex Update Available',
|
||||||
'value': plexpy.CONFIG.SCRIPTS_ON_INTUP_SCRIPT,
|
'value': plexpy.CONFIG.SCRIPTS_ON_PMSUPDATE_SCRIPT,
|
||||||
'name': 'scripts_on_intup_script',
|
'name': 'scripts_on_pmsupdate_script',
|
||||||
'description': 'Choose the script for Plex server back up.',
|
'description': 'Choose the script for Plex update available.',
|
||||||
'input_type': 'select',
|
'input_type': 'select',
|
||||||
'select_options': self.list_scripts()
|
'select_options': self.list_scripts()
|
||||||
}
|
}
|
||||||
|
@ -2082,6 +2114,7 @@ class FacebookNotifier(object):
|
||||||
self.app_id = plexpy.CONFIG.FACEBOOK_APP_ID
|
self.app_id = plexpy.CONFIG.FACEBOOK_APP_ID
|
||||||
self.app_secret = plexpy.CONFIG.FACEBOOK_APP_SECRET
|
self.app_secret = plexpy.CONFIG.FACEBOOK_APP_SECRET
|
||||||
self.group_id = plexpy.CONFIG.FACEBOOK_GROUP
|
self.group_id = plexpy.CONFIG.FACEBOOK_GROUP
|
||||||
|
self.incl_pmslink = plexpy.CONFIG.FACEBOOK_INCL_PMSLINK
|
||||||
self.incl_poster = plexpy.CONFIG.FACEBOOK_INCL_POSTER
|
self.incl_poster = plexpy.CONFIG.FACEBOOK_INCL_POSTER
|
||||||
self.incl_subject = plexpy.CONFIG.FACEBOOK_INCL_SUBJECT
|
self.incl_subject = plexpy.CONFIG.FACEBOOK_INCL_SUBJECT
|
||||||
|
|
||||||
|
@ -2139,10 +2172,27 @@ class FacebookNotifier(object):
|
||||||
poster_url = metadata.get('poster_url','')
|
poster_url = metadata.get('poster_url','')
|
||||||
|
|
||||||
if poster_url:
|
if poster_url:
|
||||||
if metadata['media_type'] == 'movie' or metadata['media_type'] == 'show':
|
if metadata['media_type'] == 'movie':
|
||||||
title = metadata['title']
|
title = metadata['title']
|
||||||
subtitle = metadata['year']
|
subtitle = metadata['year']
|
||||||
rating_key = metadata['rating_key']
|
rating_key = metadata['rating_key']
|
||||||
|
if metadata.get('imdb_url',''):
|
||||||
|
poster_link = metadata.get('imdb_url', '')
|
||||||
|
caption = 'View on IMDB.'
|
||||||
|
elif metadata.get('themoviedb_url',''):
|
||||||
|
poster_link = metadata.get('themoviedb_url', '')
|
||||||
|
caption = 'View on The Movie Database.'
|
||||||
|
|
||||||
|
elif metadata['media_type'] == 'show':
|
||||||
|
title = metadata['title']
|
||||||
|
subtitle = metadata['year']
|
||||||
|
rating_key = metadata['rating_key']
|
||||||
|
if metadata.get('thetvdb_url',''):
|
||||||
|
poster_link = metadata.get('thetvdb_url', '')
|
||||||
|
caption = 'View on TheTVDB.'
|
||||||
|
elif metadata.get('themoviedb_url',''):
|
||||||
|
poster_link = metadata.get('themoviedb_url', '')
|
||||||
|
caption = 'View on The Movie Database.'
|
||||||
|
|
||||||
elif metadata['media_type'] == 'episode':
|
elif metadata['media_type'] == 'episode':
|
||||||
title = '%s - %s' % (metadata['grandparent_title'], metadata['title'])
|
title = '%s - %s' % (metadata['grandparent_title'], metadata['title'])
|
||||||
|
@ -2150,26 +2200,44 @@ class FacebookNotifier(object):
|
||||||
'\xc2\xb7'.decode('utf8'),
|
'\xc2\xb7'.decode('utf8'),
|
||||||
metadata['media_index'])
|
metadata['media_index'])
|
||||||
rating_key = metadata['rating_key']
|
rating_key = metadata['rating_key']
|
||||||
|
if metadata.get('thetvdb_url',''):
|
||||||
|
poster_link = metadata.get('thetvdb_url', '')
|
||||||
|
caption = 'View on TheTVDB.'
|
||||||
|
elif metadata.get('themoviedb_url',''):
|
||||||
|
poster_link = metadata.get('themoviedb_url', '')
|
||||||
|
caption = 'View on The Movie Database.'
|
||||||
|
|
||||||
elif metadata['media_type'] == 'artist':
|
elif metadata['media_type'] == 'artist':
|
||||||
title = metadata['title']
|
title = metadata['title']
|
||||||
subtitle = ''
|
subtitle = ''
|
||||||
rating_key = metadata['rating_key']
|
rating_key = metadata['rating_key']
|
||||||
|
if metadata.get('lastfm_url',''):
|
||||||
|
poster_link = metadata.get('lastfm_url', '')
|
||||||
|
caption = 'View on Last.fm.'
|
||||||
|
|
||||||
elif metadata['media_type'] == 'track':
|
elif metadata['media_type'] == 'track':
|
||||||
title = '%s - %s' % (metadata['grandparent_title'], metadata['title'])
|
title = '%s - %s' % (metadata['grandparent_title'], metadata['title'])
|
||||||
subtitle = metadata['parent_title']
|
subtitle = metadata['parent_title']
|
||||||
rating_key = metadata['parent_rating_key']
|
rating_key = metadata['parent_rating_key']
|
||||||
|
if metadata.get('lastfm_url',''):
|
||||||
caption = 'View in Plex Web.'
|
poster_link = metadata.get('lastfm_url', '')
|
||||||
|
caption = 'View on Last.fm.'
|
||||||
|
|
||||||
# Build Facebook post attachment
|
# Build Facebook post attachment
|
||||||
attachment['link'] = 'http://app.plex.tv/web/app#!/server/' + plexpy.CONFIG.PMS_IDENTIFIER + \
|
if self.incl_pmslink:
|
||||||
'/details/%2Flibrary%2Fmetadata%2F' + rating_key
|
caption = 'View on Plex Web.'
|
||||||
|
attachment['link'] = 'http://app.plex.tv/web/app#!/server/' + plexpy.CONFIG.PMS_IDENTIFIER + \
|
||||||
|
'/details/%2Flibrary%2Fmetadata%2F' + rating_key
|
||||||
|
attachment['caption'] = caption
|
||||||
|
elif poster_link:
|
||||||
|
attachment['link'] = poster_link
|
||||||
|
attachment['caption'] = caption
|
||||||
|
else:
|
||||||
|
attachment['link'] = poster_url
|
||||||
|
|
||||||
attachment['picture'] = poster_url
|
attachment['picture'] = poster_url
|
||||||
attachment['name'] = title
|
attachment['name'] = title
|
||||||
attachment['description'] = subtitle
|
attachment['description'] = subtitle
|
||||||
attachment['caption'] = caption
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
api.put_wall_post(profile_id=self.group_id, message=message, attachment=attachment)
|
api.put_wall_post(profile_id=self.group_id, message=message, attachment=attachment)
|
||||||
|
@ -2186,7 +2254,7 @@ class FacebookNotifier(object):
|
||||||
def return_config_options(self):
|
def return_config_options(self):
|
||||||
config_option = [{'label': 'Instructions',
|
config_option = [{'label': 'Instructions',
|
||||||
'description': '<strong>Facebook notifications are currently experimental!</strong><br><br> \
|
'description': '<strong>Facebook notifications are currently experimental!</strong><br><br> \
|
||||||
Step 1: Visit <a href="https://developers.facebook.com/apps/" target="_blank"> \
|
Step 1: Visit <a href="' + helpers.anon_url('https://developers.facebook.com/apps') + '" target="_blank"> \
|
||||||
Facebook Developers</a> to add a new app using <strong>basic setup</strong>.<br>\
|
Facebook Developers</a> to add a new app using <strong>basic setup</strong>.<br>\
|
||||||
Step 2: Go to <strong>Settings > Basic</strong> and fill in a \
|
Step 2: Go to <strong>Settings > Basic</strong> and fill in a \
|
||||||
<strong>Contact Email</strong>.<br>\
|
<strong>Contact Email</strong>.<br>\
|
||||||
|
@ -2195,7 +2263,7 @@ class FacebookNotifier(object):
|
||||||
Step 4: Go to <strong>App Review</strong> and toggle public to <strong>Yes</strong>.<br>\
|
Step 4: Go to <strong>App Review</strong> and toggle public to <strong>Yes</strong>.<br>\
|
||||||
Step 5: Fill in the <strong>PlexPy URL</strong> below with the exact same URL from Step 3.<br>\
|
Step 5: Fill in the <strong>PlexPy URL</strong> below with the exact same URL from Step 3.<br>\
|
||||||
Step 6: Fill in the <strong>App ID</strong> and <strong>App Secret</strong> below.<br>\
|
Step 6: Fill in the <strong>App ID</strong> and <strong>App Secret</strong> below.<br>\
|
||||||
Step 7: Click the <strong>Request Authorization</strong> button below.<br> \
|
Step 7: Click the <strong>Request Authorization</strong> button below.<br>\
|
||||||
Step 8: Fill in the <strong>Group ID</strong> below.',
|
Step 8: Fill in the <strong>Group ID</strong> below.',
|
||||||
'input_type': 'help'
|
'input_type': 'help'
|
||||||
},
|
},
|
||||||
|
@ -2232,13 +2300,20 @@ class FacebookNotifier(object):
|
||||||
{'label': 'Include Poster Image',
|
{'label': 'Include Poster Image',
|
||||||
'value': self.incl_poster,
|
'value': self.incl_poster,
|
||||||
'name': 'facebook_incl_poster',
|
'name': 'facebook_incl_poster',
|
||||||
'description': 'Include a poster and link in the notifications.',
|
'description': 'Include a poster with the notifications.',
|
||||||
|
'input_type': 'checkbox'
|
||||||
|
},
|
||||||
|
{'label': 'Include Link to Plex Web',
|
||||||
|
'value': self.incl_pmslink,
|
||||||
|
'name': 'facebook_incl_pmslink',
|
||||||
|
'description': 'Include a link to the media in Plex Web with the notifications.<br>'
|
||||||
|
'If disabled, the link will go to IMDB, TVDB, TMDb, or Last.fm instead, if available.',
|
||||||
'input_type': 'checkbox'
|
'input_type': 'checkbox'
|
||||||
},
|
},
|
||||||
{'label': 'Include Subject Line',
|
{'label': 'Include Subject Line',
|
||||||
'value': self.incl_subject,
|
'value': self.incl_subject,
|
||||||
'name': 'facebook_incl_subject',
|
'name': 'facebook_incl_subject',
|
||||||
'description': 'Include the subject line in the notifications.',
|
'description': 'Include the subject line with the notifications.',
|
||||||
'input_type': 'checkbox'
|
'input_type': 'checkbox'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -251,7 +251,7 @@ def import_from_plexwatch(database=None, table_name=None, import_ignore_interval
|
||||||
hours=0, minutes=0, seconds=0)
|
hours=0, minutes=0, seconds=0)
|
||||||
plexpy.schedule_job(activity_pinger.check_recently_added, 'Check for recently added items',
|
plexpy.schedule_job(activity_pinger.check_recently_added, 'Check for recently added items',
|
||||||
hours=0, minutes=0, seconds=0)
|
hours=0, minutes=0, seconds=0)
|
||||||
plexpy.schedule_job(activity_pinger.check_server_response, 'Check for server response',
|
plexpy.schedule_job(activity_pinger.check_server_response, 'Check for Plex remote access',
|
||||||
hours=0, minutes=0, seconds=0)
|
hours=0, minutes=0, seconds=0)
|
||||||
|
|
||||||
ap = activity_processor.ActivityProcessor()
|
ap = activity_processor.ActivityProcessor()
|
||||||
|
@ -302,7 +302,7 @@ def import_from_plexwatch(database=None, table_name=None, import_ignore_interval
|
||||||
|
|
||||||
# Skip line if we don't have a ratingKey to work with
|
# Skip line if we don't have a ratingKey to work with
|
||||||
if not row['rating_key']:
|
if not row['rating_key']:
|
||||||
logger.error(u"PlexPy Importer :: Skipping record due to null ratingRey.")
|
logger.error(u"PlexPy Importer :: Skipping record due to null ratingKey.")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# If the user_id no longer exists in the friends list, pull it from the xml.
|
# If the user_id no longer exists in the friends list, pull it from the xml.
|
||||||
|
|
|
@ -389,6 +389,38 @@ class PmsConnect(object):
|
||||||
|
|
||||||
return request
|
return request
|
||||||
|
|
||||||
|
def put_updater(self, output_format=''):
|
||||||
|
"""
|
||||||
|
Refresh updater status.
|
||||||
|
|
||||||
|
Optional parameters: output_format { dict, json }
|
||||||
|
|
||||||
|
Output: array
|
||||||
|
"""
|
||||||
|
uri = '/updater/check?download=0'
|
||||||
|
request = self.request_handler.make_request(uri=uri,
|
||||||
|
proto=self.protocol,
|
||||||
|
request_type='PUT',
|
||||||
|
output_format=output_format)
|
||||||
|
|
||||||
|
return request
|
||||||
|
|
||||||
|
def get_updater(self, output_format=''):
|
||||||
|
"""
|
||||||
|
Return updater status.
|
||||||
|
|
||||||
|
Optional parameters: output_format { dict, json }
|
||||||
|
|
||||||
|
Output: array
|
||||||
|
"""
|
||||||
|
uri = '/updater/status'
|
||||||
|
request = self.request_handler.make_request(uri=uri,
|
||||||
|
proto=self.protocol,
|
||||||
|
request_type='GET',
|
||||||
|
output_format=output_format)
|
||||||
|
|
||||||
|
return request
|
||||||
|
|
||||||
def get_recently_added_details(self, section_id='', count='0'):
|
def get_recently_added_details(self, section_id='', count='0'):
|
||||||
"""
|
"""
|
||||||
Return processed and validated list of recently added items.
|
Return processed and validated list of recently added items.
|
||||||
|
@ -1008,7 +1040,7 @@ class PmsConnect(object):
|
||||||
'user_id': user_details['user_id'],
|
'user_id': user_details['user_id'],
|
||||||
'friendly_name': user_details['friendly_name'],
|
'friendly_name': user_details['friendly_name'],
|
||||||
'user_thumb': user_details['user_thumb'],
|
'user_thumb': user_details['user_thumb'],
|
||||||
'ip_address': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'address').split(':')[-1],
|
'ip_address': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'address').split('::ffff:')[-1],
|
||||||
'player': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'title'),
|
'player': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'title'),
|
||||||
'platform': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'platform'),
|
'platform': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'platform'),
|
||||||
'machine_id': machine_id,
|
'machine_id': machine_id,
|
||||||
|
@ -1130,7 +1162,7 @@ class PmsConnect(object):
|
||||||
'user_id': user_details['user_id'],
|
'user_id': user_details['user_id'],
|
||||||
'friendly_name': user_details['friendly_name'],
|
'friendly_name': user_details['friendly_name'],
|
||||||
'user_thumb': user_details['user_thumb'],
|
'user_thumb': user_details['user_thumb'],
|
||||||
'ip_address': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'address').split(':')[-1],
|
'ip_address': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'address').split('::ffff:')[-1],
|
||||||
'player': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'title'),
|
'player': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'title'),
|
||||||
'platform': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'platform'),
|
'platform': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'platform'),
|
||||||
'machine_id': machine_id,
|
'machine_id': machine_id,
|
||||||
|
@ -1188,7 +1220,7 @@ class PmsConnect(object):
|
||||||
'user_id': user_details['user_id'],
|
'user_id': user_details['user_id'],
|
||||||
'friendly_name': user_details['friendly_name'],
|
'friendly_name': user_details['friendly_name'],
|
||||||
'user_thumb': user_details['user_thumb'],
|
'user_thumb': user_details['user_thumb'],
|
||||||
'ip_address': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'address').split(':')[-1],
|
'ip_address': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'address').split('::ffff:')[-1],
|
||||||
'player': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'title'),
|
'player': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'title'),
|
||||||
'platform': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'platform'),
|
'platform': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'platform'),
|
||||||
'machine_id': machine_id,
|
'machine_id': machine_id,
|
||||||
|
@ -1246,7 +1278,7 @@ class PmsConnect(object):
|
||||||
'user_id': user_details['user_id'],
|
'user_id': user_details['user_id'],
|
||||||
'friendly_name': user_details['friendly_name'],
|
'friendly_name': user_details['friendly_name'],
|
||||||
'user_thumb': user_details['user_thumb'],
|
'user_thumb': user_details['user_thumb'],
|
||||||
'ip_address': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'address').split(':')[-1],
|
'ip_address': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'address').split('::ffff:')[-1],
|
||||||
'player': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'title'),
|
'player': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'title'),
|
||||||
'platform': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'platform'),
|
'platform': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'platform'),
|
||||||
'machine_id': machine_id,
|
'machine_id': machine_id,
|
||||||
|
@ -1337,7 +1369,7 @@ class PmsConnect(object):
|
||||||
'user_id': user_details['user_id'],
|
'user_id': user_details['user_id'],
|
||||||
'friendly_name': user_details['friendly_name'],
|
'friendly_name': user_details['friendly_name'],
|
||||||
'user_thumb': user_details['user_thumb'],
|
'user_thumb': user_details['user_thumb'],
|
||||||
'ip_address': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'address').split(':')[-1],
|
'ip_address': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'address').split('::ffff:')[-1],
|
||||||
'player': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'title'),
|
'player': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'title'),
|
||||||
'platform': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'platform'),
|
'platform': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'platform'),
|
||||||
'machine_id': machine_id,
|
'machine_id': machine_id,
|
||||||
|
@ -1479,7 +1511,7 @@ class PmsConnect(object):
|
||||||
xml_head = identity.getElementsByTagName('MediaContainer')
|
xml_head = identity.getElementsByTagName('MediaContainer')
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Pmsconnect :: Unable to parse XML for get_local_server_identity: %s." % e)
|
logger.warn(u"PlexPy Pmsconnect :: Unable to parse XML for get_local_server_identity: %s." % e)
|
||||||
return []
|
return {}
|
||||||
|
|
||||||
server_identity = {}
|
server_identity = {}
|
||||||
for a in xml_head:
|
for a in xml_head:
|
||||||
|
@ -1995,3 +2027,40 @@ class PmsConnect(object):
|
||||||
}
|
}
|
||||||
|
|
||||||
return server_response
|
return server_response
|
||||||
|
|
||||||
|
def get_update_staus(self):
|
||||||
|
# Refresh the Plex updater status first
|
||||||
|
self.put_updater()
|
||||||
|
updater_status = self.get_updater(output_format='xml')
|
||||||
|
|
||||||
|
try:
|
||||||
|
xml_head = updater_status.getElementsByTagName('MediaContainer')
|
||||||
|
except Exception as e:
|
||||||
|
logger.warn(u"PlexPy Pmsconnect :: Unable to parse XML for get_update_staus: %s." % e)
|
||||||
|
|
||||||
|
# Catch the malformed XML on certain PMX version.
|
||||||
|
# XML parser helper returns empty list if there is an error parsing XML
|
||||||
|
if updater_status == []:
|
||||||
|
logger.warn(u"Plex API updater XML is broken on the current PMS version. Please update your PMS manually.")
|
||||||
|
logger.info(u"PlexPy is unable to check for Plex updates. Disabling check for Plex updates.")
|
||||||
|
|
||||||
|
# Disable check for Plex updates
|
||||||
|
plexpy.CONFIG.MONITOR_PMS_UPDATES = 0
|
||||||
|
plexpy.initialize_scheduler()
|
||||||
|
plexpy.CONFIG.write()
|
||||||
|
|
||||||
|
return {}
|
||||||
|
|
||||||
|
updater_info = {}
|
||||||
|
for a in xml_head:
|
||||||
|
if a.getElementsByTagName('Release'):
|
||||||
|
release = a.getElementsByTagName('Release')
|
||||||
|
for item in release:
|
||||||
|
updater_info = {'can_install': helpers.get_xml_attr(a, 'canInstall'),
|
||||||
|
'download_url': helpers.get_xml_attr(a, 'downloadURL'),
|
||||||
|
'version': helpers.get_xml_attr(item, 'version'),
|
||||||
|
'state': helpers.get_xml_attr(item, 'state'),
|
||||||
|
'changelog': helpers.get_xml_attr(item, 'fixed')
|
||||||
|
}
|
||||||
|
|
||||||
|
return updater_info
|
||||||
|
|
|
@ -50,8 +50,7 @@ class Users(object):
|
||||||
'session_history_metadata.year',
|
'session_history_metadata.year',
|
||||||
'session_history_metadata.media_index',
|
'session_history_metadata.media_index',
|
||||||
'session_history_metadata.parent_media_index',
|
'session_history_metadata.parent_media_index',
|
||||||
'session_history_media_info.video_decision',
|
'session_history_media_info.transcode_decision',
|
||||||
'session_history_media_info.audio_decision',
|
|
||||||
'users.do_notify as do_notify',
|
'users.do_notify as do_notify',
|
||||||
'users.keep_history as keep_history'
|
'users.keep_history as keep_history'
|
||||||
]
|
]
|
||||||
|
@ -117,8 +116,7 @@ class Users(object):
|
||||||
'year': item['year'],
|
'year': item['year'],
|
||||||
'media_index': item['media_index'],
|
'media_index': item['media_index'],
|
||||||
'parent_media_index': item['parent_media_index'],
|
'parent_media_index': item['parent_media_index'],
|
||||||
'video_decision': item['video_decision'],
|
'transcode_decision': item['transcode_decision'],
|
||||||
'audio_decision': item['audio_decision'],
|
|
||||||
'do_notify': helpers.checked(item['do_notify']),
|
'do_notify': helpers.checked(item['do_notify']),
|
||||||
'keep_history': helpers.checked(item['keep_history'])
|
'keep_history': helpers.checked(item['keep_history'])
|
||||||
}
|
}
|
||||||
|
@ -154,8 +152,7 @@ class Users(object):
|
||||||
'session_history_metadata.year',
|
'session_history_metadata.year',
|
||||||
'session_history_metadata.media_index',
|
'session_history_metadata.media_index',
|
||||||
'session_history_metadata.parent_media_index',
|
'session_history_metadata.parent_media_index',
|
||||||
'session_history_media_info.video_decision',
|
'session_history_media_info.transcode_decision',
|
||||||
'session_history_media_info.audio_decision',
|
|
||||||
'session_history.user',
|
'session_history.user',
|
||||||
'session_history.user_id as custom_user_id',
|
'session_history.user_id as custom_user_id',
|
||||||
'(CASE WHEN users.friendly_name IS NULL THEN users.username ELSE \
|
'(CASE WHEN users.friendly_name IS NULL THEN users.username ELSE \
|
||||||
|
@ -213,8 +210,7 @@ class Users(object):
|
||||||
'year': item['year'],
|
'year': item['year'],
|
||||||
'media_index': item['media_index'],
|
'media_index': item['media_index'],
|
||||||
'parent_media_index': item['parent_media_index'],
|
'parent_media_index': item['parent_media_index'],
|
||||||
'video_decision': item['video_decision'],
|
'transcode_decision': item['transcode_decision'],
|
||||||
'audio_decision': item['audio_decision'],
|
|
||||||
'friendly_name': item['friendly_name']
|
'friendly_name': item['friendly_name']
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -245,7 +241,7 @@ class Users(object):
|
||||||
def get_details(self, user_id=None, user=None):
|
def get_details(self, user_id=None, user=None):
|
||||||
from plexpy import plextv
|
from plexpy import plextv
|
||||||
|
|
||||||
default_return = {'user_id': None,
|
default_return = {'user_id': 0,
|
||||||
'username': 'Local',
|
'username': 'Local',
|
||||||
'friendly_name': 'Local',
|
'friendly_name': 'Local',
|
||||||
'user_thumb': common.DEFAULT_USER_THUMB,
|
'user_thumb': common.DEFAULT_USER_THUMB,
|
||||||
|
@ -254,7 +250,7 @@ class Users(object):
|
||||||
'is_allow_sync': 0,
|
'is_allow_sync': 0,
|
||||||
'is_restricted': 0,
|
'is_restricted': 0,
|
||||||
'do_notify': 0,
|
'do_notify': 0,
|
||||||
'keep_history': 0
|
'keep_history': 1
|
||||||
}
|
}
|
||||||
|
|
||||||
if not user_id and not user:
|
if not user_id and not user:
|
||||||
|
@ -316,7 +312,8 @@ class Users(object):
|
||||||
return user_details
|
return user_details
|
||||||
|
|
||||||
else:
|
else:
|
||||||
logger.warn(u"PlexPy Users :: Unable to retrieve user from local database. Requesting user list refresh.")
|
logger.warn(u"PlexPy Users :: Unable to retrieve user %s from database. Requesting user list refresh."
|
||||||
|
% user_id if user_id else user)
|
||||||
# Let's first refresh the user list to make sure the user isn't newly added and not in the db yet
|
# Let's first refresh the user list to make sure the user isn't newly added and not in the db yet
|
||||||
plextv.refresh_users()
|
plextv.refresh_users()
|
||||||
|
|
||||||
|
@ -326,7 +323,8 @@ class Users(object):
|
||||||
return user_details
|
return user_details
|
||||||
|
|
||||||
else:
|
else:
|
||||||
logger.warn(u"PlexPy Users :: Unable to retrieve user from local database. Returning 'Local' user.")
|
logger.warn(u"PlexPy Users :: Unable to retrieve user %s from database. Returning 'Local' user."
|
||||||
|
% user_id if user_id else user)
|
||||||
# If there is no user data we must return something
|
# If there is no user data we must return something
|
||||||
# Use "Local" user to retain compatibility with PlexWatch database value
|
# Use "Local" user to retain compatibility with PlexWatch database value
|
||||||
return default_return
|
return default_return
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
PLEXPY_VERSION = "master"
|
PLEXPY_VERSION = "master"
|
||||||
PLEXPY_RELEASE_VERSION = "1.3.9"
|
PLEXPY_RELEASE_VERSION = "1.3.10"
|
||||||
|
|
|
@ -25,6 +25,7 @@ import websocket
|
||||||
|
|
||||||
name = 'websocket'
|
name = 'websocket'
|
||||||
opcode_data = (websocket.ABNF.OPCODE_TEXT, websocket.ABNF.OPCODE_BINARY)
|
opcode_data = (websocket.ABNF.OPCODE_TEXT, websocket.ABNF.OPCODE_BINARY)
|
||||||
|
ws_reconnect = False
|
||||||
|
|
||||||
|
|
||||||
def start_thread():
|
def start_thread():
|
||||||
|
@ -34,6 +35,11 @@ def start_thread():
|
||||||
threading.Thread(target=run).start()
|
threading.Thread(target=run).start()
|
||||||
|
|
||||||
|
|
||||||
|
def reconnect():
|
||||||
|
global ws_reconnect
|
||||||
|
ws_reconnect = True
|
||||||
|
|
||||||
|
|
||||||
def run():
|
def run():
|
||||||
from websocket import create_connection
|
from websocket import create_connection
|
||||||
|
|
||||||
|
@ -51,19 +57,21 @@ def run():
|
||||||
if plexpy.CONFIG.PMS_TOKEN:
|
if plexpy.CONFIG.PMS_TOKEN:
|
||||||
uri += '?X-Plex-Token=' + plexpy.CONFIG.PMS_TOKEN
|
uri += '?X-Plex-Token=' + plexpy.CONFIG.PMS_TOKEN
|
||||||
|
|
||||||
|
global ws_reconnect
|
||||||
|
ws_reconnect = False
|
||||||
ws_connected = False
|
ws_connected = False
|
||||||
reconnects = 0
|
reconnects = 0
|
||||||
|
|
||||||
# Try an open the websocket connection - if it fails after 15 retries fallback to polling
|
# Try an open the websocket connection - if it fails after 15 retries fallback to polling
|
||||||
while not ws_connected and reconnects <= 15:
|
while not ws_connected and reconnects <= 15:
|
||||||
try:
|
try:
|
||||||
logger.info(u'PlexPy WebSocket :: Opening%s websocket, connection attempt %s.' % (secure, str(reconnects + 1)))
|
logger.info(u"PlexPy WebSocket :: Opening%s websocket, connection attempt %s." % (secure, str(reconnects + 1)))
|
||||||
ws = create_connection(uri)
|
ws = create_connection(uri)
|
||||||
reconnects = 0
|
reconnects = 0
|
||||||
ws_connected = True
|
ws_connected = True
|
||||||
logger.info(u'PlexPy WebSocket :: Ready')
|
logger.info(u"PlexPy WebSocket :: Ready")
|
||||||
except IOError, e:
|
except IOError, e:
|
||||||
logger.error(u'PlexPy WebSocket :: %s.' % e)
|
logger.error(u"PlexPy WebSocket :: %s." % e)
|
||||||
reconnects += 1
|
reconnects += 1
|
||||||
time.sleep(5)
|
time.sleep(5)
|
||||||
|
|
||||||
|
@ -81,22 +89,30 @@ def run():
|
||||||
if reconnects > 1:
|
if reconnects > 1:
|
||||||
time.sleep(5)
|
time.sleep(5)
|
||||||
|
|
||||||
logger.warn(u'PlexPy WebSocket :: Connection has closed, reconnecting...')
|
logger.warn(u"PlexPy WebSocket :: Connection has closed, reconnecting...")
|
||||||
try:
|
try:
|
||||||
ws = create_connection(uri)
|
ws = create_connection(uri)
|
||||||
except IOError, e:
|
except IOError, e:
|
||||||
logger.info(u'PlexPy WebSocket :: %s.' % e)
|
logger.info(u"PlexPy WebSocket :: %s." % e)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
ws.shutdown()
|
||||||
ws_connected = False
|
ws_connected = False
|
||||||
break
|
break
|
||||||
|
|
||||||
if not ws_connected:
|
# Check if we recieved a restart notification and close websocket connection cleanly
|
||||||
logger.error(u'PlexPy WebSocket :: Connection unavailable, falling back to polling.')
|
if ws_reconnect:
|
||||||
|
logger.info(u"PlexPy WebSocket :: Reconnecting websocket...")
|
||||||
|
ws.shutdown()
|
||||||
|
ws_connected = False
|
||||||
|
start_thread()
|
||||||
|
|
||||||
|
if not ws_connected and not ws_reconnect:
|
||||||
|
logger.error(u"PlexPy WebSocket :: Connection unavailable, falling back to polling.")
|
||||||
plexpy.POLLING_FAILOVER = True
|
plexpy.POLLING_FAILOVER = True
|
||||||
plexpy.initialize_scheduler()
|
plexpy.initialize_scheduler()
|
||||||
|
|
||||||
logger.debug(u'PlexPy WebSocket :: Leaving thread.')
|
logger.debug(u"PlexPy WebSocket :: Leaving thread.")
|
||||||
|
|
||||||
|
|
||||||
def receive(ws):
|
def receive(ws):
|
||||||
|
@ -124,7 +140,7 @@ def process(opcode, data):
|
||||||
try:
|
try:
|
||||||
info = json.loads(data)
|
info = json.loads(data)
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
logger.warn(u'PlexPy WebSocket :: Error decoding message from websocket: %s' % ex)
|
logger.warn(u"PlexPy WebSocket :: Error decoding message from websocket: %s" % ex)
|
||||||
logger.debug(data)
|
logger.debug(data)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,8 @@
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
|
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
from plexpy import logger, notifiers, plextv, pmsconnect, common, log_reader, datafactory, graphs, users, libraries, database
|
from plexpy import logger, notifiers, plextv, pmsconnect, common, log_reader, \
|
||||||
|
datafactory, graphs, users, libraries, database, web_socket
|
||||||
from plexpy.helpers import checked, addtoapi, get_ip, create_https_certificates
|
from plexpy.helpers import checked, addtoapi, get_ip, create_https_certificates
|
||||||
|
|
||||||
from mako.lookup import TemplateLookup
|
from mako.lookup import TemplateLookup
|
||||||
|
@ -253,6 +254,18 @@ class WebInterface(object):
|
||||||
logger.warn(u"Unable to retrieve data for get_recently_added.")
|
logger.warn(u"Unable to retrieve data for get_recently_added.")
|
||||||
return serve_template(templatename="recently_added.html", data=None)
|
return serve_template(templatename="recently_added.html", data=None)
|
||||||
|
|
||||||
|
@cherrypy.expose
|
||||||
|
def delete_temp_sessions(self):
|
||||||
|
|
||||||
|
result = database.delete_sessions()
|
||||||
|
|
||||||
|
if result:
|
||||||
|
cherrypy.response.headers['Content-type'] = 'application/json'
|
||||||
|
return json.dumps({'message': result})
|
||||||
|
else:
|
||||||
|
cherrypy.response.headers['Content-type'] = 'application/json'
|
||||||
|
return json.dumps({'message': 'no data received'})
|
||||||
|
|
||||||
|
|
||||||
##### Libraries #####
|
##### Libraries #####
|
||||||
|
|
||||||
|
@ -776,6 +789,10 @@ class WebInterface(object):
|
||||||
media_type = kwargs.get('media_type', "")
|
media_type = kwargs.get('media_type', "")
|
||||||
if media_type != 'all':
|
if media_type != 'all':
|
||||||
custom_where.append(['session_history.media_type', media_type])
|
custom_where.append(['session_history.media_type', media_type])
|
||||||
|
if 'transcode_decision' in kwargs:
|
||||||
|
transcode_decision = kwargs.get('transcode_decision', "")
|
||||||
|
if transcode_decision:
|
||||||
|
custom_where.append(['session_history_media_info.transcode_decision', transcode_decision])
|
||||||
|
|
||||||
data_factory = datafactory.DataFactory()
|
data_factory = datafactory.DataFactory()
|
||||||
history = data_factory.get_datatables_history(kwargs=kwargs, custom_where=custom_where, grouping=grouping, watched_percent=watched_percent)
|
history = data_factory.get_datatables_history(kwargs=kwargs, custom_where=custom_where, grouping=grouping, watched_percent=watched_percent)
|
||||||
|
@ -989,9 +1006,9 @@ class WebInterface(object):
|
||||||
logger.warn(u"Unable to retrieve data for get_stream_type_by_top_10_platforms.")
|
logger.warn(u"Unable to retrieve data for get_stream_type_by_top_10_platforms.")
|
||||||
|
|
||||||
@cherrypy.expose
|
@cherrypy.expose
|
||||||
def history_table_modal(self, start_date=None, **kwargs):
|
def history_table_modal(self, **kwargs):
|
||||||
|
|
||||||
return serve_template(templatename="history_table_modal.html", title="History Data", data=start_date)
|
return serve_template(templatename="history_table_modal.html", title="History Data", data=kwargs)
|
||||||
|
|
||||||
|
|
||||||
##### Sync #####
|
##### Sync #####
|
||||||
|
@ -1091,6 +1108,19 @@ class WebInterface(object):
|
||||||
cherrypy.response.headers['Content-type'] = 'application/json'
|
cherrypy.response.headers['Content-type'] = 'application/json'
|
||||||
return json.dumps(notifications)
|
return json.dumps(notifications)
|
||||||
|
|
||||||
|
@cherrypy.expose
|
||||||
|
@addtoapi()
|
||||||
|
def clearNotifyLogs(self, **kwargs):
|
||||||
|
data_factory = datafactory.DataFactory()
|
||||||
|
result = data_factory.delete_notification_log()
|
||||||
|
|
||||||
|
if result:
|
||||||
|
cherrypy.response.headers['Content-type'] = 'application/json'
|
||||||
|
return json.dumps({'message': result})
|
||||||
|
else:
|
||||||
|
cherrypy.response.headers['Content-type'] = 'application/json'
|
||||||
|
return json.dumps({'message': 'no data received'})
|
||||||
|
|
||||||
@cherrypy.expose
|
@cherrypy.expose
|
||||||
def clearLogs(self):
|
def clearLogs(self):
|
||||||
plexpy.LOG_LIST = []
|
plexpy.LOG_LIST = []
|
||||||
|
@ -1147,8 +1177,9 @@ class WebInterface(object):
|
||||||
"api_key": plexpy.CONFIG.API_KEY,
|
"api_key": plexpy.CONFIG.API_KEY,
|
||||||
"update_db_interval": plexpy.CONFIG.UPDATE_DB_INTERVAL,
|
"update_db_interval": plexpy.CONFIG.UPDATE_DB_INTERVAL,
|
||||||
"freeze_db": checked(plexpy.CONFIG.FREEZE_DB),
|
"freeze_db": checked(plexpy.CONFIG.FREEZE_DB),
|
||||||
"log_dir": plexpy.CONFIG.LOG_DIR,
|
"backup_dir": plexpy.CONFIG.BACKUP_DIR,
|
||||||
"cache_dir": plexpy.CONFIG.CACHE_DIR,
|
"cache_dir": plexpy.CONFIG.CACHE_DIR,
|
||||||
|
"log_dir": plexpy.CONFIG.LOG_DIR,
|
||||||
"check_github": checked(plexpy.CONFIG.CHECK_GITHUB),
|
"check_github": checked(plexpy.CONFIG.CHECK_GITHUB),
|
||||||
"interface_list": interface_list,
|
"interface_list": interface_list,
|
||||||
"cache_sizemb": plexpy.CONFIG.CACHE_SIZEMB,
|
"cache_sizemb": plexpy.CONFIG.CACHE_SIZEMB,
|
||||||
|
@ -1178,6 +1209,7 @@ class WebInterface(object):
|
||||||
"tv_notify_on_pause": checked(plexpy.CONFIG.TV_NOTIFY_ON_PAUSE),
|
"tv_notify_on_pause": checked(plexpy.CONFIG.TV_NOTIFY_ON_PAUSE),
|
||||||
"movie_notify_on_pause": checked(plexpy.CONFIG.MOVIE_NOTIFY_ON_PAUSE),
|
"movie_notify_on_pause": checked(plexpy.CONFIG.MOVIE_NOTIFY_ON_PAUSE),
|
||||||
"music_notify_on_pause": checked(plexpy.CONFIG.MUSIC_NOTIFY_ON_PAUSE),
|
"music_notify_on_pause": checked(plexpy.CONFIG.MUSIC_NOTIFY_ON_PAUSE),
|
||||||
|
"monitor_pms_updates": checked(plexpy.CONFIG.MONITOR_PMS_UPDATES),
|
||||||
"monitor_remote_access": checked(plexpy.CONFIG.MONITOR_REMOTE_ACCESS),
|
"monitor_remote_access": checked(plexpy.CONFIG.MONITOR_REMOTE_ACCESS),
|
||||||
"monitoring_interval": plexpy.CONFIG.MONITORING_INTERVAL,
|
"monitoring_interval": plexpy.CONFIG.MONITORING_INTERVAL,
|
||||||
"monitoring_use_websocket": checked(plexpy.CONFIG.MONITORING_USE_WEBSOCKET),
|
"monitoring_use_websocket": checked(plexpy.CONFIG.MONITORING_USE_WEBSOCKET),
|
||||||
|
@ -1219,6 +1251,8 @@ class WebInterface(object):
|
||||||
"notify_on_extup_body_text": plexpy.CONFIG.NOTIFY_ON_EXTUP_BODY_TEXT,
|
"notify_on_extup_body_text": plexpy.CONFIG.NOTIFY_ON_EXTUP_BODY_TEXT,
|
||||||
"notify_on_intup_subject_text": plexpy.CONFIG.NOTIFY_ON_INTUP_SUBJECT_TEXT,
|
"notify_on_intup_subject_text": plexpy.CONFIG.NOTIFY_ON_INTUP_SUBJECT_TEXT,
|
||||||
"notify_on_intup_body_text": plexpy.CONFIG.NOTIFY_ON_INTUP_BODY_TEXT,
|
"notify_on_intup_body_text": plexpy.CONFIG.NOTIFY_ON_INTUP_BODY_TEXT,
|
||||||
|
"notify_on_pmsupdate_subject_text": plexpy.CONFIG.NOTIFY_ON_PMSUPDATE_SUBJECT_TEXT,
|
||||||
|
"notify_on_pmsupdate_body_text": plexpy.CONFIG.NOTIFY_ON_PMSUPDATE_BODY_TEXT,
|
||||||
"notify_scripts_args_text": plexpy.CONFIG.NOTIFY_SCRIPTS_ARGS_TEXT,
|
"notify_scripts_args_text": plexpy.CONFIG.NOTIFY_SCRIPTS_ARGS_TEXT,
|
||||||
"home_stats_length": plexpy.CONFIG.HOME_STATS_LENGTH,
|
"home_stats_length": plexpy.CONFIG.HOME_STATS_LENGTH,
|
||||||
"home_stats_type": checked(plexpy.CONFIG.HOME_STATS_TYPE),
|
"home_stats_type": checked(plexpy.CONFIG.HOME_STATS_TYPE),
|
||||||
|
@ -1246,12 +1280,15 @@ class WebInterface(object):
|
||||||
"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",
|
||||||
"pms_is_remote", "home_stats_type", "group_history_tables", "notify_consecutive", "notify_upload_posters",
|
"pms_is_remote", "home_stats_type", "group_history_tables", "notify_consecutive", "notify_upload_posters",
|
||||||
"notify_recently_added", "notify_recently_added_grandparent", "monitor_remote_access", "get_file_sizes"
|
"notify_recently_added", "notify_recently_added_grandparent",
|
||||||
|
"monitor_pms_updates", "monitor_remote_access", "get_file_sizes"
|
||||||
]
|
]
|
||||||
for checked_config in checked_configs:
|
for checked_config in checked_configs:
|
||||||
if checked_config not in kwargs:
|
if checked_config not in kwargs:
|
||||||
# checked items should be zero or one. if they were not sent then the item was not checked
|
# checked items should be zero or one. if they were not sent then the item was not checked
|
||||||
kwargs[checked_config] = '0'
|
kwargs[checked_config] = 0
|
||||||
|
else:
|
||||||
|
kwargs[checked_config] = 1
|
||||||
|
|
||||||
# If http password exists in config, do not overwrite when blank value received
|
# If http password exists in config, do not overwrite when blank value received
|
||||||
if kwargs.get('http_password'):
|
if kwargs.get('http_password'):
|
||||||
|
@ -1274,13 +1311,14 @@ class WebInterface(object):
|
||||||
if kwargs.get('monitoring_interval') != str(plexpy.CONFIG.MONITORING_INTERVAL) or \
|
if kwargs.get('monitoring_interval') != str(plexpy.CONFIG.MONITORING_INTERVAL) or \
|
||||||
kwargs.get('refresh_libraries_interval') != str(plexpy.CONFIG.REFRESH_LIBRARIES_INTERVAL) or \
|
kwargs.get('refresh_libraries_interval') != str(plexpy.CONFIG.REFRESH_LIBRARIES_INTERVAL) or \
|
||||||
kwargs.get('refresh_users_interval') != str(plexpy.CONFIG.REFRESH_USERS_INTERVAL) or \
|
kwargs.get('refresh_users_interval') != str(plexpy.CONFIG.REFRESH_USERS_INTERVAL) or \
|
||||||
kwargs.get('notify_recently_added') != str(plexpy.CONFIG.NOTIFY_RECENTLY_ADDED) or \
|
kwargs.get('notify_recently_added') != plexpy.CONFIG.NOTIFY_RECENTLY_ADDED or \
|
||||||
kwargs.get('monitor_remote_access') != str(plexpy.CONFIG.MONITOR_REMOTE_ACCESS):
|
kwargs.get('monitor_pms_updates') != plexpy.CONFIG.MONITOR_PMS_UPDATES or \
|
||||||
|
kwargs.get('monitor_remote_access') != plexpy.CONFIG.MONITOR_REMOTE_ACCESS:
|
||||||
reschedule = True
|
reschedule = True
|
||||||
|
|
||||||
# If we change the SSL setting for PMS or PMS remote setting, make sure we grab the new url.
|
# If we change the SSL setting for PMS or PMS remote setting, make sure we grab the new url.
|
||||||
if kwargs.get('pms_ssl') != str(plexpy.CONFIG.PMS_SSL) or \
|
if kwargs.get('pms_ssl') != plexpy.CONFIG.PMS_SSL or \
|
||||||
kwargs.get('pms_is_remote') != str(plexpy.CONFIG.PMS_IS_REMOTE):
|
kwargs.get('pms_is_remote') != plexpy.CONFIG.PMS_IS_REMOTE:
|
||||||
server_changed = True
|
server_changed = True
|
||||||
|
|
||||||
# If we change the HTTPS setting, make sure we generate a new certificate.
|
# If we change the HTTPS setting, make sure we generate a new certificate.
|
||||||
|
@ -1327,6 +1365,7 @@ class WebInterface(object):
|
||||||
if server_changed:
|
if server_changed:
|
||||||
plextv.get_real_pms_url()
|
plextv.get_real_pms_url()
|
||||||
pmsconnect.get_server_friendly_name()
|
pmsconnect.get_server_friendly_name()
|
||||||
|
web_socket.reconnect()
|
||||||
|
|
||||||
# Reconfigure scheduler if intervals changed
|
# Reconfigure scheduler if intervals changed
|
||||||
if reschedule:
|
if reschedule:
|
||||||
|
@ -1630,11 +1669,16 @@ class WebInterface(object):
|
||||||
if source == 'history':
|
if source == 'history':
|
||||||
data_factory = datafactory.DataFactory()
|
data_factory = datafactory.DataFactory()
|
||||||
metadata = data_factory.get_metadata_details(rating_key=rating_key)
|
metadata = data_factory.get_metadata_details(rating_key=rating_key)
|
||||||
|
poster_url = data_factory.get_poster_url(metadata=metadata)
|
||||||
|
metadata['poster_url'] = poster_url
|
||||||
else:
|
else:
|
||||||
pms_connect = pmsconnect.PmsConnect()
|
pms_connect = pmsconnect.PmsConnect()
|
||||||
result = pms_connect.get_metadata_details(rating_key=rating_key, get_media_info=True)
|
result = pms_connect.get_metadata_details(rating_key=rating_key, get_media_info=True)
|
||||||
if result:
|
if result:
|
||||||
metadata = result['metadata']
|
metadata = result['metadata']
|
||||||
|
data_factory = datafactory.DataFactory()
|
||||||
|
poster_url = data_factory.get_poster_url(metadata=metadata)
|
||||||
|
metadata['poster_url'] = poster_url
|
||||||
|
|
||||||
if metadata:
|
if metadata:
|
||||||
return serve_template(templatename="info.html", data=metadata, title="Info", config=config, source=source)
|
return serve_template(templatename="info.html", data=metadata, title="Info", config=config, source=source)
|
||||||
|
@ -1681,6 +1725,22 @@ class WebInterface(object):
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@cherrypy.expose
|
||||||
|
def delete_poster_url(self, poster_url=''):
|
||||||
|
|
||||||
|
if poster_url:
|
||||||
|
data_factory = datafactory.DataFactory()
|
||||||
|
result = data_factory.delete_poster_url(poster_url=poster_url)
|
||||||
|
else:
|
||||||
|
result = None
|
||||||
|
|
||||||
|
if result:
|
||||||
|
cherrypy.response.headers['Content-type'] = 'application/json'
|
||||||
|
return json.dumps({'message': result})
|
||||||
|
else:
|
||||||
|
cherrypy.response.headers['Content-type'] = 'application/json'
|
||||||
|
return json.dumps({'message': 'no data received'})
|
||||||
|
|
||||||
|
|
||||||
##### Search #####
|
##### Search #####
|
||||||
|
|
||||||
|
@ -2183,3 +2243,9 @@ class WebInterface(object):
|
||||||
a = Api()
|
a = Api()
|
||||||
a.checkParams(*args, **kwargs)
|
a.checkParams(*args, **kwargs)
|
||||||
return a.fetchData()
|
return a.fetchData()
|
||||||
|
|
||||||
|
@cherrypy.expose
|
||||||
|
def check_pms_updater(self):
|
||||||
|
pms_connect = pmsconnect.PmsConnect()
|
||||||
|
result = pms_connect.get_update_staus()
|
||||||
|
return json.dumps(result)
|
Loading…
Add table
Add a link
Reference in a new issue