Massive code cleanup

* Finish up library pages (toggles and notifications)
* Update user pages to match library pages
* Fix no current activity bif thumbnail at the start of a stream
* Improved logging throughout PlexPy
This commit is contained in:
Jonathan Wong 2016-01-05 20:46:27 -08:00
parent 5fedac691d
commit 636f898da8
31 changed files with 2873 additions and 2715 deletions

View file

@ -174,42 +174,42 @@ from plexpy import version
</div> </div>
</form> </form>
</li> </li>
% if title=="Home": % if title == "Home":
<li class="active"><a href="home"><i class="fa fa-lg fa-home"></i></a></li> <li class="active"><a href="home"><i class="fa fa-lg fa-home"></i></a></li>
% else: % else:
<li><a href="home"><i class="fa fa-lg fa-home"></i></a></li> <li><a href="home"><i class="fa fa-lg fa-home"></i></a></li>
% endif % endif
% if title=="Libraries" or title=="Library": % if title == "Libraries" or title == "Library" or title == "Info":
<li class="active"><a href="libraries">Libraries</a></li> <li class="active"><a href="libraries">Libraries</a></li>
% else: % else:
<li><a href="libraries">Libraries</a></li> <li><a href="libraries">Libraries</a></li>
% endif % endif
% if title=="Users" or title=="User": % if title == "Users" or title == "User":
<li class="active"><a href="users">Users</a></li> <li class="active"><a href="users">Users</a></li>
% else: % else:
<li><a href="users">Users</a></li> <li><a href="users">Users</a></li>
% endif % endif
% if title=="History": % if title == "History":
<li class="active"><a href="history">History</a></li> <li class="active"><a href="history">History</a></li>
% else: % else:
<li><a href="history">History</a></li> <li><a href="history">History</a></li>
% endif % endif
% if title=="Graphs": % if title == "Graphs":
<li class="active"><a href="graphs">Graphs</a></li> <li class="active"><a href="graphs">Graphs</a></li>
% else: % else:
<li><a href="graphs">Graphs</a></li> <li><a href="graphs">Graphs</a></li>
% endif % endif
% if title=="Synced Items": % if title == "Synced Items":
<li class="active"><a href="sync">Synced Items</a></li> <li class="active"><a href="sync">Synced Items</a></li>
% else: % else:
<li><a href="sync">Synced Items</a></li> <li><a href="sync">Synced Items</a></li>
% endif % endif
% if title=="Log": % if title == "Log":
<li class="active"><a href="logs">Logs</a></li> <li class="active"><a href="logs">Logs</a></li>
% else: % else:
<li><a href="logs">Logs</a></li> <li><a href="logs">Logs</a></li>
% endif % endif
% if title=="Settings": % if title == "Settings":
<li class="active"><a href="settings">Settings</a></li> <li class="active"><a href="settings">Settings</a></li>
% else: % else:
<li><a href="settings">Settings</a></li> <li><a href="settings">Settings</a></li>

View file

@ -2463,6 +2463,7 @@ a .home-platforms-instance-list-oval:hover,
} }
#users-to-delete > li, #users-to-delete > li,
#users-to-purge > li, #users-to-purge > li,
#libraries-to-delete > li,
#libraries-to-purge > li { #libraries-to-purge > li {
color: #e9a049; color: #e9a049;
} }

View file

@ -72,9 +72,9 @@ DOCUMENTATION :: END
<a href="info?rating_key=${a['rating_key']}"> <a href="info?rating_key=${a['rating_key']}">
% endif % endif
<div class="dashboard-activity-poster"> <div class="dashboard-activity-poster">
% if a['media_type'] == 'movie' and not a['indexes']: % if (a['media_type'] == 'movie' and not a['indexes']) or (a['indexes'] and not a['view_offset']):
<div class="dashboard-activity-poster-face" style="background-image: url(pms_image_proxy?img=${a['art']}&width=500&height=280);"></div> <div class="dashboard-activity-poster-face" style="background-image: url(pms_image_proxy?img=${a['art']}&width=500&height=280);"></div>
% elif a['media_type'] == 'episode' and not a['indexes']: % elif (a['media_type'] == 'episode' and not a['indexes']) or (a['indexes'] and not a['view_offset']):
<div class="dashboard-activity-poster-face" style="background-image: url(pms_image_proxy?img=${a['art']}&width=500&height=280);"></div> <div class="dashboard-activity-poster-face" style="background-image: url(pms_image_proxy?img=${a['art']}&width=500&height=280);"></div>
% elif a['indexes']: % elif a['indexes']:
<div class="dashboard-activity-poster-face bif" style="background-image: url(pms_image_proxy?img=${a['bif_thumb']}&width=500&height=280); display: none;"></div> <div class="dashboard-activity-poster-face bif" style="background-image: url(pms_image_proxy?img=${a['bif_thumb']}&width=500&height=280); display: none;"></div>

View file

@ -14,6 +14,8 @@ section_id Returns the library id of the library.
section_name Returns the name of the library. section_name Returns the name of the library.
section_type Returns the type of the library. section_type Returns the type of the library.
library_thumb Returns the thumbnail for the library. library_thumb Returns the thumbnail for the library.
custom_thumb Returns the custom thumbnail for the library.
library_art Returns the artwork for the library.
count Returns the item count for the library. count Returns the item count for the library.
parent_count Returns the parent item count for the library. parent_count Returns the parent item count for the library.
child_count Returns the child item count for the library. child_count Returns the child item count for the library.
@ -40,11 +42,7 @@ DOCUMENTATION :: END
<label for="profile_url">Library Picture URL</label> <label for="profile_url">Library Picture URL</label>
<div class="row"> <div class="row">
<div class="col-md-8"> <div class="col-md-8">
% if data['custom_thumb']:
<input type="text" class="form-control" id="custom_thumb_url" name="custom_thumb_url" value="${data['custom_thumb']}">
% else:
<input type="text" class="form-control" id="custom_thumb_url" name="custom_thumb_url" value="${data['library_thumb']}"> <input type="text" class="form-control" id="custom_thumb_url" name="custom_thumb_url" value="${data['library_thumb']}">
% endif
</div> </div>
</div> </div>
<p class="help-block">Change the library's picture in PlexPy. To reset to default, leave this field empty and save.</p> <p class="help-block">Change the library's picture in PlexPy. To reset to default, leave this field empty and save.</p>
@ -61,6 +59,12 @@ DOCUMENTATION :: END
</label> </label>
<p class="help-block">Uncheck this if you do not want this keep any history on this library's activity.</p> <p class="help-block">Uncheck this if you do not want this keep any history on this library's activity.</p>
</div> </div>
<div class="checkbox">
<label>
<input type="checkbox" id="do_notify_created" name="do_notify_created" value="1" ${helpers.checked(data['do_notify_created'])}> Enable recently added notifications
</label>
<p class="help-block">Uncheck this if you do not want to receive recently added notifications for this library.</p>
</div>
% if data['section_id']: % if data['section_id']:
<div class="form-group"> <div class="form-group">
<button class="btn btn-danger" id="delete-all-history">Purge</button> <button class="btn btn-danger" id="delete-all-history">Purge</button>
@ -96,14 +100,18 @@ DOCUMENTATION :: END
</div> </div>
</div> </div>
<script> <script>
// Set new friendly name // Save library options
$("#save_library").click(function () { $("#save_library").on('click', function () {
var custom_thumb = $("#custom_thumb_url").val(); var custom_thumb = $("#custom_thumb_url").val();
var do_notify = 0; var do_notify = 0;
var do_notify_created = 0;
var keep_history = 0; var keep_history = 0;
if ($("#do_notify").is(":checked")) { if ($("#do_notify").is(":checked")) {
do_notify = 1; do_notify = 1;
} }
if ($("#do_notify_created").is(":checked")) {
do_notify_created = 1;
}
if ($("#keep_history").is(":checked")) { if ($("#keep_history").is(":checked")) {
keep_history = 1; keep_history = 1;
} }
@ -112,9 +120,10 @@ DOCUMENTATION :: END
url: 'edit_library', url: 'edit_library',
data: { data: {
section_id: '${data["section_id"]}', section_id: '${data["section_id"]}',
custom_thumb: custom_thumb,
do_notify: do_notify, do_notify: do_notify,
keep_history: keep_history, do_notify_created: do_notify_created,
custom_thumb: custom_thumb keep_history: keep_history
}, },
cache: false, cache: false,
async: true, async: true,
@ -167,5 +176,4 @@ DOCUMENTATION :: END
}); });
}); });
</script> </script>
% endif % endif

View file

@ -10,21 +10,30 @@ Variable names: data [list]
data :: Usable parameters data :: Usable parameters
== Global keys == == Global keys ==
user Return the real Plex username user_id Returns the user id of the user.
user_id Return the Plex user_id username Returns the user's username.
friendly_name Returns the friendly edited Plex username friendly_name Returns the friendly name of the user.
do_notify Returns bool value for whether the user should trigger notifications email Returns the user's email address.
keep_history Returns bool value for whether the user's activity should be logged user_thumb Returns the thumbnail for the user.
is_home_user Returns bool value for whether the user is part of a Plex Home.
is_allow_sync Returns bool value for whether the user has sync rights.
is_restricted Returns bool value for whether the user account is restricted.
do_notify Returns bool value for whether to send notifications for the user.
keep_history Returns bool value for whether to keep history for the user.
DOCUMENTATION :: END DOCUMENTATION :: END
</%doc> </%doc>
% if data is not None: <%!
from plexpy import helpers
%>
% if data != None:
<div class="modal-dialog" role="document"> <div class="modal-dialog" role="document">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
<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">Edit user <strong>${data['user']}</strong></h4> <h4 class="modal-title">Edit user <strong>${data['username']}</strong></h4>
</div> </div>
<div class="modal-body" id="modal-text"> <div class="modal-body" id="modal-text">
<fieldset> <fieldset>
@ -41,20 +50,20 @@ DOCUMENTATION :: END
<label for="profile_url">Profile Picture URL</label> <label for="profile_url">Profile Picture URL</label>
<div class="row"> <div class="row">
<div class="col-md-8"> <div class="col-md-8">
<input type="text" class="form-control" id="profile_url" name="profile_url" value="${data['thumb']}"> <input type="text" class="form-control" id="custom_avatar_url" name="custom_avatar_url" value="${data['user_thumb']}">
</div> </div>
</div> </div>
<p class="help-block">Change the users profile picture in PlexPy. To reset to default, leave this field empty and save then perform a user refresh.</p> <p class="help-block">Change the users profile picture in PlexPy. To reset to default, leave this field empty and save.</p>
</div> </div>
<div class="checkbox"> <div class="checkbox">
<label> <label>
<input type="checkbox" id="do_notify" name="do_notify" value="1" ${data['do_notify']}> Enable notifications <input type="checkbox" id="do_notify" name="do_notify" value="1" ${helpers.checked(data['do_notify'])}> Enable notifications
</label> </label>
<p class="help-block">Uncheck this if you do not want to receive notifications for this user's activity.</p> <p class="help-block">Uncheck this if you do not want to receive notifications for this user's activity.</p>
</div> </div>
<div class="checkbox"> <div class="checkbox">
<label> <label>
<input type="checkbox" id="keep_history" name="keep_history" value="1" ${data['keep_history']}> Keep history <input type="checkbox" id="keep_history" name="keep_history" value="1" ${helpers.checked(data['keep_history'])}> Keep history
</label> </label>
<p class="help-block">Uncheck this if you do not want this keep any history on this user's activity.</p> <p class="help-block">Uncheck this if you do not want this keep any history on this user's activity.</p>
</div> </div>
@ -69,7 +78,7 @@ DOCUMENTATION :: END
<div class="modal-footer"> <div class="modal-footer">
<div> <div>
<span id="edit-user-status-message"></span> <span id="edit-user-status-message"></span>
<input type="button" id="save_user_name" class="btn btn-bright" value="Save"> <input type="button" id="save_user" class="btn btn-bright" value="Save">
</div> </div>
</div> </div>
</div> </div>
@ -93,10 +102,10 @@ DOCUMENTATION :: END
</div> </div>
</div> </div>
<script> <script>
// Set new friendly name // Set user options
$("#save_user_name").click(function() { $("#save_user").on('click', function () {
var friendly_name = $("#friendly_name").val(); var friendly_name = $("#friendly_name").val();
var thumb = $("#profile_url").val(); var custom_thumb = $("#custom_avatar_url").val();
var do_notify = 0; var do_notify = 0;
var keep_history = 0; var keep_history = 0;
if ($("#do_notify").is(":checked")) { if ($("#do_notify").is(":checked")) {
@ -106,35 +115,21 @@ DOCUMENTATION :: END
keep_history = 1; keep_history = 1;
} }
% if data['user_id']:
$.ajax({ $.ajax({
url: 'edit_user', url: 'edit_user',
data: {user_id: '${data['user_id']}', friendly_name: friendly_name, do_notify: do_notify, keep_history: keep_history, thumb: thumb}, data: {
user_id: '${data["user_id"]}',
friendly_name: friendly_name,
custom_thumb: custom_thumb,
do_notify: do_notify,
keep_history: keep_history
},
cache: false, cache: false,
async: true, async: true,
success: function(data) { success: function(data) {
$("#edit-user-status-message").html(data); location.reload();
if ($.trim(friendly_name) !== '') {
$('.set-username').html(document.createTextNode(friendly_name));
}
$("#user-profile-thumb").attr('src', thumb);
} }
}); });
% else:
$.ajax({
url: 'edit_user',
data: {user: '${data['user']}', friendly_name: friendly_name, do_notify: do_notify, keep_history: keep_history, thumb: thumb},
cache: false,
async: true,
success: function(data) {
$("#edit-user-status-message").html(data);
if ($.trim(friendly_name) !== '') {
$(".set-username").html(friendly_name);
}
$("#user-profile-thumb").attr('src', thumb);
}
});
% endif
}); });
$("#delete-all-history").on('click', function() { $("#delete-all-history").on('click', function() {
@ -142,7 +137,7 @@ DOCUMENTATION :: END
$('#confirm-modal').one('click', '#confirm-purge', function () { $('#confirm-modal').one('click', '#confirm-purge', function () {
$.ajax({ $.ajax({
url: 'delete_all_user_history', url: 'delete_all_user_history',
data: {user_id: '${data['user_id']}'}, data: { user_id: '${data["user_id"]}' },
cache: false, cache: false,
async: true, async: true,
success: function(data) { success: function(data) {
@ -155,7 +150,8 @@ DOCUMENTATION :: END
$(document).ready(function() { $(document).ready(function() {
// Move #confirm-modal to parent container // Move #confirm-modal to parent container
if(!($('#edit-user-modal').next().is('#confirm-modal'))) { if(!($('#edit-user-modal').next().is('#confirm-modal'))) {
$('#confirm-modal').appendTo($('#edit-user-modal').parent()); } $('#confirm-modal').appendTo($('#edit-user-modal').parent());
}
$('#edit-user-modal > #confirm-modal').remove(); $('#edit-user-modal > #confirm-modal').remove();
$('#edit-user-modal').css('z-index', '1050'); $('#edit-user-modal').css('z-index', '1050');
@ -179,5 +175,4 @@ DOCUMENTATION :: END
}); });
}); });
</script> </script>
% endif % endif

View file

@ -18,8 +18,8 @@ duration Returns the standard runtime of the media.
content_rating Returns the age rating for the media. content_rating Returns the age rating for the media.
summary Returns a brief description of the media plot. summary Returns a brief description of the media plot.
grandparent_title Returns the name of the show, or artist. grandparent_title Returns the name of the show, or artist.
parent_index Returns the index number of the season. parent_media_index Returns the index number of the season.
index Returns the index number of the episode, or track. media_index Returns the index number of the episode, or track.
parent_thumb Returns the location of the item's thumbnail. Use with pms_image_proxy. parent_thumb Returns the location of the item's thumbnail. Use with pms_image_proxy.
writers Returns an array of writers. writers Returns an array of writers.
thumb Returns the location of the item's thumbnail. Use with pms_image_proxy. thumb Returns the location of the item's thumbnail. Use with pms_image_proxy.
@ -54,29 +54,29 @@ DOCUMENTATION :: END
<div class="summary-navbar-list"> <div class="summary-navbar-list">
<ul class="list-unstyled breadcrumb"> <ul class="list-unstyled breadcrumb">
% if data['media_type'] == 'movie': % if data['media_type'] == 'movie':
<li><a href="library?section_id=${data['library_id']}">${data['library_title']}</a></li> <li><a href="library?section_id=${data['library_id']}">${data['library_name']}</a></li>
<li class="active">${data['title']}</li> <li class="active">${data['title']}</li>
% elif data['media_type'] == 'show': % elif data['media_type'] == 'show':
<li><a href="library?section_id=${data['library_id']}">${data['library_title']}</a></li> <li><a href="library?section_id=${data['library_id']}">${data['library_name']}</a></li>
<li class="active">${data['title']}</li> <li class="active">${data['title']}</li>
% elif data['media_type'] == 'season': % elif data['media_type'] == 'season':
<li class="hidden-xs hidden-sm"><a href="library?section_id=${data['library_id']}">${data['library_title']}</a></li> <li class="hidden-xs hidden-sm"><a href="library?section_id=${data['library_id']}">${data['library_name']}</a></li>
<li><a href="info?rating_key=${data['parent_rating_key']}">${data['parent_title']}</a></li> <li><a href="info?rating_key=${data['parent_rating_key']}">${data['parent_title']}</a></li>
<li class="active">Season ${data['media_index']}</li> <li class="active">Season ${data['media_index']}</li>
% elif data['media_type'] == 'episode': % elif data['media_type'] == 'episode':
<li class="hidden-xs hidden-sm"><a href="library?section_id=${data['library_id']}">${data['library_title']}</a></li> <li class="hidden-xs hidden-sm"><a href="library?section_id=${data['library_id']}">${data['library_name']}</a></li>
<li class="hidden-xs hidden-sm"><a href="info?rating_key=${data['grandparent_rating_key']}">${data['grandparent_title']}</a></li> <li class="hidden-xs hidden-sm"><a href="info?rating_key=${data['grandparent_rating_key']}">${data['grandparent_title']}</a></li>
<li><a href="info?rating_key=${data['parent_rating_key']}">Season ${data['parent_media_index']}</a></li> <li><a href="info?rating_key=${data['parent_rating_key']}">Season ${data['parent_media_index']}</a></li>
<li class="active">Episode ${data['media_index']} - ${data['title']}</li> <li class="active">Episode ${data['media_index']} - ${data['title']}</li>
% elif data['media_type'] == 'artist': % elif data['media_type'] == 'artist':
<li><a href="library?section_id=${data['library_id']}">${data['library_title']}</a></li> <li><a href="library?section_id=${data['library_id']}">${data['library_name']}</a></li>
<li class="active">${data['title']}</li> <li class="active">${data['title']}</li>
% elif data['media_type'] == 'album': % elif data['media_type'] == 'album':
<li class="hidden-xs hidden-sm"><a href="library?section_id=${data['library_id']}">${data['library_title']}</a></li> <li class="hidden-xs hidden-sm"><a href="library?section_id=${data['library_id']}">${data['library_name']}</a></li>
<li><a href="info?rating_key=${data['parent_rating_key']}">${data['parent_title']}</a></li> <li><a href="info?rating_key=${data['parent_rating_key']}">${data['parent_title']}</a></li>
<li class="active">${data['title']}</li> <li class="active">${data['title']}</li>
% elif data['media_type'] == 'track': % elif data['media_type'] == 'track':
<li class="hidden-xs hidden-sm"><a href="library?section_id=${data['library_id']}">${data['library_title']}</a></li> <li class="hidden-xs hidden-sm"><a href="library?section_id=${data['library_id']}">${data['library_name']}</a></li>
<li class="hidden-xs hidden-sm"><a href="info?rating_key=${data['grandparent_rating_key']}">${data['grandparent_title']}</a></li> <li class="hidden-xs hidden-sm"><a href="info?rating_key=${data['grandparent_rating_key']}">${data['grandparent_title']}</a></li>
<li><a href="info?rating_key=${data['parent_rating_key']}">${data['parent_title']}</a></li> <li><a href="info?rating_key=${data['parent_rating_key']}">${data['parent_title']}</a></li>
<li class="active">Track ${data['media_index']} - ${data['title']}</li> <li class="active">Track ${data['media_index']} - ${data['title']}</li>

View file

@ -1,3 +1,4 @@
var libraries_to_delete = [];
var libraries_to_purge = []; var libraries_to_purge = [];
libraries_list_table_options = { libraries_list_table_options = {
@ -23,9 +24,12 @@ libraries_list_table_options = {
"data": null, "data": null,
"createdCell": function (td, cellData, rowData, row, col) { "createdCell": function (td, cellData, rowData, row, col) {
$(td).html('<div class="edit-library-toggles">' + $(td).html('<div class="edit-library-toggles">' +
'<button class="btn btn-xs btn-warning delete-library" data-id="' + rowData['section_id'] + '" data-toggle="button"><i class="fa fa-trash-o fa-fw"></i> Delete</button>&nbsp' +
'<button class="btn btn-xs btn-warning purge-library" data-id="' + rowData['section_id'] + '" data-toggle="button"><i class="fa fa-eraser fa-fw"></i> Purge</button>&nbsp&nbsp&nbsp' + '<button class="btn btn-xs btn-warning purge-library" data-id="' + rowData['section_id'] + '" data-toggle="button"><i class="fa fa-eraser fa-fw"></i> Purge</button>&nbsp&nbsp&nbsp' +
'<input type="checkbox" id="do_notify-' + rowData['section_id'] + '" name="do_notify" value="1" ' + rowData['do_notify'] + '><label class="edit-tooltip" for="do_notify-' + rowData['section_id'] + '" data-toggle="tooltip" title="Toggle Notifications"><i class="fa fa-bell fa-lg fa-fw"></i></label>&nbsp' + '<input type="checkbox" id="do_notify-' + rowData['section_id'] + '" name="do_notify" value="1" ' + rowData['do_notify'] + '><label class="edit-tooltip" for="do_notify-' + rowData['section_id'] + '" data-toggle="tooltip" title="Toggle Notifications"><i class="fa fa-bell fa-lg fa-fw"></i></label>&nbsp' +
'<input type="checkbox" id="keep_history-' + rowData['section_id'] + '" name="keep_history" value="1" ' + rowData['keep_history'] + '><label class="edit-tooltip" for="keep_history-' + rowData['section_id'] + '" data-toggle="tooltip" title="Toggle History"><i class="fa fa-history fa-lg fa-fw"></i></label>&nbsp'); '<input type="checkbox" id="keep_history-' + rowData['section_id'] + '" name="keep_history" value="1" ' + rowData['keep_history'] + '><label class="edit-tooltip" for="keep_history-' + rowData['section_id'] + '" data-toggle="tooltip" title="Toggle History"><i class="fa fa-history fa-lg fa-fw"></i></label>&nbsp' +
'<input type="checkbox" id="do_notify_created-' + rowData['section_id'] + '" name="do_notify_created" value="1" ' + rowData['do_notify_created'] + '><label class="edit-tooltip" for="do_notify_created-' + rowData['section_id'] + '" data-toggle="tooltip" title="Toggle Recently Added"><i class="fa fa-download fa-lg fa-fw"></i></label>&nbsp' +
'</div>');
}, },
"width": "7%", "width": "7%",
"className": "edit-control no-wrap hidden", "className": "edit-control no-wrap hidden",
@ -37,10 +41,10 @@ libraries_list_table_options = {
"data": "library_thumb", "data": "library_thumb",
"createdCell": function (td, cellData, rowData, row, col) { "createdCell": function (td, cellData, rowData, row, col) {
if (cellData === '') { if (cellData === '') {
$(td).html('<a href="library?section_id=' + rowData['section_id'] + '"><div class="libraries-poster-face" style="background-image: url(pms_image_proxy?img=' + rowData['library_thumb'] + '&width=80&height=80&fallback=poster);"></div></a>'); $(td).html('<a href="library?section_id=' + rowData['section_id'] + '"><div class="libraries-poster-face" style="background-image: url(interfaces/default/images/cover.png);"></div></a>');
} else { } else {
if (rowData['custom_thumb']) { if (rowData['library_thumb'].substring(0, 4) == "http") {
$(td).html('<a href="library?section_id=' + rowData['section_id'] + '"><div class="libraries-poster-face" style="background-image: url(' + rowData['custom_thumb'] + ');"></div></a>'); $(td).html('<a href="library?section_id=' + rowData['section_id'] + '"><div class="libraries-poster-face" style="background-image: url(' + rowData['library_thumb'] + ');"></div></a>');
} else { } else {
$(td).html('<a href="library?section_id=' + rowData['section_id'] + '"><div class="libraries-poster-face" style="background-image: url(pms_image_proxy?img=' + rowData['library_thumb'] + '&width=80&height=80&fallback=poster);"></div></a>'); $(td).html('<a href="library?section_id=' + rowData['section_id'] + '"><div class="libraries-poster-face" style="background-image: url(pms_image_proxy?img=' + rowData['library_thumb'] + '&width=80&height=80&fallback=poster);"></div></a>');
} }
@ -56,7 +60,9 @@ libraries_list_table_options = {
"data": "section_name", "data": "section_name",
"createdCell": function (td, cellData, rowData, row, col) { "createdCell": function (td, cellData, rowData, row, col) {
if (cellData !== '') { if (cellData !== '') {
$(td).html('<div data-id="' + rowData['section_id'] + '"><a href="library?section_id=' + rowData['section_id'] + '">' + cellData + '</a></div>'); $(td).html('<div data-id="' + rowData['section_id'] + '">' +
'<a href="library?section_id=' + rowData['section_id'] + '">' + cellData + '</a>' +
'</div>');
} else { } else {
$(td).html(cellData); $(td).html(cellData);
} }
@ -198,8 +204,11 @@ libraries_list_table_options = {
showMsg(msg, false, false, 0) showMsg(msg, false, false, 0)
}, },
"rowCallback": function (row, rowData) { "rowCallback": function (row, rowData) {
if ($.inArray(rowData['section_id'], libraries_to_delete) !== -1) {
$(row).find('button.delete-library[data-id="' + rowData['section_id'] + '"]').toggleClass('btn-warning').toggleClass('btn-danger');
}
if ($.inArray(rowData['section_id'], libraries_to_purge) !== -1) { if ($.inArray(rowData['section_id'], libraries_to_purge) !== -1) {
$(row).find('button[data-id="' + rowData['section_id'] + '"]').toggleClass('btn-warning').toggleClass('btn-danger'); $(row).find('button.purge-library[data-id="' + rowData['section_id'] + '"]').toggleClass('btn-warning').toggleClass('btn-danger');
} }
} }
} }
@ -210,10 +219,14 @@ $('#libraries_list_table').on('change', 'td.edit-control > .edit-library-toggles
var rowData = row.data(); var rowData = row.data();
var do_notify = 0; var do_notify = 0;
var do_notify_created = 0;
var keep_history = 0; var keep_history = 0;
if ($('#do_notify-' + rowData['section_id']).is(':checked')) { if ($('#do_notify-' + rowData['section_id']).is(':checked')) {
do_notify = 1; do_notify = 1;
} }
if ($('#do_notify_created-' + rowData['section_id']).is(':checked')) {
do_notify_created = 1;
}
if ($('#keep_history-' + rowData['section_id']).is(':checked')) { if ($('#keep_history-' + rowData['section_id']).is(':checked')) {
keep_history = 1; keep_history = 1;
} }
@ -228,6 +241,7 @@ $('#libraries_list_table').on('change', 'td.edit-control > .edit-library-toggles
data: { data: {
section_id: rowData['section_id'], section_id: rowData['section_id'],
do_notify: do_notify, do_notify: do_notify,
do_notify_created: do_notify_created,
keep_history: keep_history, keep_history: keep_history,
custom_thumb: custom_thumb custom_thumb: custom_thumb
}, },
@ -240,17 +254,44 @@ $('#libraries_list_table').on('change', 'td.edit-control > .edit-library-toggles
}); });
}); });
$('#libraries_list_table').on('click', 'td.edit-control > .edit-library-toggles > button.delete-library', function () {
var tr = $(this).parents('tr');
var row = libraries_list_table.row(tr);
var rowData = row.data();
var index_delete = $.inArray(rowData['section_id'], libraries_to_delete);
var index_purge = $.inArray(rowData['section_id'], libraries_to_purge);
if (index_delete === -1) {
libraries_to_delete.push(rowData['section_id']);
if (index_purge === -1) {
tr.find('button.purge-library').click();
}
} else {
libraries_to_delete.splice(index_delete, 1);
if (index_purge != -1) {
tr.find('button.purge-library').click();
}
}
$(this).toggleClass('btn-warning').toggleClass('btn-danger');
});
$('#libraries_list_table').on('click', 'td.edit-control > .edit-library-toggles > button.purge-library', function () { $('#libraries_list_table').on('click', 'td.edit-control > .edit-library-toggles > button.purge-library', function () {
var tr = $(this).parents('tr'); var tr = $(this).parents('tr');
var row = libraries_list_table.row(tr); var row = libraries_list_table.row(tr);
var rowData = row.data(); var rowData = row.data();
var index_delete = $.inArray(rowData['section_id'], libraries_to_delete);
var index_purge = $.inArray(rowData['section_id'], libraries_to_purge); var index_purge = $.inArray(rowData['section_id'], libraries_to_purge);
if (index_purge === -1) { if (index_purge === -1) {
libraries_to_purge.push(rowData['section_id']); libraries_to_purge.push(rowData['section_id']);
} else { } else {
libraries_to_purge.splice(index_purge, 1); libraries_to_purge.splice(index_purge, 1);
if (index_delete != -1) {
tr.find('button.delete-library').click();
}
} }
$(this).toggleClass('btn-warning').toggleClass('btn-danger'); $(this).toggleClass('btn-warning').toggleClass('btn-danger');
}); });

View file

@ -23,12 +23,12 @@ users_list_table_options = {
"targets": [0], "targets": [0],
"data": null, "data": null,
"createdCell": function (td, cellData, rowData, row, col) { "createdCell": function (td, cellData, rowData, row, col) {
$(td).html('<div class="edit-user-toggles"><button class="btn btn-xs btn-warning delete-user" data-id="' + rowData['user_id'] + '" data-toggle="button"><i class="fa fa-trash-o fa-fw"></i> Delete</button>&nbsp' + $(td).html('<div class="edit-user-toggles">' +
'<button class="btn btn-xs btn-warning delete-user" data-id="' + rowData['user_id'] + '" data-toggle="button"><i class="fa fa-trash-o fa-fw"></i> Delete</button>&nbsp' +
'<button class="btn btn-xs btn-warning purge-user" data-id="' + rowData['user_id'] + '" data-toggle="button"><i class="fa fa-eraser fa-fw"></i> Purge</button>&nbsp&nbsp&nbsp' + '<button class="btn btn-xs btn-warning purge-user" data-id="' + rowData['user_id'] + '" data-toggle="button"><i class="fa fa-eraser fa-fw"></i> Purge</button>&nbsp&nbsp&nbsp' +
'<input type="checkbox" id="do_notify-' + rowData['user_id'] + '" name="do_notify" value="1" ' + rowData['do_notify'] + '><label class="edit-tooltip" for="do_notify-' + rowData['user_id'] + '" data-toggle="tooltip" title="Toggle Notifications"><i class="fa fa-bell fa-lg fa-fw"></i></label>&nbsp' + '<input type="checkbox" id="do_notify-' + rowData['user_id'] + '" name="do_notify" value="1" ' + rowData['do_notify'] + '><label class="edit-tooltip" for="do_notify-' + rowData['user_id'] + '" data-toggle="tooltip" title="Toggle Notifications"><i class="fa fa-bell fa-lg fa-fw"></i></label>&nbsp' +
'<input type="checkbox" id="keep_history-' + rowData['user_id'] + '" name="keep_history" value="1" ' + rowData['keep_history'] + '><label class="edit-tooltip" for="keep_history-' + rowData['user_id'] + '" data-toggle="tooltip" title="Toggle History"><i class="fa fa-history fa-lg fa-fw"></i></label>&nbsp'); '<input type="checkbox" id="keep_history-' + rowData['user_id'] + '" name="keep_history" value="1" ' + rowData['keep_history'] + '><label class="edit-tooltip" for="keep_history-' + rowData['user_id'] + '" data-toggle="tooltip" title="Toggle History"><i class="fa fa-history fa-lg fa-fw"></i></label>&nbsp' +
// Show/hide user currently doesn't work '</div>');
//'<input type="checkbox" id="show_hide-' + rowData['user_id'] + '" name="show_hide" value="1" checked><label class="edit-tooltip" for="show_hide-' + rowData['user_id'] + '" data-toggle="tooltip" title="Show/Hide User"><i class="fa fa-eye fa-lg fa-fw"></i></label>');
}, },
"width": "7%", "width": "7%",
"className": "edit-control no-wrap hidden", "className": "edit-control no-wrap hidden",
@ -42,7 +42,7 @@ users_list_table_options = {
if (cellData === '') { if (cellData === '') {
$(td).html('<a href="user?user_id=' + rowData['user_id'] + '"><div class="users-poster-face" style="background-image: url(interfaces/default/images/gravatar-default-80x80.png);"></div></a>'); $(td).html('<a href="user?user_id=' + rowData['user_id'] + '"><div class="users-poster-face" style="background-image: url(interfaces/default/images/gravatar-default-80x80.png);"></div></a>');
} else { } else {
$(td).html('<a href="user?user_id=' + rowData['user_id'] + '"><div class="users-poster-face" style="background-image: url(' + cellData + ');"></div></a>'); $(td).html('<a href="user?user_id=' + rowData['user_id'] + '"><div class="users-poster-face" style="background-image: url(' + rowData['user_thumb'] + ');"></div></a>');
} }
}, },
"orderable": false, "orderable": false,
@ -55,13 +55,10 @@ users_list_table_options = {
"data": "friendly_name", "data": "friendly_name",
"createdCell": function (td, cellData, rowData, row, col) { "createdCell": function (td, cellData, rowData, row, col) {
if (cellData !== '') { if (cellData !== '') {
if (rowData['user_id'] > 0) { $(td).html('<div class="edit-user-name" data-id="' + rowData['user_id'] + '">' +
$(td).html('<div class="edit-user-name" data-id="' + rowData['user_id'] + '"><a href="user?user_id=' + rowData['user_id'] + '">' + cellData + '</a>' + '<a href="user?user_id=' + rowData['user_id'] + '">' + cellData + '</a>' +
'<input type="text" class="hidden" value="' + cellData + '"></div>'); '<input type="text" class="hidden" value="' + cellData + '">' +
} else { '</div>');
$(td).html('<div class="edit-user-name" data-id="' + rowData['user_id'] + '"><a href="user?user=' + rowData['user'] + '">' + cellData + '</a>' +
'<input type="text" class="hidden" value="' + cellData + '"></div>');
}
} else { } else {
$(td).html(cellData); $(td).html(cellData);
} }
@ -206,8 +203,11 @@ users_list_table_options = {
showMsg(msg, false, false, 0) showMsg(msg, false, false, 0)
}, },
"rowCallback": function (row, rowData) { "rowCallback": function (row, rowData) {
if ($.inArray(rowData['user_id'], users_to_delete) !== -1) {
$(row).find('button.delete-user[data-id="' + rowData['user_id'] + '"]').toggleClass('btn-warning').toggleClass('btn-danger');
}
if ($.inArray(rowData['user_id'], users_to_purge) !== -1) { if ($.inArray(rowData['user_id'], users_to_purge) !== -1) {
$(row).find('button[data-id="' + rowData['user_id'] + '"]').toggleClass('btn-warning').toggleClass('btn-danger'); $(row).find('button.purge-user[data-id="' + rowData['user_id'] + '"]').toggleClass('btn-warning').toggleClass('btn-danger');
} }
} }
} }

View file

@ -43,15 +43,16 @@
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
<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">Confirm Purge</h4> <h4 class="modal-title" id="myModalLabel">Confirm Delete/Purge</h4>
</div> </div>
<div class="modal-body" style="text-align: center;"> <div class="modal-body" style="text-align: center;">
<ul id="libraries-to-delete" class="list-unstyled"></ul>
<ul id="libraries-to-purge" class="list-unstyled"></ul> <ul id="libraries-to-purge" class="list-unstyled"></ul>
<p>This is permanent and cannot be undone!</p> <p>This is permanent and cannot be undone!</p>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="btn btn-dark" data-dismiss="modal">Cancel</button> <button type="button" class="btn btn-dark" data-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-danger btn-ok" data-dismiss="modal" id="confirm-purge">Confirm</button> <button type="button" class="btn btn-danger btn-ok" data-dismiss="modal" id="confirm-delete">Confirm</button>
</div> </div>
</div> </div>
</div> </div>
@ -83,7 +84,8 @@
$('#row-edit-mode').on('click', function () { $('#row-edit-mode').on('click', function () {
$('#row-edit-mode-alert').fadeIn(200); $('#row-edit-mode-alert').fadeIn(200);
$('#libraries_to_purge').html(''); $('#libraries-to-delete').html('');
$('#libraries-to-purge').html('');
if ($(this).hasClass('active')) { if ($(this).hasClass('active')) {
if (libraries_to_purge.length > 0) { if (libraries_to_purge.length > 0) {
@ -91,6 +93,17 @@
$(this).find('button.btn-danger').toggleClass('btn-warning').toggleClass('btn-danger'); $(this).find('button.btn-danger').toggleClass('btn-warning').toggleClass('btn-danger');
}); });
libraries_to_purge = $.grep(libraries_to_purge, function (value) {
return $.inArray(value, libraries_to_delete) < 0;
});
if (libraries_to_delete.length > 0) {
$('#libraries-to-delete').prepend('<p>Are you REALLY sure you want to delete the following libraries:</p>')
for (var i = 0; i < libraries_to_delete.length; i++) {
$('#libraries-to-delete').append('<li>' + $('div[data-id=' + libraries_to_delete[i] + ']').text() + '</li>');
}
}
if (libraries_to_purge.length > 0) { if (libraries_to_purge.length > 0) {
$('#libraries-to-purge').prepend('<p>Are you REALLY sure you want to purge all history for the following libraries:</p>') $('#libraries-to-purge').prepend('<p>Are you REALLY sure you want to purge all history for the following libraries:</p>')
for (var i = 0; i < libraries_to_purge.length; i++) { for (var i = 0; i < libraries_to_purge.length; i++) {
@ -99,7 +112,19 @@
} }
$('#confirm-modal').modal(); $('#confirm-modal').modal();
$('#confirm-modal').one('click', '#confirm-purge', function () { $('#confirm-modal').one('click', '#confirm-delete', function () {
for (var i = 0; i < libraries_to_delete.length; i++) {
$.ajax({
url: 'delete_library',
data: { section_id: libraries_to_delete[i] },
cache: false,
async: true,
success: function (data) {
var msg = "Library deleted";
showMsg(msg, false, true, 2000);
}
});
}
for (var i = 0; i < libraries_to_purge.length; i++) { for (var i = 0; i < libraries_to_purge.length; i++) {
$.ajax({ $.ajax({
url: 'delete_all_library_history', url: 'delete_all_library_history',
@ -122,6 +147,7 @@
}); });
} else { } else {
libraries_to_delete = [];
libraries_to_purge = []; libraries_to_purge = [];
$('.edit-control').each(function () { $('.edit-control').each(function () {
$(this).find('button.btn-danger').toggleClass('btn-warning').toggleClass('btn-danger'); $(this).find('button.btn-danger').toggleClass('btn-warning').toggleClass('btn-danger');
@ -137,13 +163,13 @@
cache: false, cache: false,
async: true, async: true,
success: function (data) { success: function (data) {
showMsg('<i class="fa fa-refresh"></i>&nbspLibraries list refresh started...', false, true, 2000, false) showMsg('<i class="fa fa-refresh"></i>&nbspLibraries list refresh started...', false, true, 2000, false);
}, },
complete: function (data) { complete: function (data) {
showMsg('<i class="fa fa-check"></i>&nbspLibraries list refreshed.', false, true, 2000, false) showMsg('<i class="fa fa-check"></i>&nbspLibraries list refreshed.', false, true, 2000, false);
}, },
error: function (jqXHR, textStatus, errorThrown) { error: function (jqXHR, textStatus, errorThrown) {
showMsg('<i class="fa fa-exclamation-circle"></i>&nbspUnable to refresh libraries list.',false,true,2000,true) showMsg('<i class="fa fa-exclamation-circle"></i>&nbspUnable to refresh libraries list.', false, true, 2000, true);
} }
}); });
}); });

View file

@ -13,6 +13,8 @@ section_id Returns the library id of the library.
section_name Returns the name of the library. section_name Returns the name of the library.
section_type Returns the type of the library. section_type Returns the type of the library.
library_thumb Returns the thumbnail for the library. library_thumb Returns the thumbnail for the library.
custom_thumb Returns the custom thumbnail for the library.
library_art Returns the artwork for the library.
count Returns the item count for the library. count Returns the item count for the library.
parent_count Returns the parent item count for the library. parent_count Returns the parent item count for the library.
child_count Returns the child item count for the library. child_count Returns the child item count for the library.
@ -31,8 +33,8 @@ DOCUMENTATION :: END
<link rel="stylesheet" href="interfaces/default/css/plexpy-dataTables.css"> <link rel="stylesheet" href="interfaces/default/css/plexpy-dataTables.css">
</%def> </%def>
% if data != None:
<%def name="body()"> <%def name="body()">
% if data:
<div class="container-fluid"> <div class="container-fluid">
<div class="row"> <div class="row">
<div class="art-face" style="background-image:url(pms_image_proxy?img=${data['library_art']}&width=1920&height=1080)"></div> <div class="art-face" style="background-image:url(pms_image_proxy?img=${data['library_art']}&width=1920&height=1080)"></div>
@ -50,12 +52,11 @@ DOCUMENTATION :: END
<div class="col-md-12"> <div class="col-md-12">
<div class="table-card-back"> <div class="table-card-back">
<div class="user-info-wrapper"> <div class="user-info-wrapper">
% if data['custom_thumb']: % if data['library_thumb'][:4] == 'http':
<div class="library-info-poster-face" id="user-gravatar" style="background-image: url(${data['custom_thumb']});"> <div class="library-info-poster-face" style="background-image: url(${data['library_thumb']});"></div>
% else: % else:
<div class="library-info-poster-face" id="user-gravatar" style="background-image: url(pms_image_proxy?img=${data['library_thumb']}&width=80&height=80&fallback=poster);"> <div class="library-info-poster-face" style="background-image: url(pms_image_proxy?img=${data['library_thumb']}&width=80&height=80&fallback=cover);"></div>
% endif % endif
</div>
<div class="user-info-username"> <div class="user-info-username">
<span class="set-username">${data['section_name']}</span> <span class="set-username">${data['section_name']}</span>
<span id="edit-library-tooltip" data-target="tooltip" title="Edit library details"> <span id="edit-library-tooltip" data-target="tooltip" title="Edit library details">
@ -201,6 +202,27 @@ DOCUMENTATION :: END
</div> </div>
</div> </div>
<footer></footer> <footer></footer>
% else:
<div class="container-fluid">
<div class="row">
<div class="summary-container">
<div class="summary-navbar">
<div class="col-md-12">
<div class="summary-navbar-list">
</div>
</div>
</div>
<div class="summary-content-wrapper">
<div class='col-md-12'>
<div style="text-align: center; margin-top: 20px;">
<i class="fa fa-exclamation-triangle"></i> Error retrieving library information. Please see the logs for more details.
</div>
</div>
</div>
</div>
</div>
</div>
% endif
</%def> </%def>
<%def name="javascriptIncludes()"> <%def name="javascriptIncludes()">
@ -208,12 +230,13 @@ DOCUMENTATION :: END
<script src="interfaces/default/js/dataTables.colVis.js"></script> <script src="interfaces/default/js/dataTables.colVis.js"></script>
<script src="interfaces/default/js/dataTables.bootstrap.min.js"></script> <script src="interfaces/default/js/dataTables.bootstrap.min.js"></script>
<script src="interfaces/default/js/dataTables.bootstrap.pagination.js"></script> <script src="interfaces/default/js/dataTables.bootstrap.pagination.js"></script>
% if data:
<script src="interfaces/default/js/moment-with-locale.js"></script> <script src="interfaces/default/js/moment-with-locale.js"></script>
<script src="interfaces/default/js/tables/history_table.js"></script> <script src="interfaces/default/js/tables/history_table.js"></script>
<script> <script>
$(document).ready(function () { $(document).ready(function () {
% if data['section_id']: % if str(data['section_id']).isdigit():
var section_id = ${data['section_id']}; var section_id = ${data['section_id']};
% else: % else:
var section_id = null; var section_id = null;
@ -348,18 +371,7 @@ DOCUMENTATION :: END
recentlyWatched(); recentlyWatched();
}); });
}); });
</script>
<script>
$('div.art-face').animate({ opacity: 0.2 }, { duration: 1000 }); $('div.art-face').animate({ opacity: 0.2 }, { duration: 1000 });
</script> </script>
</%def>
% else:
<div class="clear"></div>
<div class="container-fluid">
<div class="row-fluid">
<div class="span10 offset1">
<h3>Error retrieving library information. Please see the logs for more details.</h3>
</div>
</div>
</div>
% endif % endif
</%def>

View file

@ -18,7 +18,7 @@ total_plays Returns the play count for the user.
DOCUMENTATION :: END DOCUMENTATION :: END
</%doc> </%doc>
% if data != None: % if data:
% for a in data: % for a in data:
<ul class="list-unstyled"> <ul class="list-unstyled">
<div class="user-player-instance"> <div class="user-player-instance">
@ -38,6 +38,6 @@ DOCUMENTATION :: END
</ul> </ul>
% endfor % endfor
% else: % else:
<div class="text-muted">Unable to retrieve data from database. Please check your <a href="settings">settings</a>. <div class="text-muted">Unable to retrieve data from database.
</div><br> </div><br>
% endif % endif

View file

@ -800,7 +800,7 @@ available_notification_agents = sorted(notifiers.available_notification_agents()
% for agent in available_notification_agents: % for agent in available_notification_agents:
<li> <li>
<span> <span>
% if agent['on_play'] or agent['on_stop'] or agent['on_pause'] or agent['on_resume'] or agent['on_buffer'] or agent['on_watched'] or agent['on_created'] or agent['on_extdown'] or agent['on_intdown']: % if any(k[:2] == 'on' and v == 1 for k, v in agent.iteritems()):
<a href="javascript:void(0)" data-target="#notification-triggers-modal" data-id="${agent['id']}" class="toggle-notification-triggers-modal toggle-left active" data-toggle="modal"><i class="fa fa-lg fa-bell"></i></a> <a href="javascript:void(0)" data-target="#notification-triggers-modal" data-id="${agent['id']}" class="toggle-notification-triggers-modal toggle-left active" data-toggle="modal"><i class="fa fa-lg fa-bell"></i></a>
% else: % else:
<a href="javascript:void(0)" data-target="#notification-triggers-modal" data-id="${agent['id']}" class="toggle-notification-triggers-modal toggle-left" data-toggle="modal"><i class="fa fa-lg fa-bell"></i></a> <a href="javascript:void(0)" data-target="#notification-triggers-modal" data-id="${agent['id']}" class="toggle-notification-triggers-modal toggle-left" data-toggle="modal"><i class="fa fa-lg fa-bell"></i></a>
@ -1167,6 +1167,10 @@ available_notification_agents = sorted(notifiers.available_notification_agents()
<td><strong>{title}</strong></td> <td><strong>{title}</strong></td>
<td>The full title of the item being played.</td> <td>The full title of the item being played.</td>
</tr> </tr>
<tr>
<td><strong>{library_name}</strong></td>
<td>The library title of the item being played.</td>
</tr>
<tr> <tr>
<td><strong>{show_name}</strong></td> <td><strong>{show_name}</strong></td>
<td>The title of the TV series being played.</td> <td>The title of the TV series being played.</td>

View file

@ -13,10 +13,12 @@ user_id Returns the user id of the user.
username Returns the user's username. username Returns the user's username.
friendly_name Returns the friendly name of the user. friendly_name Returns the friendly name of the user.
email Returns the user's email address. email Returns the user's email address.
thumb Returns the thumbnail for the user. user_thumb Returns the thumbnail for the user.
is_home_user Returns bool value for whether the user is part of a Plex Home. is_home_user Returns bool value for whether the user is part of a Plex Home.
is_allow_sync Returns bool value for whether the user has sync rights. is_allow_sync Returns bool value for whether the user has sync rights.
is_restricted Returns bool value for whether the user account is restricted. is_restricted Returns bool value for whether the user account is restricted.
do_notify Returns bool value for whether to send notifications for the user.
keep_history Returns bool value for whether to keep history for the user.
DOCUMENTATION :: END DOCUMENTATION :: END
@ -33,17 +35,28 @@ from plexpy import helpers
<link rel="stylesheet" href="interfaces/default/css/plexpy-dataTables.css"> <link rel="stylesheet" href="interfaces/default/css/plexpy-dataTables.css">
</%def> </%def>
% if user != None:
<%def name="body()"> <%def name="body()">
% if data:
<div class="container-fluid"> <div class="container-fluid">
<div class="row"> <div class="row">
<div class="summary-container">
<div class="summary-navbar">
<div class="col-md-12">
<div class="summary-navbar-list">
<ul class="list-unstyled breadcrumb"></ul>
</div>
</div>
</div>
<div class="summary-content-wrapper">
<div class="col-md-12"> <div class="col-md-12">
<div class="table-card-back"> <div class="table-card-back">
<div class="user-info-wrapper"> <div class="user-info-wrapper">
<div class="user-info-poster-face" id="user-gravatar" style="background-image: url(${data['thumb']});"> <div class="user-info-poster-face" style="background-image: url(${data['user_thumb']});"></div>
</div>
<div class="user-info-username"> <div class="user-info-username">
<span class="set-username">${data['friendly_name']}</span> <span id="edit-user-tooltip" data-target="tooltip" title="Edit user details"><a href="#" data-toggle="modal" data-target="#edit-user-modal" id="toggle-edit-user-modal"><i class="fa fa-pencil"></i></a></span> <span class="set-username">${data['friendly_name']}</span>
<span id="edit-user-tooltip" data-target="tooltip" title="Edit user details">
<a href="#" data-toggle="modal" data-target="#edit-user-modal" id="toggle-edit-user-modal"><i class="fa fa-pencil"></i></a>
</span>
</div> </div>
<div class="user-info-nav"> <div class="user-info-nav">
<ul class="user-info-nav"> <ul class="user-info-nav">
@ -56,12 +69,10 @@ from plexpy import helpers
</div> </div>
</div> </div>
</div> </div>
</div>
<div id="edit-user-modal" class="modal fade" tabindex="-1" role="dialog" <div id="edit-user-modal" class="modal fade" tabindex="-1" role="dialog"
aria-labelledby="edit-user-modal"> aria-labelledby="edit-user-modal">
</div> </div>
</div> <div class="tab-content">
<div class="tab-content">
<div class="tab-pane active" id="profile"> <div class="tab-pane active" id="profile">
<div class="container-fluid"> <div class="container-fluid">
<div class="row"> <div class="row">
@ -121,9 +132,11 @@ from plexpy import helpers
<div class="col-md-12"> <div class="col-md-12">
<div class="table-card-header"> <div class="table-card-header">
<div class="header-bar"> <div class="header-bar">
<span><i class="fa fa-map-marker"></i> IP Addresses for <strong> <span>
<i class="fa fa-map-marker"></i> IP Addresses for <strong>
<span class="set-username">${data['friendly_name']}</span> <span class="set-username">${data['friendly_name']}</span>
</strong></span> </strong>
</span>
</div> </div>
</div> </div>
<div class="table-card-back"> <div class="table-card-back">
@ -150,9 +163,11 @@ from plexpy import helpers
<div class="col-md-12"> <div class="col-md-12">
<div class='table-card-header'> <div class='table-card-header'>
<div class="header-bar"> <div class="header-bar">
<span><i class="fa fa-history"></i> Watch History for <strong> <span>
<i class="fa fa-history"></i> Watch History for <strong>
<span class="set-username">${data['friendly_name']}</span> <span class="set-username">${data['friendly_name']}</span>
</strong></span> </strong>
</span>
</div> </div>
<div class="button-bar"> <div class="button-bar">
<div class="colvis-button-bar hidden-xs" id="button-bar-history"></div> <div class="colvis-button-bar hidden-xs" id="button-bar-history"></div>
@ -180,8 +195,7 @@ from plexpy import helpers
<th align='left' id="percent_complete"></th> <th align='left' id="percent_complete"></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody></tbody>
</tbody>
</table> </table>
</div> </div>
</div> </div>
@ -194,9 +208,11 @@ from plexpy import helpers
<div class="col-md-12"> <div class="col-md-12">
<div class='table-card-header'> <div class='table-card-header'>
<div class="header-bar"> <div class="header-bar">
<span><i class="fa fa-cloud-download"></i> Synced Items for <strong> <span>
<i class="fa fa-cloud-download"></i> Synced Items for <strong>
<span class="set-username">${data['friendly_name']}</span> <span class="set-username">${data['friendly_name']}</span>
</strong></span> </strong>
</span>
</div> </div>
<div class="colvis-button-bar hidden-xs" id="button-bar-sync"> <div class="colvis-button-bar hidden-xs" id="button-bar-sync">
</div> </div>
@ -218,8 +234,7 @@ from plexpy import helpers
<th align='left' id="sync_percent_complete">Complete</th> <th align='left' id="sync_percent_complete">Complete</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody></tbody>
</tbody>
</table> </table>
</div> </div>
</div> </div>
@ -248,8 +263,33 @@ from plexpy import helpers
</div> </div>
</div> </div>
</div> </div>
</div>
</div>
</div>
</div>
</div> </div>
<footer></footer> <footer></footer>
% else:
<div class="container-fluid">
<div class="row">
<div class="summary-container">
<div class="summary-navbar">
<div class="col-md-12">
<div class="summary-navbar-list">
</div>
</div>
</div>
<div class="summary-content-wrapper">
<div class='col-md-12'>
<div style="text-align: center; margin-top: 20px;">
<i class="fa fa-exclamation-triangle"></i> Error retrieving user information. Please see the logs for more details.
</div>
</div>
</div>
</div>
</div>
</div>
% endif
</%def> </%def>
<%def name="javascriptIncludes()"> <%def name="javascriptIncludes()">
@ -257,6 +297,7 @@ from plexpy import helpers
<script src="interfaces/default/js/dataTables.colVis.js"></script> <script src="interfaces/default/js/dataTables.colVis.js"></script>
<script src="interfaces/default/js/dataTables.bootstrap.min.js"></script> <script src="interfaces/default/js/dataTables.bootstrap.min.js"></script>
<script src="interfaces/default/js/dataTables.bootstrap.pagination.js"></script> <script src="interfaces/default/js/dataTables.bootstrap.pagination.js"></script>
% if data:
<script src="interfaces/default/js/moment-with-locale.js"></script> <script src="interfaces/default/js/moment-with-locale.js"></script>
<script src="interfaces/default/js/tables/history_table.js"></script> <script src="interfaces/default/js/tables/history_table.js"></script>
<script src="interfaces/default/js/tables/user_ips.js"></script> <script src="interfaces/default/js/tables/user_ips.js"></script>
@ -264,7 +305,7 @@ from plexpy import helpers
<script> <script>
$(document).ready(function () { $(document).ready(function () {
% if data['user_id']: % if str(data['user_id']).isdigit():
var user_id = ${data['user_id']}; var user_id = ${data['user_id']};
% else: % else:
var user_id = null; var user_id = null;
@ -303,7 +344,6 @@ from plexpy import helpers
return { return {
'json_data': JSON.stringify( d ), 'json_data': JSON.stringify( d ),
'user_id': user_id, 'user_id': user_id,
'user': username,
'media_type': media_type 'media_type': media_type
}; };
} }
@ -348,12 +388,11 @@ from plexpy import helpers
$( "#ip-tab-btn" ).one( "click", function() { $( "#ip-tab-btn" ).one( "click", function() {
// Build user IP table // Build user IP table
user_ip_table_options.ajax = { user_ip_table_options.ajax = {
"url": "get_user_ips", url: 'get_user_ips',
type: 'post', type: 'post',
data: function ( d ) { data: function ( d ) {
return { 'json_data': JSON.stringify( d ), return { 'json_data': JSON.stringify( d ),
'user_id': user_id, 'user_id': user_id
'user': username
}; };
} }
} }
@ -365,10 +404,9 @@ from plexpy import helpers
$( "#sync-tab-btn" ).one( "click", function() { $( "#sync-tab-btn" ).one( "click", function() {
// Build user sync table // Build user sync table
sync_table_options.ajax = { sync_table_options.ajax = {
"url": "get_sync", url: 'get_sync',
"data": function(d) { data: function(d) {
d.user_id = user_id; d.user_id = user_id;
d.user = username;
} }
} }
sync_table = $('#sync_table').DataTable(sync_table_options); sync_table = $('#sync_table').DataTable(sync_table_options);
@ -385,7 +423,7 @@ from plexpy import helpers
$("#edit-user-tooltip").tooltip('hide'); $("#edit-user-tooltip").tooltip('hide');
$.ajax({ $.ajax({
url: 'edit_user_dialog', url: 'edit_user_dialog',
data: { user_id: user_id, user: username }, data: { user_id: user_id },
cache: false, cache: false,
async: true, async: true,
complete: function(xhr, status) { complete: function(xhr, status) {
@ -441,17 +479,14 @@ from plexpy import helpers
containerSize = 1; containerSize = 1;
} }
% if data['user_id']:
var user_id = ${data['user_id']};
% else:
var user_id = null;
% endif
// Populate recently watched // Populate recently watched
$.ajax({ $.ajax({
url: 'get_user_recently_watched', url: 'get_user_recently_watched',
async: true, async: true,
data: { user_id: user_id, user: username, limit: containerSize }, data: {
user_id: user_id,
limit: containerSize
},
complete: function(xhr, status) { complete: function(xhr, status) {
$("#user-recently-watched").html(xhr.responseText); $("#user-recently-watched").html(xhr.responseText);
} }
@ -464,14 +499,5 @@ from plexpy import helpers
}); });
}); });
</script> </script>
</%def>
% else:
<div class="clear"></div>
<div class="container-fluid">
<div class="row-fluid">
<div class="span10 offset1">
<h3>Error retrieving user information. Please see the logs for more details.</h3>
</div>
</div>
</div>
% endif % endif
</%def>

View file

@ -18,7 +18,7 @@ total_plays Returns the play count for the player.
DOCUMENTATION :: END DOCUMENTATION :: END
</%doc> </%doc>
% if data != None: % if data:
% for a in data: % for a in data:
<ul class="list-unstyled"> <ul class="list-unstyled">
<div class="user-player-instance"> <div class="user-player-instance">
@ -39,6 +39,6 @@ DOCUMENTATION :: END
</script> </script>
% endfor % endfor
% else: % else:
<div class="text-muted">Unable to retrieve data from database. Please check your <a href="settings">settings</a>. <div class="text-muted">Unable to retrieve data from database.
</div><br> </div><br>
% endif % endif

View file

@ -28,7 +28,7 @@ year Returns the movie release year.
DOCUMENTATION :: END DOCUMENTATION :: END
</%doc> </%doc>
% if data != None: % if data:
<div class="dashboard-recent-media-row"> <div class="dashboard-recent-media-row">
<ul class="dashboard-recent-media list-unstyled"> <ul class="dashboard-recent-media list-unstyled">
% for item in data: % for item in data:
@ -84,6 +84,6 @@ DOCUMENTATION :: END
</ul> </ul>
</div> </div>
% else: % else:
<div class="text-muted">Unable to retrieve data from database. Please check your <a href="settings">settings</a>. <div class="text-muted">Unable to retrieve data from database.
</div><br> </div><br>
% endif % endif

View file

@ -16,7 +16,7 @@ total_plays Returns the play count for the watch stat period..
DOCUMENTATION :: END DOCUMENTATION :: END
</%doc> </%doc>
% if data != None: % if data:
<ul class="list-unstyled"> <ul class="list-unstyled">
% for a in data: % for a in data:
<div class='user-overview-stats-instance'> <div class='user-overview-stats-instance'>
@ -43,6 +43,6 @@ DOCUMENTATION :: END
% endfor % endfor
</ul> </ul>
% else: % else:
<div class="text-muted">Unable to retrieve data from database. Please check your <a href="settings">settings</a>. <div class="text-muted">Unable to retrieve data from database.
</div><br> </div><br>
% endif % endif

View file

@ -177,13 +177,13 @@
cache: false, cache: false,
async: true, async: true,
success: function(data) { success: function(data) {
showMsg('<i class="fa fa-check"></i>&nbspUsers list refresh started...',false,true,2000,false) showMsg('<i class="fa fa-check"></i>&nbspUsers list refresh started...', false, true, 2000, false);
}, },
complete: function (data) { complete: function (data) {
showMsg('<i class="fa fa-check"></i>&nbspUsers list refreshed.', false, true, 2000, false) showMsg('<i class="fa fa-check"></i>&nbspUsers list refreshed.', false, true, 2000, false);
}, },
error: function (jqXHR, textStatus, errorThrown) { error: function (jqXHR, textStatus, errorThrown) {
showMsg('<i class="fa fa-exclamation-circle"></i>&nbspUnable to refresh users list.',false,true,2000,true) showMsg('<i class="fa fa-exclamation-circle"></i>&nbspUnable to refresh users list.', false, true, 2000, true);
} }
}); });
}); });

View file

@ -377,7 +377,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, media_type TEXT, started INTEGER, ' 'session_key INTEGER, rating_key INTEGER, library_id INTEGER, media_type TEXT, started 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, '
@ -441,7 +441,8 @@ def dbcheck():
'CREATE TABLE IF NOT EXISTS library_sections (id INTEGER PRIMARY KEY AUTOINCREMENT, ' 'CREATE TABLE IF NOT EXISTS library_sections (id INTEGER PRIMARY KEY AUTOINCREMENT, '
'server_id TEXT, section_id INTEGER UNIQUE, section_name TEXT, section_type TEXT, ' 'server_id TEXT, section_id INTEGER UNIQUE, section_name TEXT, section_type TEXT, '
'thumb TEXT, custom_thumb_url TEXT, art TEXT, count INTEGER, parent_count INTEGER, child_count INTEGER, ' 'thumb TEXT, custom_thumb_url TEXT, art TEXT, count INTEGER, parent_count INTEGER, child_count INTEGER, '
'do_notify INTEGER DEFAULT 1, keep_history INTEGER DEFAULT 1)' 'do_notify INTEGER DEFAULT 1, do_notify_created INTEGER DEFAULT 1, keep_history INTEGER DEFAULT 1, '
'deleted_section INTEGER DEFAULT 0)'
) )
# Upgrade sessions table from earlier versions # Upgrade sessions table from earlier versions
@ -591,6 +592,15 @@ def dbcheck():
'ALTER TABLE sessions ADD COLUMN last_paused INTEGER' 'ALTER TABLE sessions ADD COLUMN last_paused INTEGER'
) )
# Upgrade sessions table from earlier versions
try:
c_db.execute('SELECT library_id from sessions')
except sqlite3.OperationalError:
logger.debug(u"Altering database. Updating database table sessions.")
c_db.execute(
'ALTER TABLE sessions ADD COLUMN library_id 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')

View file

@ -16,7 +16,7 @@
import time import time
import plexpy import plexpy
from plexpy import logger, pmsconnect, activity_processor, threading, notification_handler from plexpy import logger, pmsconnect, activity_processor, threading, notification_handler, helpers
class ActivityHandler(object): class ActivityHandler(object):
@ -165,8 +165,6 @@ class ActivityHandler(object):
# This function receives events from our websocket connection # This function receives events from our websocket connection
def process(self): def process(self):
if self.is_valid_session(): if self.is_valid_session():
from plexpy import helpers
ap = activity_processor.ActivityProcessor() ap = activity_processor.ActivityProcessor()
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())

View file

@ -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 from plexpy import logger, pmsconnect, plextv, notification_handler, database, helpers, activity_processor, libraries
import threading import threading
import plexpy import plexpy
@ -46,16 +46,7 @@ def check_active_sessions(ws_request=False):
media_container = session_list['sessions'] media_container = session_list['sessions']
# Check our temp table for what we must do with the new streams # Check our temp table for what we must do with the new streams
db_streams = monitor_db.select('SELECT started, session_key, rating_key, media_type, title, parent_title, ' db_streams = monitor_db.select('SELECT * FROM sessions')
'grandparent_title, user_id, user, friendly_name, ip_address, player, '
'platform, machine_id, parent_rating_key, grandparent_rating_key, state, '
'view_offset, duration, video_decision, audio_decision, width, height, '
'container, video_codec, audio_codec, bitrate, video_resolution, '
'video_framerate, aspect_ratio, audio_channels, transcode_protocol, '
'transcode_container, transcode_video_codec, transcode_audio_codec, '
'transcode_audio_channels, transcode_width, transcode_height, '
'paused_counter, last_paused '
'FROM sessions')
for stream in db_streams: for stream in db_streams:
if any(d['session_key'] == str(stream['session_key']) and d['rating_key'] == str(stream['rating_key']) if any(d['session_key'] == str(stream['session_key']) and d['rating_key'] == str(stream['rating_key'])
for d in media_container): for d in media_container):
@ -196,10 +187,16 @@ def check_recently_added():
pms_connect = pmsconnect.PmsConnect() pms_connect = pmsconnect.PmsConnect()
recently_added_list = pms_connect.get_recently_added_details(count='10') recently_added_list = pms_connect.get_recently_added_details(count='10')
library_data = libraries.Libraries()
if recently_added_list: if recently_added_list:
recently_added = recently_added_list['recently_added'] recently_added = recently_added_list['recently_added']
for item in recently_added: for item in recently_added:
library_details = library_data.get_details(section_id=item['library_id'])
if not library_details['do_notify_created']:
continue
metadata = [] metadata = []
if 0 < time_threshold - int(item['added_at']) <= time_interval: if 0 < time_threshold - int(item['added_at']) <= time_interval:
@ -220,8 +217,12 @@ def check_recently_added():
% str(item['rating_key'])) % str(item['rating_key']))
if metadata: if metadata:
if not plexpy.CONFIG.NOTIFY_RECENTLY_ADDED_GRANDPARENT: if not plexpy.CONFIG.NOTIFY_RECENTLY_ADDED_GRANDPARENT:
for item in metadata: for item in metadata:
library_details = library_data.get_details(section_id=item['library_id'])
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 # Fire off notifications

View file

@ -29,6 +29,7 @@ class ActivityProcessor(object):
def write_session(self, session=None, notify=True): def write_session(self, session=None, notify=True):
if session: if session:
values = {'session_key': session['session_key'], values = {'session_key': session['session_key'],
'library_id': session['library_id'],
'rating_key': session['rating_key'], 'rating_key': session['rating_key'],
'media_type': session['media_type'], 'media_type': session['media_type'],
'state': session['state'], 'state': session['state'],
@ -97,10 +98,13 @@ class ActivityProcessor(object):
self.db.upsert('sessions', ip_address, keys) self.db.upsert('sessions', ip_address, keys)
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 from plexpy import users, libraries
user_data = users.Users() user_data = users.Users()
user_details = user_data.get_user_friendly_name(user=session['user']) user_details = user_data.get_details(user_id=session['user_id'])
library_data = libraries.Libraries()
library_details = library_data.get_details(section_id=session['library_id'])
if session: if session:
logging_enabled = False logging_enabled = False
@ -155,7 +159,10 @@ class ActivityProcessor(object):
if not user_details['keep_history'] and not is_import: if not user_details['keep_history'] and not is_import:
logging_enabled = False logging_enabled = False
logger.debug(u"PlexPy ActivityProcessor :: History logging for user '%s' is disabled." % session['user']) 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:
logging_enabled = False
logger.debug(u"PlexPy ActivityProcessor :: History logging for library '%s' is disabled." % library_details['section_name'])
if logging_enabled: if logging_enabled:
# logger.debug(u"PlexPy ActivityProcessor :: Attempting to write to session_history table...") # logger.debug(u"PlexPy ActivityProcessor :: Attempting to write to session_history table...")
@ -331,15 +338,7 @@ class ActivityProcessor(object):
def get_session_by_key(self, session_key=None): def get_session_by_key(self, session_key=None):
if str(session_key).isdigit(): if str(session_key).isdigit():
result = self.db.select('SELECT started, session_key, rating_key, media_type, title, parent_title, ' result = self.db.select('SELECT * '
'grandparent_title, user_id, user, friendly_name, ip_address, player, '
'platform, machine_id, parent_rating_key, grandparent_rating_key, state, '
'view_offset, duration, video_decision, audio_decision, width, height, '
'container, video_codec, audio_codec, bitrate, video_resolution, '
'video_framerate, aspect_ratio, audio_channels, transcode_protocol, '
'transcode_container, transcode_video_codec, transcode_audio_codec, '
'transcode_audio_channels, transcode_width, transcode_height, '
'paused_counter, last_paused '
'FROM sessions WHERE session_key = ? LIMIT 1', args=[session_key]) 'FROM sessions WHERE session_key = ? LIMIT 1', args=[session_key])
for session in result: for session in result:
if session: if session:

View file

@ -323,7 +323,7 @@ class Api(object):
custom_where = [['strftime("%Y-%m-%d", datetime(date, "unixepoch", "localtime"))', start_date]] custom_where = [['strftime("%Y-%m-%d", datetime(date, "unixepoch", "localtime"))', start_date]]
data_factory = datafactory.DataFactory() data_factory = datafactory.DataFactory()
history = data_factory.get_history(kwargs=kwargs, custom_where=custom_where) history = data_factory.get_datatables_history(kwargs=kwargs, custom_where=custom_where)
self.data = history self.data = history
return self.data return self.data

View file

@ -26,7 +26,7 @@ class DataFactory(object):
def __init__(self): def __init__(self):
pass pass
def get_history(self, kwargs=None, custom_where=None, grouping=0, watched_percent=85): def get_datatables_history(self, kwargs=None, custom_where=None, grouping=0, watched_percent=85):
data_tables = datatables.DataTables() data_tables = datatables.DataTables()
group_by = ['session_history.reference_id'] if grouping else ['session_history.id'] group_by = ['session_history.reference_id'] if grouping else ['session_history.id']
@ -81,8 +81,8 @@ class DataFactory(object):
['session_history.id', 'session_history_metadata.id'], ['session_history.id', 'session_history_metadata.id'],
['session_history.id', 'session_history_media_info.id']], ['session_history.id', 'session_history_media_info.id']],
kwargs=kwargs) kwargs=kwargs)
except: except Exception as e:
logger.warn("Unable to execute database query for get_history.") logger.warn(u"PlexPy DataFactory :: Unable to execute database query for get_history: %s." % e)
return {'recordsFiltered': 0, return {'recordsFiltered': 0,
'recordsTotal': 0, 'recordsTotal': 0,
'draw': 0, 'draw': 0,
@ -185,8 +185,8 @@ class DataFactory(object):
'ORDER BY %s DESC ' \ 'ORDER BY %s DESC ' \
'LIMIT %s ' % (time_range, group_by, sort_type, stats_count) 'LIMIT %s ' % (time_range, group_by, sort_type, stats_count)
result = monitor_db.select(query) result = monitor_db.select(query)
except: except Exception as e:
logger.warn("Unable to execute database query for get_home_stats: top_tv.") logger.warn(u"PlexPy DataFactory :: Unable to execute database query for get_home_stats: top_tv: %s." % e)
return None return None
for item in result: for item in result:
@ -229,8 +229,8 @@ class DataFactory(object):
'ORDER BY users_watched DESC, %s DESC ' \ 'ORDER BY users_watched DESC, %s DESC ' \
'LIMIT %s ' % (time_range, group_by, sort_type, stats_count) 'LIMIT %s ' % (time_range, group_by, sort_type, stats_count)
result = monitor_db.select(query) result = monitor_db.select(query)
except: except Exception as e:
logger.warn("Unable to execute database query for get_home_stats: popular_tv.") logger.warn(u"PlexPy DataFactory :: Unable to execute database query for get_home_stats: popular_tv: %s." % e)
return None return None
for item in result: for item in result:
@ -270,8 +270,8 @@ class DataFactory(object):
'ORDER BY %s DESC ' \ 'ORDER BY %s DESC ' \
'LIMIT %s ' % (time_range, group_by, sort_type, stats_count) 'LIMIT %s ' % (time_range, group_by, sort_type, stats_count)
result = monitor_db.select(query) result = monitor_db.select(query)
except: except Exception as e:
logger.warn("Unable to execute database query for get_home_stats: top_movies.") logger.warn(u"PlexPy DataFactory :: Unable to execute database query for get_home_stats: top_movies: %s." % e)
return None return None
for item in result: for item in result:
@ -313,8 +313,8 @@ class DataFactory(object):
'ORDER BY users_watched DESC, %s DESC ' \ 'ORDER BY users_watched DESC, %s DESC ' \
'LIMIT %s ' % (time_range, group_by, sort_type, stats_count) 'LIMIT %s ' % (time_range, group_by, sort_type, stats_count)
result = monitor_db.select(query) result = monitor_db.select(query)
except: except Exception as e:
logger.warn("Unable to execute database query for get_home_stats: popular_movies.") logger.warn(u"PlexPy DataFactory :: Unable to execute database query for get_home_stats: popular_movies: %s." % e)
return None return None
for item in result: for item in result:
@ -354,8 +354,8 @@ class DataFactory(object):
'ORDER BY %s DESC ' \ 'ORDER BY %s DESC ' \
'LIMIT %s ' % (time_range, group_by, sort_type, stats_count) 'LIMIT %s ' % (time_range, group_by, sort_type, stats_count)
result = monitor_db.select(query) result = monitor_db.select(query)
except: except Exception as e:
logger.warn("Unable to execute database query for get_home_stats: top_music.") logger.warn(u"PlexPy DataFactory :: Unable to execute database query for get_home_stats: top_music: %s." % e)
return None return None
for item in result: for item in result:
@ -398,8 +398,8 @@ class DataFactory(object):
'ORDER BY users_watched DESC, %s DESC ' \ 'ORDER BY users_watched DESC, %s DESC ' \
'LIMIT %s ' % (time_range, group_by, sort_type, stats_count) 'LIMIT %s ' % (time_range, group_by, sort_type, stats_count)
result = monitor_db.select(query) result = monitor_db.select(query)
except: except Exception as e:
logger.warn("Unable to execute database query for get_home_stats: popular_music.") logger.warn(u"PlexPy DataFactory :: Unable to execute database query for get_home_stats: popular_music: %s." % e)
return None return None
for item in result: for item in result:
@ -424,13 +424,13 @@ class DataFactory(object):
elif stat == 'top_users': elif stat == 'top_users':
top_users = [] top_users = []
try: try:
query = 'SELECT t.user, t.user_id, t.custom_avatar_url as thumb, ' \ query = 'SELECT t.user, t.user_id, t.user_thumb, t.custom_thumb, ' \
'(CASE WHEN t.friendly_name IS NULL THEN t.username ELSE t.friendly_name END) ' \ '(CASE WHEN t.friendly_name IS NULL THEN t.username ELSE t.friendly_name END) ' \
' AS friendly_name, ' \ ' AS friendly_name, ' \
'MAX(t.started) AS last_watch, COUNT(t.id) AS total_plays, SUM(t.d) AS total_duration ' \ 'MAX(t.started) AS last_watch, COUNT(t.id) AS total_plays, SUM(t.d) AS total_duration ' \
'FROM (SELECT *, SUM(CASE WHEN stopped > 0 THEN (stopped - started) - ' \ 'FROM (SELECT *, SUM(CASE WHEN stopped > 0 THEN (stopped - started) - ' \
' (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) ' \ ' (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) ' \
' AS d ' \ ' AS d, users.thumb AS user_thumb, users.custom_avatar_url AS custom_thumb ' \
' 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 ' \
' LEFT OUTER JOIN users ON session_history.user_id = users.user_id ' \ ' LEFT OUTER JOIN users ON session_history.user_id = users.user_id ' \
@ -441,15 +441,17 @@ class DataFactory(object):
'ORDER BY %s DESC ' \ 'ORDER BY %s DESC ' \
'LIMIT %s ' % (time_range, group_by, sort_type, stats_count) 'LIMIT %s ' % (time_range, group_by, sort_type, stats_count)
result = monitor_db.select(query) result = monitor_db.select(query)
except: except Exception as e:
logger.warn("Unable to execute database query for get_home_stats: top_users.") logger.warn(u"PlexPy DataFactory :: Unable to execute database query for get_home_stats: top_users: %s." % e)
return None return None
for item in result: for item in result:
if not item['thumb'] or item['thumb'] == '': if item['custom_thumb'] and item['custom_thumb'] != item['user_thumb']:
user_thumb = common.DEFAULT_USER_THUMB user_thumb = item['custom_thumb']
elif item['user_thumb']:
user_thumb = item['user_thumb']
else: else:
user_thumb = item['thumb'] user_thumb = common.DEFAULT_USER_THUMB
row = {'user': item['user'], row = {'user': item['user'],
'user_id': item['user_id'], 'user_id': item['user_id'],
@ -490,8 +492,8 @@ class DataFactory(object):
'ORDER BY %s DESC ' \ 'ORDER BY %s DESC ' \
'LIMIT %s ' % (time_range, group_by, sort_type, stats_count) 'LIMIT %s ' % (time_range, group_by, sort_type, stats_count)
result = monitor_db.select(query) result = monitor_db.select(query)
except: except Exception as e:
logger.warn("Unable to execute database query for get_home_stats: top_platforms.") logger.warn(u"PlexPy DataFactory :: Unable to execute database query for get_home_stats: top_platforms: %s." % e)
return None return None
for item in result: for item in result:
@ -542,8 +544,8 @@ class DataFactory(object):
'ORDER BY last_watch DESC ' \ 'ORDER BY last_watch DESC ' \
'LIMIT %s' % (time_range, group_by, notify_watched_percent, stats_count) 'LIMIT %s' % (time_range, group_by, notify_watched_percent, stats_count)
result = monitor_db.select(query) result = monitor_db.select(query)
except: except Exception as e:
logger.warn("Unable to execute database query for get_home_stats: last_watched.") logger.warn(u"PlexPy DataFactory :: Unable to execute database query for get_home_stats: last_watched: %s." % e)
return None return None
for item in result: for item in result:
@ -645,8 +647,8 @@ class DataFactory(object):
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))
except: except Exception as e:
logger.warn("Unable to execute database query for get_home_stats: most_concurrent.") logger.warn(u"PlexPy DataFactory :: Unable to execute database query for get_home_stats: most_concurrent: %s." % e)
return None return None
home_stats.append({'stat_id': stat, home_stats.append({'stat_id': stat,
@ -664,10 +666,10 @@ class DataFactory(object):
try: try:
query = 'SELECT section_id, section_name, section_type, thumb, count, parent_count, child_count ' \ query = 'SELECT section_id, section_name, section_type, thumb, count, parent_count, child_count ' \
'FROM library_sections ' \ 'FROM library_sections ' \
'WHERE section_id = %s' % id 'WHERE section_id = %s ' % id
result = monitor_db.select(query) result = monitor_db.select(query)
except: except Exception as e:
logger.warn("Unable to execute database query for get_library_stats.") logger.warn(u"PlexPy DataFactory :: Unable to execute database query for get_library_stats: %s." % e)
return None return None
for item in result: for item in result:
@ -725,86 +727,6 @@ class DataFactory(object):
return stream_output return stream_output
def get_recently_watched(self, user=None, user_id=None, library_id=None, limit='10'):
monitor_db = database.MonitorDatabase()
recently_watched = []
if not limit.isdigit():
limit = '10'
try:
if user_id:
query = 'SELECT session_history.id, session_history.media_type, session_history.rating_key, session_history.parent_rating_key, ' \
'title, parent_title, grandparent_title, thumb, parent_thumb, grandparent_thumb, media_index, parent_media_index, ' \
'year, started, user ' \
'FROM session_history_metadata ' \
'JOIN session_history ON session_history_metadata.id = session_history.id ' \
'WHERE user_id = ? ' \
'GROUP BY (CASE WHEN session_history.media_type = "track" THEN session_history.parent_rating_key ' \
' ELSE session_history.rating_key END) ' \
'ORDER BY started DESC LIMIT ?'
result = monitor_db.select(query, args=[user_id, limit])
elif user:
query = 'SELECT session_history.id, session_history.media_type, session_history.rating_key, session_history.parent_rating_key, ' \
'title, parent_title, grandparent_title, thumb, parent_thumb, grandparent_thumb, media_index, parent_media_index, ' \
'year, started, user ' \
'FROM session_history_metadata ' \
'JOIN session_history ON session_history_metadata.id = session_history.id ' \
'WHERE user = ? ' \
'GROUP BY (CASE WHEN session_history.media_type = "track" THEN session_history.parent_rating_key ' \
' ELSE session_history.rating_key END) ' \
'ORDER BY started DESC LIMIT ?'
result = monitor_db.select(query, args=[user, limit])
elif library_id:
query = 'SELECT session_history.id, session_history.media_type, session_history.rating_key, session_history.parent_rating_key, ' \
'title, parent_title, grandparent_title, thumb, parent_thumb, grandparent_thumb, media_index, parent_media_index, ' \
'year, started, user ' \
'FROM session_history_metadata ' \
'JOIN session_history ON session_history_metadata.id = session_history.id ' \
'WHERE library_id = ? ' \
'GROUP BY (CASE WHEN session_history.media_type = "track" THEN session_history.parent_rating_key ' \
' ELSE session_history.rating_key END) ' \
'ORDER BY started DESC LIMIT ?'
result = monitor_db.select(query, args=[library_id, limit])
else:
query = 'SELECT session_history.id, session_history.media_type, session_history.rating_key, session_history.parent_rating_key, ' \
'title, parent_title, grandparent_title, thumb, parent_thumb, grandparent_thumb, media_index, parent_media_index, ' \
'year, started, user ' \
'FROM session_history_metadata ' \
'JOIN session_history ON session_history_metadata.id = session_history.id ' \
'GROUP BY (CASE WHEN session_history.media_type = "track" THEN session_history.parent_rating_key ' \
' ELSE session_history.rating_key END) ' \
'ORDER BY started DESC LIMIT ?'
result = monitor_db.select(query, args=[limit])
except:
logger.warn("Unable to execute database query for get_recently_watched.")
return None
for row in result:
if row['media_type'] == 'episode' and row['parent_thumb']:
thumb = row['parent_thumb']
elif row['media_type'] == 'episode':
thumb = row['grandparent_thumb']
else:
thumb = row['thumb']
recent_output = {'row_id': row['id'],
'type': row['media_type'],
'rating_key': row['rating_key'],
'title': row['title'],
'parent_title': row['parent_title'],
'grandparent_title': row['grandparent_title'],
'thumb': thumb,
'media_index': row['media_index'],
'parent_media_index': row['parent_media_index'],
'year': row['year'],
'time': row['started'],
'user': row['user']
}
recently_watched.append(recent_output)
return recently_watched
def get_metadata_details(self, rating_key): def get_metadata_details(self, rating_key):
monitor_db = database.MonitorDatabase() monitor_db = database.MonitorDatabase()
@ -866,89 +788,52 @@ class DataFactory(object):
'directors': directors, 'directors': directors,
'genres': genres, 'genres': genres,
'actors': actors, 'actors': actors,
'library_title': item['section_name'], 'library_name': item['section_name'],
'library_id': item['library_id'] 'library_id': item['library_id']
} }
return metadata return metadata
def delete_session_history_rows(self, row_id=None): def get_total_duration(self, custom_where=None):
monitor_db = database.MonitorDatabase() monitor_db = database.MonitorDatabase()
if row_id.isdigit(): # Split up custom wheres
logger.info(u"PlexPy DataFactory :: Deleting row id %s from the session history database." % row_id) if custom_where:
session_history_del = \ where = 'WHERE ' + ' AND '.join([w[0] + ' = "' + w[1] + '"' for w in custom_where])
monitor_db.action('DELETE FROM session_history WHERE id = ?', [row_id])
session_history_media_info_del = \
monitor_db.action('DELETE FROM session_history_media_info WHERE id = ?', [row_id])
session_history_metadata_del = \
monitor_db.action('DELETE FROM session_history_metadata WHERE id = ?', [row_id])
return 'Deleted rows %s.' % row_id
else: else:
return 'Unable to delete rows. Input row not valid.' where = ''
def delete_all_user_history(self, user_id=None): try:
query = 'SELECT SUM(CASE WHEN stopped > 0 THEN (stopped - started) ELSE 0 END) - ' \
'SUM(CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) AS total_duration ' \
'FROM session_history ' \
'JOIN session_history_metadata ON session_history_metadata.id = session_history.id ' \
'%s ' % where
result = monitor_db.select(query)
except Exception as e:
logger.warn(u"PlexPy DataFactory :: Unable to execute database query for get_total_duration: %s." % e)
return None
for item in result:
total_duration = item['total_duration']
return total_duration
def get_session_ip(self, session_key=''):
monitor_db = database.MonitorDatabase() monitor_db = database.MonitorDatabase()
if user_id.isdigit(): if session_key:
logger.info(u"PlexPy DataFactory :: Deleting all history for user id %s from database." % user_id) query = 'SELECT ip_address FROM sessions WHERE session_key = %d' % int(session_key)
session_history_media_info_del = \ result = monitor_db.select(query)
monitor_db.action('DELETE FROM '
'session_history_media_info '
'WHERE session_history_media_info.id IN (SELECT session_history_media_info.id '
'FROM session_history_media_info '
'JOIN session_history ON session_history_media_info.id = session_history.id '
'WHERE session_history.user_id = ?)', [user_id])
session_history_metadata_del = \
monitor_db.action('DELETE FROM '
'session_history_metadata '
'WHERE session_history_metadata.id IN (SELECT session_history_metadata.id '
'FROM session_history_metadata '
'JOIN session_history ON session_history_metadata.id = session_history.id '
'WHERE session_history.user_id = ?)', [user_id])
session_history_del = \
monitor_db.action('DELETE FROM '
'session_history '
'WHERE session_history.user_id = ?', [user_id])
return 'Deleted all items for user_id %s.' % user_id
else: else:
return 'Unable to delete items. Input user_id not valid.' return None
def delete_user(self, user_id=None): ip_address = 'N/A'
monitor_db = database.MonitorDatabase()
if user_id.isdigit(): for item in result:
self.delete_all_user_history(user_id) ip_address = item['ip_address']
logger.info(u"PlexPy DataFactory :: Deleting user with id %s from database." % user_id)
monitor_db.action('UPDATE users SET deleted_user = 1 WHERE user_id = ?', [user_id])
monitor_db.action('UPDATE users SET keep_history = 0 WHERE user_id = ?', [user_id])
monitor_db.action('UPDATE users SET do_notify = 0 WHERE user_id = ?', [user_id])
return 'Deleted user with id %s.' % user_id return ip_address
else:
return 'Unable to delete user. Input user_id not valid.'
def undelete_user(self, user_id=None, username=None):
monitor_db = database.MonitorDatabase()
if user_id and user_id.isdigit():
logger.info(u"PlexPy DataFactory :: Re-adding user with id %s to database." % user_id)
monitor_db.action('UPDATE users SET deleted_user = 0 WHERE user_id = ?', [user_id])
monitor_db.action('UPDATE users SET keep_history = 1 WHERE user_id = ?', [user_id])
monitor_db.action('UPDATE users SET do_notify = 1 WHERE user_id = ?', [user_id])
return 'Re-added user with id %s.' % user_id
elif username:
logger.info(u"PlexPy DataFactory :: Re-adding user with username %s to database." % username)
monitor_db.action('UPDATE users SET deleted_user = 0 WHERE username = ?', [username])
monitor_db.action('UPDATE users SET keep_history = 1 WHERE username = ?', [username])
monitor_db.action('UPDATE users SET do_notify = 1 WHERE username = ?', [username])
return 'Re-added user with username %s.' % username
else:
return 'Unable to re-add user. Input user_id or username not valid.'
def get_search_query(self, rating_key=''): def get_search_query(self, rating_key=''):
monitor_db = database.MonitorDatabase() monitor_db = database.MonitorDatabase()
@ -1037,8 +922,8 @@ class DataFactory(object):
grandparent_rating_key = result[0]['grandparent_rating_key'] grandparent_rating_key = result[0]['grandparent_rating_key']
except: except Exception as e:
logger.warn("Unable to execute database query for get_rating_keys_list.") logger.warn(u"PlexPy DataFactory :: Unable to execute database query for get_rating_keys_list: %s." % e)
return {} return {}
query = 'SELECT rating_key, parent_rating_key, grandparent_rating_key, title, parent_title, grandparent_title, ' \ query = 'SELECT rating_key, parent_rating_key, grandparent_rating_key, title, parent_title, grandparent_title, ' \
@ -1081,6 +966,22 @@ class DataFactory(object):
return key_list return key_list
def delete_session_history_rows(self, row_id=None):
monitor_db = database.MonitorDatabase()
if row_id.isdigit():
logger.info(u"PlexPy DataFactory :: Deleting row id %s from the session history database." % row_id)
session_history_del = \
monitor_db.action('DELETE FROM session_history WHERE id = ?', [row_id])
session_history_media_info_del = \
monitor_db.action('DELETE FROM session_history_media_info WHERE id = ?', [row_id])
session_history_metadata_del = \
monitor_db.action('DELETE FROM session_history_metadata WHERE id = ?', [row_id])
return 'Deleted rows %s.' % row_id
else:
return 'Unable to delete rows. Input row not valid.'
def update_metadata(self, old_key_list='', new_key_list='', media_type=''): def update_metadata(self, old_key_list='', new_key_list='', media_type=''):
from plexpy import pmsconnect from plexpy import pmsconnect
pms_connect = pmsconnect.PmsConnect() pms_connect = pmsconnect.PmsConnect()
@ -1134,8 +1035,6 @@ class DataFactory(object):
return 'Updated metadata in database.' return 'Updated metadata in database.'
else: else:
return 'Unable to update metadata in database. No changes were made.' return 'Unable to update metadata in database. No changes were made.'
# for debugging
#return mapping
def update_metadata_details(self, old_rating_key='', new_rating_key='', metadata=None): def update_metadata_details(self, old_rating_key='', new_rating_key='', metadata=None):
@ -1176,31 +1075,6 @@ class DataFactory(object):
monitor_db.action(query=query, args=args) monitor_db.action(query=query, args=args)
def get_total_duration(self, custom_where=None):
monitor_db = database.MonitorDatabase()
# Split up custom wheres
if custom_where:
where = 'WHERE ' + ' AND '.join([w[0] + ' = "' + w[1] + '"' for w in custom_where])
else:
where = ''
try:
query = 'SELECT SUM(CASE WHEN stopped > 0 THEN (stopped - started) ELSE 0 END) - ' \
'SUM(CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) AS total_duration ' \
'FROM session_history ' \
'JOIN session_history_metadata ON session_history_metadata.id = session_history.id ' \
'%s ' % where
result = monitor_db.select(query)
except:
logger.warn("Unable to execute database query for get_total_duration.")
return None
for item in result:
total_duration = item['total_duration']
return total_duration
def update_library_ids(self): def update_library_ids(self):
from plexpy import pmsconnect from plexpy import pmsconnect
@ -1210,8 +1084,8 @@ class DataFactory(object):
try: try:
query = 'SELECT id, rating_key FROM session_history_metadata WHERE library_id IS NULL' query = 'SELECT id, rating_key FROM session_history_metadata WHERE library_id IS NULL'
result = monitor_db.select(query=query) result = monitor_db.select(query=query)
except: except Exception as e:
logger.warn("Unable to execute database query for update_library_id.") logger.warn(u"PlexPy DataFactory :: Unable to execute database query for update_library_id: %s." % e)
return None return None
for item in result: for item in result:
@ -1231,59 +1105,3 @@ class DataFactory(object):
continue continue
return True return True
def get_library_sections(self):
monitor_db = database.MonitorDatabase()
try:
query = 'SELECT section_id, section_name FROM library_sections'
result = monitor_db.select(query=query)
except:
logger.warn("Unable to execute database query for get_library_sections.")
return None
libraries = []
for item in result:
library = {'section_id': item['section_id'],
'section_name': item['section_name']
}
libraries.append(library)
return libraries
def update_library_sections(self):
from plexpy import pmsconnect
pms_connect = pmsconnect.PmsConnect()
library_sections = pms_connect.get_server_children()
if library_sections:
if library_sections['libraries_count'] != '0':
monitor_db = database.MonitorDatabase()
for section in library_sections['libraries_list']:
section_keys = {'section_id': section['key']}
section_values = {'section_id': section['key'],
'section_name': section['title'],
'section_type': section['type']}
monitor_db.upsert('library_sections', key_dict=section_keys, value_dict=section_values)
return True
def get_session_ip(self, session_key=''):
monitor_db = database.MonitorDatabase()
if session_key:
query = 'SELECT ip_address FROM sessions WHERE session_key = %d' % int(session_key)
result = monitor_db.select(query)
else:
return None
ip_address = 'N/A'
for item in result:
ip_address = item['ip_address']
return ip_address

View file

@ -14,6 +14,7 @@
# 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, datatables, common, database, helpers from plexpy import logger, datatables, common, database, helpers
import plexpy
class Libraries(object): class Libraries(object):
@ -21,22 +22,23 @@ class Libraries(object):
def __init__(self): def __init__(self):
pass pass
def get_library_list(self, kwargs=None): def get_datatables_list(self, kwargs=None):
data_tables = datatables.DataTables() data_tables = datatables.DataTables()
custom_where = ['library_sections.deleted_section', 0]
columns = ['library_sections.section_id', columns = ['library_sections.section_id',
'library_sections.section_name', 'library_sections.section_name',
'library_sections.section_type', 'library_sections.section_type',
'library_sections.count as count', 'library_sections.count',
'library_sections.parent_count', 'library_sections.parent_count',
'library_sections.child_count', 'library_sections.child_count',
'library_sections.thumb AS library_thumb', 'library_sections.thumb AS library_thumb',
'(CASE WHEN library_sections.custom_thumb_url == library_sections.thumb \ 'library_sections.custom_thumb_url AS custom_thumb',
THEN NULL ELSE custom_thumb_url END) AS custom_thumb',
'library_sections.art', 'library_sections.art',
'COUNT(session_history.id) as plays', 'COUNT(session_history.id) AS plays',
'MAX(session_history.started) as last_accessed', 'MAX(session_history.started) AS last_accessed',
'session_history_metadata.full_title as last_watched', 'session_history_metadata.full_title AS last_watched',
'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',
@ -44,12 +46,13 @@ class Libraries(object):
'session_history.rating_key', 'session_history.rating_key',
'session_history_media_info.video_decision', 'session_history_media_info.video_decision',
'library_sections.do_notify', 'library_sections.do_notify',
'library_sections.do_notify_created',
'library_sections.keep_history' 'library_sections.keep_history'
] ]
try: try:
query = data_tables.ssp_query(table_name='library_sections', query = data_tables.ssp_query(table_name='library_sections',
columns=columns, columns=columns,
custom_where=[], custom_where=[custom_where],
group_by=['library_sections.section_id'], group_by=['library_sections.section_id'],
join_types=['LEFT OUTER JOIN', join_types=['LEFT OUTER JOIN',
'LEFT OUTER JOIN', 'LEFT OUTER JOIN',
@ -61,8 +64,8 @@ class Libraries(object):
['session_history_metadata.id', 'session_history.id'], ['session_history_metadata.id', 'session_history.id'],
['session_history_metadata.id', 'session_history_media_info.id']], ['session_history_metadata.id', 'session_history_media_info.id']],
kwargs=kwargs) kwargs=kwargs)
except: except Exception as e:
logger.warn("Unable to execute database query for get_library_list.") logger.warn(u"PlexPy Libraries :: Unable to execute database query for get_list: %s." % e)
return {'recordsFiltered': 0, return {'recordsFiltered': 0,
'recordsTotal': 0, 'recordsTotal': 0,
'draw': 0, 'draw': 0,
@ -80,23 +83,30 @@ class Libraries(object):
else: else:
thumb = item['thumb'] thumb = item['thumb']
row = {'plays': item['plays'], if item['custom_thumb'] and item['custom_thumb'] != item['library_thumb']:
library_thumb = item['custom_thumb']
elif item['library_thumb']:
library_thumb = item['library_thumb']
else:
library_thumb = common.DEFAULT_COVER_THUMB
row = {'section_id': item['section_id'],
'section_name': item['section_name'],
'section_type': item['section_type'].capitalize(),
'count': item['count'],
'parent_count': item['parent_count'],
'child_count': item['child_count'],
'library_thumb': library_thumb,
'library_art': item['art'],
'plays': item['plays'],
'last_accessed': item['last_accessed'], 'last_accessed': item['last_accessed'],
'last_watched': item['last_watched'], 'last_watched': item['last_watched'],
'thumb': thumb, 'thumb': thumb,
'media_type': item['media_type'], 'media_type': item['media_type'],
'rating_key': item['rating_key'], 'rating_key': item['rating_key'],
'video_decision': item['video_decision'], 'video_decision': item['video_decision'],
'section_id': item['section_id'],
'section_name': item['section_name'],
'section_type': item['section_type'].capitalize(),
'count': item['count'],
'parent_count': item['parent_count'],
'library_thumb': item['library_thumb'],
'custom_thumb': item['custom_thumb'],
'library_art': item['art'],
'child_count': item['child_count'],
'do_notify': helpers.checked(item['do_notify']), 'do_notify': helpers.checked(item['do_notify']),
'do_notify_created': helpers.checked(item['do_notify_created']),
'keep_history': helpers.checked(item['keep_history']) 'keep_history': helpers.checked(item['keep_history'])
} }
@ -110,107 +120,130 @@ class Libraries(object):
return dict return dict
def set_library_config(self, section_id=None, do_notify=1, keep_history=1, custom_thumb=''): def set_config(self, section_id=None, custom_thumb='', do_notify=1, keep_history=1, do_notify_created=1):
if section_id: if section_id:
monitor_db = database.MonitorDatabase() monitor_db = database.MonitorDatabase()
key_dict = {'section_id': section_id} key_dict = {'section_id': section_id}
value_dict = {'do_notify': do_notify, value_dict = {'custom_thumb_url': custom_thumb,
'keep_history': keep_history, 'do_notify': do_notify,
'custom_thumb_url': custom_thumb} 'do_notify_created': do_notify_created,
'keep_history': keep_history}
try: try:
monitor_db.upsert('library_sections', value_dict, key_dict) monitor_db.upsert('library_sections', value_dict, key_dict)
except: except:
logger.warn("Unable to execute database query for set_user_friendly_name.") logger.warn(u"PlexPy Libraries :: Unable to execute database query for set_config: %s." % e)
def get_library_details(self, section_id=None): def get_details(self, section_id=None):
from plexpy import pmsconnect from plexpy import pmsconnect
monitor_db = database.MonitorDatabase() monitor_db = database.MonitorDatabase()
try:
if section_id: if section_id:
query = 'SELECT section_id, section_name, section_type, count, parent_count, child_count, ' \ query = 'SELECT section_id, section_name, section_type, count, parent_count, child_count, ' \
'thumb AS library_thumb, (CASE WHEN library_sections.custom_thumb_url == library_sections.thumb ' \ 'thumb AS library_thumb, custom_thumb_url AS custom_thumb, art, ' \
' THEN NULL ELSE custom_thumb_url END) AS custom_thumb, art, do_notify, keep_history ' \ 'do_notify, do_notify_created, keep_history ' \
'FROM library_sections ' \ 'FROM library_sections ' \
'WHERE section_id = ? ' 'WHERE section_id = ? '
result = monitor_db.select(query, args=[section_id]) result = monitor_db.select(query, args=[section_id])
else: else:
result = None result = []
except Exception as e:
logger.warn(u"PlexPy Libraries :: Unable to execute database query for get_details: %s." % e)
result = []
if result: if result:
library_details = {} library_details = {}
for item in result: for item in result:
if item['custom_thumb'] and item['custom_thumb'] != item['library_thumb']:
library_thumb = item['custom_thumb']
elif item['library_thumb']:
library_thumb = item['library_thumb']
else:
library_thumb = common.DEFAULT_COVER_THUMB
library_details = {'section_id': item['section_id'], library_details = {'section_id': item['section_id'],
'section_name': item['section_name'], 'section_name': item['section_name'],
'section_type': item['section_type'], 'section_type': item['section_type'],
'library_thumb': item['library_thumb'], 'library_thumb': library_thumb,
'custom_thumb': item['custom_thumb'],
'library_art': item['art'], 'library_art': item['art'],
'count': item['count'], 'count': item['count'],
'parent_count': item['parent_count'], 'parent_count': item['parent_count'],
'child_count': item['child_count'], 'child_count': item['child_count'],
'do_notify': item['do_notify'], 'do_notify': item['do_notify'],
'do_notify_created': item['do_notify_created'],
'keep_history': item['keep_history'] 'keep_history': item['keep_history']
} }
return library_details return library_details
else: else:
logger.warn(u"PlexPy :: Unable to retrieve library from local database. Requesting library list refresh.") logger.warn(u"PlexPy Libraries :: Unable to retrieve library from local database. Requesting library list refresh.")
# 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
try:
if section_id: if section_id:
# Refresh libraries # Refresh libraries
pmsconnect.refresh_libraries() pmsconnect.refresh_libraries()
query = 'SELECT section_id, section_name, section_type, count, parent_count, child_count, ' \ query = 'SELECT section_id, section_name, section_type, count, parent_count, child_count, ' \
'thumb AS library_thumb, (CASE WHEN library_sections.custom_thumb_url == library_sections.thumb ' \ 'thumb AS library_thumb, custom_thumb_url AS custom_thumb, art, ' \
' THEN NULL ELSE custom_thumb_url END) AS custom_thumb, art, do_notify, keep_history ' \ 'do_notify, do_notify_created, keep_history ' \
'FROM library_sections ' \ 'FROM library_sections ' \
'WHERE section_id = ? ' 'WHERE section_id = ? '
result = monitor_db.select(query, args=[section_id]) result = monitor_db.select(query, args=[section_id])
else: else:
result = None result = []
except:
logger.warn(u"PlexPy Libraries :: Unable to execute database query for get_details: %s." % e)
result = []
if result: if result:
library_details = {} library_details = {}
for item in result: for item in result:
if item['custom_thumb'] and item['custom_thumb'] != item['library_thumb']:
library_thumb = item['custom_thumb']
elif item['library_thumb']:
library_thumb = item['library_thumb']
else:
library_thumb = common.DEFAULT_COVER_THUMB
library_details = {'section_id': item['section_id'], library_details = {'section_id': item['section_id'],
'section_name': item['section_name'], 'section_name': item['section_name'],
'section_type': item['section_type'], 'section_type': item['section_type'],
'library_thumb': item['library_thumb'], 'library_thumb': library_thumb,
'custom_thumb': item['custom_thumb'],
'library_art': item['art'], 'library_art': item['art'],
'count': item['count'], 'count': item['count'],
'parent_count': item['parent_count'], 'parent_count': item['parent_count'],
'child_count': item['child_count'], 'child_count': item['child_count'],
'do_notify': item['do_notify'], 'do_notify': item['do_notify'],
'do_notify_created': item['do_notify_created'],
'keep_history': item['keep_history'] 'keep_history': item['keep_history']
} }
return user_details return library_details
else: else:
# If there is no library data we must return something # If there is no library 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 {'section_id': None, return {'section_id': None,
'section_name': '', 'section_name': 'Local',
'section_type': '', 'section_type': '',
'library_thumb': '', 'library_thumb': common.DEFAULT_COVER_THUMB,
'custom_thumb': '',
'library_art': '', 'library_art': '',
'count': 0, 'count': 0,
'parent_count': 0, 'parent_count': 0,
'child_count': 0, 'child_count': 0,
'do_notify': 0, 'do_notify': 0,
'do_notify_created': 0,
'keep_history': 0 'keep_history': 0
} }
def get_library_watch_time_stats(self, library_id=None): def get_watch_time_stats(self, library_id=None):
monitor_db = database.MonitorDatabase() monitor_db = database.MonitorDatabase()
time_queries = [1, 7, 30, 0] time_queries = [1, 7, 30, 0]
library_watch_time_stats = [] library_watch_time_stats = []
for days in time_queries: for days in time_queries:
try:
if days > 0: if days > 0:
if library_id: if str(library_id).isdigit():
query = 'SELECT (SUM(stopped - started) - ' \ query = 'SELECT (SUM(stopped - started) - ' \
'SUM(CASE WHEN paused_counter is null THEN 0 ELSE paused_counter END)) as total_time, ' \ 'SUM(CASE WHEN paused_counter is null THEN 0 ELSE paused_counter END)) as total_time, ' \
'COUNT(session_history.id) AS total_plays ' \ 'COUNT(session_history.id) AS total_plays ' \
@ -220,6 +253,9 @@ class Libraries(object):
'AND library_id = ?' % days 'AND library_id = ?' % days
result = monitor_db.select(query, args=[library_id]) result = monitor_db.select(query, args=[library_id])
else: else:
result = []
else:
if str(library_id).isdigit():
query = 'SELECT (SUM(stopped - started) - ' \ query = 'SELECT (SUM(stopped - started) - ' \
'SUM(CASE WHEN paused_counter is null THEN 0 ELSE paused_counter END)) as total_time, ' \ 'SUM(CASE WHEN paused_counter is null THEN 0 ELSE paused_counter END)) as total_time, ' \
'COUNT(session_history.id) AS total_plays ' \ 'COUNT(session_history.id) AS total_plays ' \
@ -227,6 +263,11 @@ class Libraries(object):
'JOIN session_history_metadata ON session_history_metadata.id = session_history.id ' \ 'JOIN session_history_metadata ON session_history_metadata.id = session_history.id ' \
'WHERE library_id = ?' 'WHERE library_id = ?'
result = monitor_db.select(query, args=[library_id]) result = monitor_db.select(query, args=[library_id])
else:
result = []
except Exception as e:
logger.warn(u"PlexPy Libraries :: Unable to execute database query for get_watch_time_stats: %s." % e)
result = []
for item in result: for item in result:
if item['total_time']: if item['total_time']:
@ -245,13 +286,13 @@ class Libraries(object):
return library_watch_time_stats return library_watch_time_stats
def get_library_user_stats(self, library_id=None): def get_user_stats(self, library_id=None):
monitor_db = database.MonitorDatabase() monitor_db = database.MonitorDatabase()
user_stats = [] user_stats = []
try: try:
if library_id: if str(library_id).isdigit():
query = 'SELECT (CASE WHEN users.friendly_name IS NULL THEN users.username ' \ query = 'SELECT (CASE WHEN users.friendly_name IS NULL THEN users.username ' \
'ELSE users.friendly_name END) AS user, users.user_id, users.thumb, COUNT(user) AS user_count ' \ 'ELSE users.friendly_name END) AS user, users.user_id, users.thumb, COUNT(user) AS user_count ' \
'FROM session_history ' \ 'FROM session_history ' \
@ -261,9 +302,11 @@ class Libraries(object):
'GROUP BY user ' \ 'GROUP BY user ' \
'ORDER BY user_count DESC' 'ORDER BY user_count DESC'
result = monitor_db.select(query, args=[library_id]) result = monitor_db.select(query, args=[library_id])
except: else:
logger.warn("Unable to execute database query for get_library_user_stats.") result = []
return None except Exception as e:
logger.warn(u"PlexPy Libraries :: Unable to execute database query for get_user_stats: %s." % e)
result = []
for item in result: for item in result:
row = {'user': item['user'], row = {'user': item['user'],
@ -275,9 +318,79 @@ class Libraries(object):
return user_stats return user_stats
def delete_all_library_history(self, section_id=None): def get_recently_watched(self, library_id=None, limit='10'):
monitor_db = database.MonitorDatabase()
recently_watched = []
if not limit.isdigit():
limit = '10'
try:
if str(library_id).isdigit():
query = 'SELECT session_history.id, session_history.media_type, session_history.rating_key, session_history.parent_rating_key, ' \
'title, parent_title, grandparent_title, thumb, parent_thumb, grandparent_thumb, media_index, parent_media_index, ' \
'year, started, user ' \
'FROM session_history_metadata ' \
'JOIN session_history ON session_history_metadata.id = session_history.id ' \
'WHERE library_id = ? ' \
'GROUP BY (CASE WHEN session_history.media_type = "track" THEN session_history.parent_rating_key ' \
' ELSE session_history.rating_key END) ' \
'ORDER BY started DESC LIMIT ?'
result = monitor_db.select(query, args=[library_id, limit])
else:
result = []
except Exception as e:
logger.warn(u"PlexPy Libraries :: Unable to execute database query for get_recently_watched: %s." % e)
result = []
for row in result:
if row['media_type'] == 'episode' and row['parent_thumb']:
thumb = row['parent_thumb']
elif row['media_type'] == 'episode':
thumb = row['grandparent_thumb']
else:
thumb = row['thumb']
recent_output = {'row_id': row['id'],
'type': row['media_type'],
'rating_key': row['rating_key'],
'title': row['title'],
'parent_title': row['parent_title'],
'grandparent_title': row['grandparent_title'],
'thumb': thumb,
'media_index': row['media_index'],
'parent_media_index': row['parent_media_index'],
'year': row['year'],
'time': row['started'],
'user': row['user']
}
recently_watched.append(recent_output)
return recently_watched
def get_sections(self):
monitor_db = database.MonitorDatabase() monitor_db = database.MonitorDatabase()
try:
query = 'SELECT section_id, section_name FROM library_sections WHERE deleted_section = 0'
result = monitor_db.select(query=query)
except Exception as e:
logger.warn(u"PlexPy Libraries :: Unable to execute database query for get_sections: %s." % e)
return None
libraries = []
for item in result:
library = {'section_id': item['section_id'],
'section_name': item['section_name']
}
libraries.append(library)
return libraries
def delete_all_history(self, section_id=None):
monitor_db = database.MonitorDatabase()
try:
if section_id.isdigit(): if section_id.isdigit():
logger.info(u"PlexPy Libraries :: Deleting all history for library id %s from database." % section_id) logger.info(u"PlexPy Libraries :: Deleting all history for library id %s from database." % section_id)
session_history_media_info_del = \ session_history_media_info_del = \
@ -299,6 +412,57 @@ class Libraries(object):
'session_history_metadata ' 'session_history_metadata '
'WHERE session_history_metadata.library_id = ?', [section_id]) 'WHERE session_history_metadata.library_id = ?', [section_id])
return 'Deleted all items for library_id %s.' % section_id return 'Deleted all items for section_id %s.' % section_id
else: else:
return 'Unable to delete items. Input library_id not valid.' return 'Unable to delete items, section_id not valid.'
except Exception as e:
logger.warn(u"PlexPy Libraries :: Unable to execute database query for delete_all_history: %s." % e)
def delete(self, section_id=None):
monitor_db = database.MonitorDatabase()
try:
if section_id.isdigit():
self.delete_all_history(section_id)
logger.info(u"PlexPy Libraries :: Deleting library with id %s from database." % section_id)
monitor_db.action('UPDATE library_sections SET deleted_section = 1 WHERE section_id = ?', [section_id])
monitor_db.action('UPDATE library_sections SET keep_history = 0 WHERE section_id = ?', [section_id])
monitor_db.action('UPDATE library_sections SET do_notify = 0 WHERE section_id = ?', [section_id])
monitor_db.action('UPDATE library_sections SET do_notify_created = 0 WHERE section_id = ?', [section_id])
library_cards = plexpy.CONFIG.HOME_LIBRARY_CARDS
if section_id in library_cards:
library_cards.remove(section_id)
plexpy.CONFIG.__setattr__('HOME_LIBRARY_CARDS', library_cards)
plexpy.CONFIG.write()
return 'Deleted library with id %s.' % section_id
else:
return 'Unable to delete library, section_id not valid.'
except Exception as e:
logger.warn(u"PlexPy Libraries :: Unable to execute database query for delete: %s." % e)
def undelete(self, section_id=None, section_name=None):
monitor_db = database.MonitorDatabase()
try:
if section_id and section_id.isdigit():
logger.info(u"PlexPy Libraries :: Re-adding library with id %s to database." % section_id)
monitor_db.action('UPDATE library_sections SET deleted_section = 0 WHERE section_id = ?', [section_id])
monitor_db.action('UPDATE library_sections SET keep_history = 1 WHERE section_id = ?', [section_id])
monitor_db.action('UPDATE library_sections SET do_notify = 1 WHERE section_id = ?', [section_id])
monitor_db.action('UPDATE library_sections SET do_notify_created = 1 WHERE section_id = ?', [section_id])
return 'Re-added library with id %s.' % section_id
elif section_name:
logger.info(u"PlexPy Libraries :: Re-adding library with name %s to database." % section_name)
monitor_db.action('UPDATE library_sections SET deleted_section = 0 WHERE section_name = ?', [section_name])
monitor_db.action('UPDATE library_sections SET keep_history = 1 WHERE section_name = ?', [section_name])
monitor_db.action('UPDATE library_sections SET do_notify = 1 WHERE section_name = ?', [section_name])
monitor_db.action('UPDATE library_sections SET do_notify_created = 1 WHERE section_name = ?', [section_name])
return 'Re-added library with section_name %s.' % section_name
else:
return 'Unable to re-add library, section_id or section_name not valid.'
except Exception as e:
logger.warn(u"PlexPy Libraries :: Unable to execute database query for undelete: %s." % e)

View file

@ -16,20 +16,28 @@
import re import re
import time import time
import re
from plexpy import logger, config, notifiers, database, helpers, plextv, pmsconnect from plexpy import logger, config, notifiers, database, helpers, plextv, pmsconnect
import plexpy import plexpy
def notify(stream_data=None, notify_action=None): def notify(stream_data=None, notify_action=None):
from plexpy import users from plexpy import users, libraries
if stream_data and notify_action: if stream_data and notify_action:
# Check if notifications enabled for user # Check if notifications enabled for user and library
user_data = users.Users() user_data = users.Users()
user_details = user_data.get_user_friendly_name(user=stream_data['user']) user_details = user_data.get_details(user_id=stream_data['user_id'])
library_data = libraries.Libraries()
library_details = library_data.get_details(section_id=stream_data['library_id'])
if not user_details['do_notify']: if not user_details['do_notify']:
# logger.debug(u"PlexPy NotificationHandler :: Notifications for user '%s' is disabled." % user_details['username'])
return
elif not library_details['do_notify']:
# logger.debug(u"PlexPy NotificationHandler :: Notifications for library '%s' is disabled." % library_details['section_name'])
return return
if (stream_data['media_type'] == 'movie' and plexpy.CONFIG.MOVIE_NOTIFY_ENABLE) \ if (stream_data['media_type'] == 'movie' and plexpy.CONFIG.MOVIE_NOTIFY_ENABLE) \
@ -195,10 +203,10 @@ def notify(stream_data=None, notify_action=None):
elif stream_data['media_type'] == 'clip': elif stream_data['media_type'] == 'clip':
pass pass
else: else:
#logger.debug(u"PlexPy Notifier :: Notify called with unsupported media type.") #logger.debug(u"PlexPy NotificationHandler :: Notify called with unsupported media type.")
pass pass
else: else:
logger.debug(u"PlexPy Notifier :: Notify called but incomplete data received.") logger.debug(u"PlexPy NotificationHandler :: Notify called but incomplete data received.")
def notify_timeline(timeline_data=None, notify_action=None): def notify_timeline(timeline_data=None, notify_action=None):
@ -256,7 +264,7 @@ def notify_timeline(timeline_data=None, notify_action=None):
notify_action=notify_action, notify_action=notify_action,
script_args=notify_strings[2]) script_args=notify_strings[2])
else: else:
logger.debug(u"PlexPy Notifier :: Notify timeline called but incomplete data received.") logger.debug(u"PlexPy NotificationHandler :: Notify timeline called but incomplete data received.")
def get_notify_state(session): def get_notify_state(session):
@ -334,11 +342,10 @@ def set_notify_state(session, state, agent_info):
monitor_db.upsert(table_name='notify_log', key_dict=keys, value_dict=values) monitor_db.upsert(table_name='notify_log', key_dict=keys, value_dict=values)
else: else:
logger.error('PlexPy Notifier :: Unable to set notify state.') logger.error(u"PlexPy NotificationHandler :: Unable to set notify state.")
def build_notify_text(session=None, timeline=None, state=None): def build_notify_text(session=None, timeline=None, state=None):
# Get the server name # Get the server name
server_name = plexpy.CONFIG.PMS_NAME server_name = plexpy.CONFIG.PMS_NAME
@ -350,7 +357,7 @@ def build_notify_text(session=None, timeline=None, state=None):
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_float(updated_at))) server_uptime = helpers.human_duration(int(time.time() - helpers.cast_to_float(updated_at)))
else: else:
logger.error(u"PlexPy Notifier :: Unable to retrieve server uptime.") logger.error(u"PlexPy NotificationHandler :: Unable to retrieve server uptime.")
server_uptime = 'N/A' server_uptime = 'N/A'
# Get metadata feed for item # Get metadata feed for item
@ -367,7 +374,7 @@ def build_notify_text(session=None, timeline=None, state=None):
if metadata_list: if metadata_list:
metadata = metadata_list['metadata'] metadata = metadata_list['metadata']
else: else:
logger.error(u"PlexPy Notifier :: Unable to retrieve metadata for rating_key %s" % str(rating_key)) logger.error(u"PlexPy NotificationHandler :: Unable to retrieve metadata for rating_key %s" % str(rating_key))
return [] return []
# Check for exclusion tags # Check for exclusion tags
@ -547,15 +554,16 @@ def build_notify_text(session=None, timeline=None, state=None):
'transcode_audio_codec': transcode_audio_codec, 'transcode_audio_codec': transcode_audio_codec,
'transcode_audio_channels': transcode_audio_channels, 'transcode_audio_channels': transcode_audio_channels,
'title': full_title, 'title': full_title,
'library_name': metadata['library_name'],
'show_name': show_name, 'show_name': show_name,
'episode_name': episode_name, 'episode_name': episode_name,
'artist_name': artist_name, 'artist_name': artist_name,
'album_name': album_name, 'album_name': album_name,
'track_name': track_name, 'track_name': track_name,
'season_num': metadata['parent_index'].zfill(1), 'season_num': metadata['parent_media_index'].zfill(1),
'season_num00': metadata['parent_index'].zfill(2), 'season_num00': metadata['parent_media_index'].zfill(2),
'episode_num': metadata['index'].zfill(1), 'episode_num': metadata['media_index'].zfill(1),
'episode_num00': metadata['index'].zfill(2), 'episode_num00': metadata['media_index'].zfill(2),
'year': metadata['year'], 'year': metadata['year'],
'studio': metadata['studio'], 'studio': metadata['studio'],
'content_rating': metadata['content_rating'], 'content_rating': metadata['content_rating'],
@ -597,16 +605,16 @@ def build_notify_text(session=None, timeline=None, state=None):
try: try:
subject_text = unicode(on_start_subject).format(**available_params) subject_text = unicode(on_start_subject).format(**available_params)
except LookupError, e: except LookupError, e:
logger.error(u"PlexPy Notifier :: Unable to parse field %s in notification subject. Using fallback." % e) logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification subject. Using fallback." % e)
except: except:
logger.error(u"PlexPy Notifier :: Unable to parse custom notification subject. Using fallback.") logger.error(u"PlexPy NotificationHandler :: Unable to parse custom notification subject. Using fallback.")
try: try:
body_text = unicode(on_start_body).format(**available_params) body_text = unicode(on_start_body).format(**available_params)
except LookupError, e: except LookupError, e:
logger.error(u"PlexPy Notifier :: Unable to parse field %s in notification body. Using fallback." % e) logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification body. Using fallback." % e)
except: except:
logger.error(u"PlexPy Notifier :: Unable to parse custom notification body. Using fallback.") logger.error(u"PlexPy NotificationHandler :: Unable to parse custom notification body. Using fallback.")
return [subject_text, body_text, script_args] return [subject_text, body_text, script_args]
else: else:
@ -621,16 +629,16 @@ def build_notify_text(session=None, timeline=None, state=None):
try: try:
subject_text = unicode(on_stop_subject).format(**available_params) subject_text = unicode(on_stop_subject).format(**available_params)
except LookupError, e: except LookupError, e:
logger.error(u"PlexPy Notifier :: Unable to parse field %s in notification subject. Using fallback." % e) logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification subject. Using fallback." % e)
except: except:
logger.error(u"PlexPy Notifier :: Unable to parse custom notification subject. Using fallback.") logger.error(u"PlexPy NotificationHandler :: Unable to parse custom notification subject. Using fallback.")
try: try:
body_text = unicode(on_stop_body).format(**available_params) body_text = unicode(on_stop_body).format(**available_params)
except LookupError, e: except LookupError, e:
logger.error(u"PlexPy Notifier :: Unable to parse field %s in notification body. Using fallback." % e) logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification body. Using fallback." % e)
except: except:
logger.error(u"PlexPy Notifier :: Unable to parse custom notification body. Using fallback.") logger.error(u"PlexPy NotificationHandler :: Unable to parse custom notification body. Using fallback.")
return [subject_text, body_text, script_args] return [subject_text, body_text, script_args]
else: else:
@ -645,16 +653,16 @@ def build_notify_text(session=None, timeline=None, state=None):
try: try:
subject_text = unicode(on_pause_subject).format(**available_params) subject_text = unicode(on_pause_subject).format(**available_params)
except LookupError, e: except LookupError, e:
logger.error(u"PlexPy Notifier :: Unable to parse field %s in notification subject. Using fallback." % e) logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification subject. Using fallback." % e)
except: except:
logger.error(u"PlexPy Notifier :: Unable to parse custom notification subject. Using fallback.") logger.error(u"PlexPy NotificationHandler :: Unable to parse custom notification subject. Using fallback.")
try: try:
body_text = unicode(on_pause_body).format(**available_params) body_text = unicode(on_pause_body).format(**available_params)
except LookupError, e: except LookupError, e:
logger.error(u"PlexPy Notifier :: Unable to parse field %s in notification body. Using fallback." % e) logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification body. Using fallback." % e)
except: except:
logger.error(u"PlexPy Notifier :: Unable to parse custom notification body. Using fallback.") logger.error(u"PlexPy NotificationHandler :: Unable to parse custom notification body. Using fallback.")
return [subject_text, body_text, script_args] return [subject_text, body_text, script_args]
else: else:
@ -669,16 +677,16 @@ def build_notify_text(session=None, timeline=None, state=None):
try: try:
subject_text = unicode(on_resume_subject).format(**available_params) subject_text = unicode(on_resume_subject).format(**available_params)
except LookupError, e: except LookupError, e:
logger.error(u"PlexPy Notifier :: Unable to parse field %s in notification subject. Using fallback." % e) logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification subject. Using fallback." % e)
except: except:
logger.error(u"PlexPy Notifier :: Unable to parse custom notification subject. Using fallback.") logger.error(u"PlexPy NotificationHandler :: Unable to parse custom notification subject. Using fallback.")
try: try:
body_text = unicode(on_resume_body).format(**available_params) body_text = unicode(on_resume_body).format(**available_params)
except LookupError, e: except LookupError, e:
logger.error(u"PlexPy Notifier :: Unable to parse field %s in notification body. Using fallback." % e) logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification body. Using fallback." % e)
except: except:
logger.error(u"PlexPy Notifier :: Unable to parse custom notification body. Using fallback.") logger.error(u"PlexPy NotificationHandler :: Unable to parse custom notification body. Using fallback.")
return [subject_text, body_text, script_args] return [subject_text, body_text, script_args]
else: else:
@ -693,16 +701,16 @@ def build_notify_text(session=None, timeline=None, state=None):
try: try:
subject_text = unicode(on_buffer_subject).format(**available_params) subject_text = unicode(on_buffer_subject).format(**available_params)
except LookupError, e: except LookupError, e:
logger.error(u"PlexPy Notifier :: Unable to parse field %s in notification subject. Using fallback." % e) logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification subject. Using fallback." % e)
except: except:
logger.error(u"PlexPy Notifier :: Unable to parse custom notification subject. Using fallback.") logger.error(u"PlexPy NotificationHandler :: Unable to parse custom notification subject. Using fallback.")
try: try:
body_text = unicode(on_buffer_body).format(**available_params) body_text = unicode(on_buffer_body).format(**available_params)
except LookupError, e: except LookupError, e:
logger.error(u"PlexPy Notifier :: Unable to parse field %s in notification body. Using fallback." % e) logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification body. Using fallback." % e)
except: except:
logger.error(u"PlexPy Notifier :: Unable to parse custom notification body. Using fallback.") logger.error(u"PlexPy NotificationHandler :: Unable to parse custom notification body. Using fallback.")
return [subject_text, body_text, script_args] return [subject_text, body_text, script_args]
else: else:
@ -717,16 +725,16 @@ def build_notify_text(session=None, timeline=None, state=None):
try: try:
subject_text = unicode(on_watched_subject).format(**available_params) subject_text = unicode(on_watched_subject).format(**available_params)
except LookupError, e: except LookupError, e:
logger.error(u"PlexPy Notifier :: Unable to parse field %s in notification subject. Using fallback." % e) logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification subject. Using fallback." % e)
except: except:
logger.error(u"PlexPy Notifier :: Unable to parse custom notification subject. Using fallback.") logger.error(u"PlexPy NotificationHandler :: Unable to parse custom notification subject. Using fallback.")
try: try:
body_text = unicode(on_watched_body).format(**available_params) body_text = unicode(on_watched_body).format(**available_params)
except LookupError, e: except LookupError, e:
logger.error(u"PlexPy Notifier :: Unable to parse field %s in notification body. Using fallback." % e) logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification body. Using fallback." % e)
except: except:
logger.error(u"PlexPy Notifier :: Unable to parse custom notification body. Using fallback.") logger.error(u"PlexPy NotificationHandler :: Unable to parse custom notification body. Using fallback.")
return [subject_text, body_text, script_args] return [subject_text, body_text, script_args]
else: else:
@ -739,16 +747,16 @@ def build_notify_text(session=None, timeline=None, state=None):
try: try:
subject_text = unicode(on_created_subject).format(**available_params) subject_text = unicode(on_created_subject).format(**available_params)
except LookupError, e: except LookupError, e:
logger.error(u"PlexPy Notifier :: Unable to parse field %s in notification subject. Using fallback." % e) logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification subject. Using fallback." % e)
except: except:
logger.error(u"PlexPy Notifier :: Unable to parse custom notification subject. Using fallback.") logger.error(u"PlexPy NotificationHandler :: Unable to parse custom notification subject. Using fallback.")
try: try:
body_text = unicode(on_created_body).format(**available_params) body_text = unicode(on_created_body).format(**available_params)
except LookupError, e: except LookupError, e:
logger.error(u"PlexPy Notifier :: Unable to parse field %s in notification body. Using fallback." % e) logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification body. Using fallback." % e)
except: except:
logger.error(u"PlexPy Notifier :: Unable to parse custom notification body. Using fallback.") logger.error(u"PlexPy NotificationHandler :: Unable to parse custom notification body. Using fallback.")
return [subject_text, body_text, script_args] return [subject_text, body_text, script_args]
else: else:
@ -769,7 +777,7 @@ def build_server_notify_text(state=None):
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_float(updated_at))) server_uptime = helpers.human_duration(int(time.time() - helpers.cast_to_float(updated_at)))
else: else:
logger.error(u"PlexPy Notifier :: Unable to retrieve server uptime.") logger.error(u"PlexPy NotificationHandler :: Unable to retrieve server uptime.")
server_uptime = 'N/A' server_uptime = 'N/A'
on_extdown_subject = plexpy.CONFIG.NOTIFY_ON_EXTDOWN_SUBJECT_TEXT on_extdown_subject = plexpy.CONFIG.NOTIFY_ON_EXTDOWN_SUBJECT_TEXT
@ -812,14 +820,14 @@ def build_server_notify_text(state=None):
try: try:
subject_text = unicode(on_extdown_subject).format(**available_params) subject_text = unicode(on_extdown_subject).format(**available_params)
except LookupError, e: except LookupError, e:
logger.error(u"PlexPy Notifier :: Unable to parse field %s in notification subject. Using fallback." % e) logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification subject. Using fallback." % e)
except: except:
logger.error(u"PlexPy Notifier :: Unable to parse custom notification subject. Using fallback.") logger.error(u"PlexPy NotificationHandler :: Unable to parse custom notification subject. Using fallback.")
try: try:
body_text = unicode(on_extdown_body).format(**available_params) body_text = unicode(on_extdown_body).format(**available_params)
except LookupError, e: except LookupError, e:
logger.error(u"PlexPy Notifier :: Unable to parse field %s in notification body. Using fallback." % e) logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification body. Using fallback." % e)
except: except:
logger.error(u"PlexPy Notifier :: Unable to parse custom notification body. Using fallback.") logger.error(u"PlexPy Notifier :: Unable to parse custom notification body. Using fallback.")
@ -835,16 +843,16 @@ def build_server_notify_text(state=None):
try: try:
subject_text = unicode(on_intdown_subject).format(**available_params) subject_text = unicode(on_intdown_subject).format(**available_params)
except LookupError, e: except LookupError, e:
logger.error(u"PlexPy Notifier :: Unable to parse field %s in notification subject. Using fallback." % e) logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification subject. Using fallback." % e)
except: except:
logger.error(u"PlexPy Notifier :: Unable to parse custom notification subject. Using fallback.") logger.error(u"PlexPy NotificationHandler :: Unable to parse custom notification subject. Using fallback.")
try: try:
body_text = unicode(on_intdown_body).format(**available_params) body_text = unicode(on_intdown_body).format(**available_params)
except LookupError, e: except LookupError, e:
logger.error(u"PlexPy Notifier :: Unable to parse field %s in notification body. Using fallback." % e) logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification body. Using fallback." % e)
except: except:
logger.error(u"PlexPy Notifier :: Unable to parse custom notification body. Using fallback.") logger.error(u"PlexPy NotificationHandler :: Unable to parse custom notification body. Using fallback.")
return [subject_text, body_text, script_args] return [subject_text, body_text, script_args]
else: else:
@ -857,16 +865,16 @@ def build_server_notify_text(state=None):
try: try:
subject_text = unicode(on_extup_subject).format(**available_params) subject_text = unicode(on_extup_subject).format(**available_params)
except LookupError, e: except LookupError, e:
logger.error(u"PlexPy Notifier :: Unable to parse field %s in notification subject. Using fallback." % e) logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification subject. Using fallback." % e)
except: except:
logger.error(u"PlexPy Notifier :: Unable to parse custom notification subject. Using fallback.") logger.error(u"PlexPy NotificationHandler :: Unable to parse custom notification subject. Using fallback.")
try: try:
body_text = unicode(on_extup_body).format(**available_params) body_text = unicode(on_extup_body).format(**available_params)
except LookupError, e: except LookupError, e:
logger.error(u"PlexPy Notifier :: Unable to parse field %s in notification body. Using fallback." % e) logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification body. Using fallback." % e)
except: except:
logger.error(u"PlexPy Notifier :: Unable to parse custom notification body. Using fallback.") logger.error(u"PlexPy NotificationHandler :: Unable to parse custom notification body. Using fallback.")
return [subject_text, body_text, script_args] return [subject_text, body_text, script_args]
else: else:
@ -879,16 +887,16 @@ def build_server_notify_text(state=None):
try: try:
subject_text = unicode(on_intup_subject).format(**available_params) subject_text = unicode(on_intup_subject).format(**available_params)
except LookupError, e: except LookupError, e:
logger.error(u"PlexPy Notifier :: Unable to parse field %s in notification subject. Using fallback." % e) logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification subject. Using fallback." % e)
except: except:
logger.error(u"PlexPy Notifier :: Unable to parse custom notification subject. Using fallback.") logger.error(u"PlexPy NotificationHandler :: Unable to parse custom notification subject. Using fallback.")
try: try:
body_text = unicode(on_intup_body).format(**available_params) body_text = unicode(on_intup_body).format(**available_params)
except LookupError, e: except LookupError, e:
logger.error(u"PlexPy Notifier :: Unable to parse field %s in notification body. Using fallback." % e) logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification body. Using fallback." % e)
except: except:
logger.error(u"PlexPy Notifier :: Unable to parse custom notification body. Using fallback.") logger.error(u"PlexPy NotificationHandler :: Unable to parse custom notification body. Using fallback.")
return [subject_text, body_text, script_args] return [subject_text, body_text, script_args]
else: else:
@ -899,7 +907,5 @@ def build_server_notify_text(state=None):
def strip_tag(data): def strip_tag(data):
import re
p = re.compile(r'<.*?>') p = re.compile(r'<.*?>')
return p.sub('', data) return p.sub('', data)

View file

@ -525,10 +525,10 @@ class GROWL(object):
try: try:
growl.register() growl.register()
except gntp.notifier.errors.NetworkError: except gntp.notifier.errors.NetworkError:
logger.warning(u'Growl notification failed: network error') logger.warn(u"PlexPy Notifier :: Growl notification failed: network error")
return return
except gntp.notifier.errors.AuthError: except gntp.notifier.errors.AuthError:
logger.warning(u'Growl notification failed: authentication error') logger.warn(u"PlexPy Notifier :: Growl notification failed: authentication error")
return return
# Fix message # Fix message
@ -548,11 +548,11 @@ class GROWL(object):
description=message, description=message,
icon=image icon=image
) )
logger.info(u"PlexPy Notifier :: Growl notification sent.")
except gntp.notifier.errors.NetworkError: except gntp.notifier.errors.NetworkError:
logger.warning(u'Growl notification failed: network error') logger.warn(u"PlexPy Notifier :: Growl notification failed: network error")
return return
logger.info(u"Growl notifications sent.")
def updateLibrary(self): def updateLibrary(self):
# For uniformity reasons not removed # For uniformity reasons not removed
@ -617,13 +617,13 @@ class PROWL(object):
request_status = response.status request_status = response.status
if request_status == 200: if request_status == 200:
logger.info(u"Prowl notifications sent.") logger.info(u"PlexPy Notifier :: Prowl notification sent.")
return True return True
elif request_status == 401: elif request_status == 401:
logger.info(u"Prowl auth failed: %s" % response.reason) logger.warn(u"PlexPy Notifier :: Prowl notification failed: %s" % response.reason)
return False return False
else: else:
logger.info(u"Prowl notification failed.") logger.warn(u"PlexPy Notifier :: Prowl notification failed.")
return False return False
def updateLibrary(self): def updateLibrary(self):
@ -698,7 +698,7 @@ class XBMC(object):
time = "3000" # in ms time = "3000" # in ms
for host in hosts: for host in hosts:
logger.info('Sending notification command to XMBC @ ' + host) logger.info(u"PlexPy Notifier :: Sending notification command to XMBC @ " + host)
try: try:
version = self._sendjson(host, 'Application.GetProperties', {'properties': ['version']})['version']['major'] version = self._sendjson(host, 'Application.GetProperties', {'properties': ['version']})['version']['major']
@ -713,15 +713,17 @@ class XBMC(object):
if not request: if not request:
raise Exception raise Exception
else:
logger.info(u"PlexPy Notifier :: XBMC notification sent.")
except Exception: except Exception:
logger.error('Error sending notification request to XBMC') logger.warn(u"PlexPy Notifier :: XBMC notification filed.")
def return_config_options(self): def return_config_options(self):
config_option = [{'label': 'XBMC Host:Port', config_option = [{'label': 'XBMC Host:Port',
'value': self.hosts, 'value': self.hosts,
'name': 'xbmc_host', 'name': 'xbmc_host',
'description': 'Host running XBMC (e.g. http://localhost:8080). Separate multiple hosts with commas.', 'description': 'Host running XBMC (e.g. http://localhost:8080). Separate multiple hosts with commas (,).',
'input_type': 'text' 'input_type': 'text'
}, },
{'label': 'XBMC Username', {'label': 'XBMC Username',
@ -763,12 +765,12 @@ class Plex(object):
base64string = base64.encodestring('%s:%s' % (username, password)).replace('\n', '') base64string = base64.encodestring('%s:%s' % (username, password)).replace('\n', '')
req.add_header("Authorization", "Basic %s" % base64string) req.add_header("Authorization", "Basic %s" % base64string)
logger.info('Plex url: %s' % url) # logger.info(u"PlexPy Notifier :: Plex url: %s" % url)
try: try:
handle = urllib2.urlopen(req) handle = urllib2.urlopen(req)
except Exception as e: except Exception as e:
logger.warn('Error opening Plex url: %s' % e) logger.error(u"PlexPy Notifier :: Error opening Plex url: %s" % e)
return return
response = handle.read().decode(plexpy.SYS_ENCODING) response = handle.read().decode(plexpy.SYS_ENCODING)
@ -784,7 +786,7 @@ class Plex(object):
time = "3000" # in ms time = "3000" # in ms
for host in hosts: for host in hosts:
logger.info('Sending notification command to Plex Media Server @ ' + host) logger.info(u"PlexPy Notifier :: Sending notification command to Plex Media Server @ " + host)
try: try:
notification = header + "," + message + "," + time notification = header + "," + message + "," + time
notifycommand = {'command': 'ExecBuiltIn', 'parameter': 'Notification(' + notification + ')'} notifycommand = {'command': 'ExecBuiltIn', 'parameter': 'Notification(' + notification + ')'}
@ -792,9 +794,11 @@ class Plex(object):
if not request: if not request:
raise Exception raise Exception
else:
logger.info(u"PlexPy Notifier :: Plex notification sent.")
except: except:
logger.warn('Error sending notification request to Plex Media Server') logger.warn(u"PlexPy Notifier :: Plex notification failed.")
def return_config_options(self): def return_config_options(self):
config_option = [{'label': 'Plex Client Host:Port', config_option = [{'label': 'Plex Client Host:Port',
@ -855,9 +859,10 @@ class NMA(object):
response = p.push(title, event, message, priority=nma_priority, batch_mode=batch) response = p.push(title, event, message, priority=nma_priority, batch_mode=batch)
if not response[api][u'code'] == u'200': if not response[api][u'code'] == u'200':
logger.error(u'Could not send notification to NotifyMyAndroid') logger.warn(u"PlexPy Notifier :: NotifyMyAndroid notification failed.")
return False return False
else: else:
logger.info(u"PlexPy Notifier :: NotifyMyAndroid notification sent.")
return True return True
def return_config_options(self): def return_config_options(self):
@ -918,13 +923,13 @@ class PUSHBULLET(object):
# logger.debug(u"PushBullet response body: %r" % response.read()) # logger.debug(u"PushBullet response body: %r" % response.read())
if request_status == 200: if request_status == 200:
logger.info(u"PushBullet notifications sent.") logger.info(u"PlexPy Notifier :: PushBullet notification sent.")
return True return True
elif request_status >= 400 and request_status < 500: elif request_status >= 400 and request_status < 500:
logger.info(u"PushBullet request failed: %s" % response.reason) logger.warn(u"PlexPy Notifier :: PushBullet notification failed: %s" % response.reason)
return False return False
else: else:
logger.info(u"PushBullet notification failed serverside.") logger.warn(u"PlexPy Notifier :: PushBullet notification failed.")
return False return False
def test(self, apikey, deviceid): def test(self, apikey, deviceid):
@ -952,10 +957,10 @@ class PUSHBULLET(object):
devices.update({'': ''}) devices.update({'': ''})
return devices return devices
elif request_status >= 400 and request_status < 500: elif request_status >= 400 and request_status < 500:
logger.info(u"Unable to retrieve Pushbullet devices list: %s" % response.reason) logger.warn(u"PlexPy Notifier :: Unable to retrieve Pushbullet devices list: %s" % response.reason)
return {'': ''} return {'': ''}
else: else:
logger.info(u"Unable to retrieve Pushbullet devices list.") logger.warn(u"PlexPy Notifier :: Unable to retrieve Pushbullet devices list.")
return {'': ''} return {'': ''}
else: else:
@ -1020,13 +1025,13 @@ class PUSHALOT(object):
# logger.debug(u"Pushalot response body: %r" % response.read()) # logger.debug(u"Pushalot response body: %r" % response.read())
if request_status == 200: if request_status == 200:
logger.info(u"Pushalot notifications sent.") logger.info(u"PlexPy Notifier :: Pushalot notification sent.")
return True return True
elif request_status == 410: elif request_status == 410:
logger.info(u"Pushalot auth failed: %s" % response.reason) logger.warn(u"PlexPy Notifier :: Pushalot notification failed: %s" % response.reason)
return False return False
else: else:
logger.info(u"Pushalot notification failed.") logger.warn(u"PlexPy Notifier :: Pushalot notification failed.")
return False return False
def return_config_options(self): def return_config_options(self):
@ -1077,13 +1082,13 @@ class PUSHOVER(object):
# logger.debug(u"Pushover response body: %r" % response.read()) # logger.debug(u"Pushover response body: %r" % response.read())
if request_status == 200: if request_status == 200:
logger.info(u"Pushover notifications sent.") logger.info(u"PlexPy Notifier :: Pushover notification sent.")
return True return True
elif request_status >= 400 and request_status < 500: elif request_status >= 400 and request_status < 500:
logger.info(u"Pushover request failed: %s" % response.reason) logger.warn(u"PlexPy Notifier :: Pushover notification failed: %s" % response.reason)
return False return False
else: else:
logger.info(u"Pushover notification failed.") logger.warn(u"PlexPy Notifier :: Pushover notification failed.")
return False return False
def updateLibrary(self): def updateLibrary(self):
@ -1111,10 +1116,10 @@ class PUSHOVER(object):
sounds.update({'': ''}) sounds.update({'': ''})
return sounds return sounds
elif request_status >= 400 and request_status < 500: elif request_status >= 400 and request_status < 500:
logger.info(u"Unable to retrieve Pushover notification sounds list: %s" % response.reason) logger.warn(u"PlexPy Notifier :: Unable to retrieve Pushover notification sounds list: %s" % response.reason)
return {'': ''} return {'': ''}
else: else:
logger.info(u"Unable to retrieve Pushover notification sounds list.") logger.warn(u"PlexPy Notifier :: Unable to retrieve Pushover notification sounds list.")
return {'': ''} return {'': ''}
else: else:
@ -1177,12 +1182,12 @@ class TwitterNotifier(object):
oauth_consumer = oauth.Consumer(key=self.consumer_key, secret=self.consumer_secret) oauth_consumer = oauth.Consumer(key=self.consumer_key, secret=self.consumer_secret)
oauth_client = oauth.Client(oauth_consumer) oauth_client = oauth.Client(oauth_consumer)
logger.info('Requesting temp token from Twitter') logger.info("PlexPy Notifier :: Requesting temp token from Twitter")
resp, content = oauth_client.request(self.REQUEST_TOKEN_URL, 'GET') resp, content = oauth_client.request(self.REQUEST_TOKEN_URL, 'GET')
if resp['status'] != '200': if resp['status'] != '200':
logger.info('Invalid respond from Twitter requesting temp token: %s' % resp['status']) logger.warn("PlexPy Notifier :: Invalid respond from Twitter requesting temp token: %s" % resp['status'])
else: else:
request_token = dict(parse_qsl(content)) request_token = dict(parse_qsl(content))
@ -1201,25 +1206,25 @@ class TwitterNotifier(object):
token = oauth.Token(request_token['oauth_token'], request_token['oauth_token_secret']) token = oauth.Token(request_token['oauth_token'], request_token['oauth_token_secret'])
token.set_verifier(key) token.set_verifier(key)
logger.info('Generating and signing request for an access token using key ' + key) # logger.debug(u"Generating and signing request for an access token using key " + key)
oauth_consumer = oauth.Consumer(key=self.consumer_key, secret=self.consumer_secret) oauth_consumer = oauth.Consumer(key=self.consumer_key, secret=self.consumer_secret)
# logger.debug('oauth_consumer: ' + str(oauth_consumer)) # logger.debug(u"oauth_consumer: " + str(oauth_consumer))
oauth_client = oauth.Client(oauth_consumer, token) oauth_client = oauth.Client(oauth_consumer, token)
# logger.info('oauth_client: ' + str(oauth_client)) # logger.debug(u"oauth_client: " + str(oauth_client))
resp, content = oauth_client.request(self.ACCESS_TOKEN_URL, method='POST', body='oauth_verifier=%s' % key) resp, content = oauth_client.request(self.ACCESS_TOKEN_URL, method='POST', body='oauth_verifier=%s' % key)
# logger.info('resp, content: ' + str(resp) + ',' + str(content)) # logger.debug(u"resp, content: " + str(resp) + ',' + str(content))
access_token = dict(parse_qsl(content)) access_token = dict(parse_qsl(content))
# logger.info('access_token: ' + str(access_token)) # logger.debug(u"access_token: " + str(access_token))
# logger.info('resp[status] = ' + str(resp['status'])) # logger.debug(u"resp[status] = " + str(resp['status']))
if resp['status'] != '200': if resp['status'] != '200':
logger.info('The request for a token with did not succeed: ' + str(resp['status']), logger.ERROR) logger.error(u"PlexPy Notifier :: The request for a Twitter token did not succeed: " + str(resp['status']), logger.ERROR)
return False return False
else: else:
logger.info('Your Twitter Access Token key: %s' % access_token['oauth_token']) # logger.info(u"PlexPy Notifier :: Your Twitter Access Token key: %s" % access_token['oauth_token'])
logger.info('Access Token secret: %s' % access_token['oauth_token_secret']) # logger.info(u"PlexPy Notifier :: Access Token secret: %s" % access_token['oauth_token_secret'])
plexpy.CONFIG.TWITTER_USERNAME = access_token['oauth_token'] plexpy.CONFIG.TWITTER_USERNAME = access_token['oauth_token']
plexpy.CONFIG.TWITTER_PASSWORD = access_token['oauth_token_secret'] plexpy.CONFIG.TWITTER_PASSWORD = access_token['oauth_token_secret']
plexpy.CONFIG.write() plexpy.CONFIG.write()
@ -1231,15 +1236,15 @@ class TwitterNotifier(object):
access_token_key = plexpy.CONFIG.TWITTER_USERNAME access_token_key = plexpy.CONFIG.TWITTER_USERNAME
access_token_secret = plexpy.CONFIG.TWITTER_PASSWORD access_token_secret = plexpy.CONFIG.TWITTER_PASSWORD
# logger.info(u"Sending tweet: " + message) # logger.info(u"PlexPy Notifier :: Sending tweet: " + message)
api = twitter.Api(username, password, access_token_key, access_token_secret) api = twitter.Api(username, password, access_token_key, access_token_secret)
try: try:
api.PostUpdate(message) api.PostUpdate(message)
logger.info(u"Twitter notifications sent.") logger.info(u"PlexPy Notifier :: Twitter notification sent")
except Exception as e: except Exception as e:
logger.info(u"Error sending Tweet: %s" % e) logger.warn(u"PlexPy Notifier :: Twitter notification failed: %s" % e)
return False return False
return True return True
@ -1335,13 +1340,13 @@ class OSX_NOTIFY(object):
notification_center = NSUserNotificationCenter.defaultUserNotificationCenter() notification_center = NSUserNotificationCenter.defaultUserNotificationCenter()
notification_center.deliverNotification_(notification) notification_center.deliverNotification_(notification)
logger.info(u"OSX Notify notifications sent.") logger.info(u"PlexPy Notifier :: OSX Notify notification sent.")
del pool del pool
return True return True
except Exception as e: except Exception as e:
logger.warn('Error sending OS X Notification: %s' % e) logger.warn(u"PlexPy Notifier :: OSX notification failed: %s" % e)
return False return False
def swizzled_bundleIdentifier(self, original, swizzled): def swizzled_bundleIdentifier(self, original, swizzled):
@ -1382,26 +1387,15 @@ class BOXCAR(object):
req = urllib2.Request(self.url) req = urllib2.Request(self.url)
handle = urllib2.urlopen(req, data) handle = urllib2.urlopen(req, data)
handle.close() handle.close()
logger.info(u"Boxcar2 notifications sent.") logger.info(u"PlexPy Notifier :: Boxcar2 notification sent.")
return True return True
except urllib2.URLError as e: except urllib2.URLError as e:
logger.warn('Error sending Boxcar2 Notification: %s' % e) logger.warn(u"PlexPy Notifier :: Boxcar2 notification failed: %s" % e)
return False return False
def return_config_options(self): def get_sounds(self):
config_option = [{'label': 'Boxcar Access Token', sounds = {'': '',
'value': plexpy.CONFIG.BOXCAR_TOKEN,
'name': 'boxcar_token',
'description': 'Your Boxcar access token.',
'input_type': 'text'
},
{'label': 'Sound',
'value': self.sound,
'name': 'boxcar_sound',
'description': 'Set the notification sound. Leave blank for the default sound.',
'input_type': 'select',
'select_options': {'': '',
'beep-crisp': 'Beep (Crisp)', 'beep-crisp': 'Beep (Crisp)',
'beep-soft': 'Beep (Soft)', 'beep-soft': 'Beep (Soft)',
'bell-modern': 'Bell (Modern)', 'bell-modern': 'Bell (Modern)',
@ -1420,7 +1414,7 @@ class BOXCAR(object):
'flourish': 'Flourish', 'flourish': 'Flourish',
'harp': 'Harp', 'harp': 'Harp',
'light': 'Light', 'light': 'Light',
'magic-chime': 'Magic Chime', 'magic-chime':'Magic Chime',
'magic-coin': 'Magic Coin', 'magic-coin': 'Magic Coin',
'no-sound': 'No Sound', 'no-sound': 'No Sound',
'notifier-1': 'Notifier (1)', 'notifier-1': 'Notifier (1)',
@ -1431,6 +1425,22 @@ class BOXCAR(object):
'score': 'Score', 'score': 'Score',
'success': 'Success', 'success': 'Success',
'up': 'Up'} 'up': 'Up'}
return sounds
def return_config_options(self):
config_option = [{'label': 'Boxcar Access Token',
'value': plexpy.CONFIG.BOXCAR_TOKEN,
'name': 'boxcar_token',
'description': 'Your Boxcar access token.',
'input_type': 'text'
},
{'label': 'Sound',
'value': self.sound,
'name': 'boxcar_sound',
'description': 'Set the notification sound. Leave blank for the default sound.',
'input_type': 'select',
'select_options': self.get_sounds()
} }
] ]
@ -1471,11 +1481,11 @@ class Email(object):
mailserver.sendmail(plexpy.CONFIG.EMAIL_FROM, recipients, message.as_string()) mailserver.sendmail(plexpy.CONFIG.EMAIL_FROM, recipients, message.as_string())
mailserver.quit() mailserver.quit()
logger.info(u"Email notifications sent.") logger.info(u"PlexPy Notifier :: Email notification sent.")
return True return True
except Exception, e: except Exception as e:
logger.warn('Error sending Email: %s' % e) logger.warn(u"PlexPy Notifier :: Email notification failed: %s" % e)
return False return False
def return_config_options(self): def return_config_options(self):
@ -1558,7 +1568,7 @@ class IFTTT(object):
data = {'value1': subject.encode("utf-8"), data = {'value1': subject.encode("utf-8"),
'value2': message.encode("utf-8")} 'value2': message.encode("utf-8")}
# logger.debug("Ifttt SENDING: %s" % json.dumps(data)) # logger.debug(u"Ifttt SENDING: %s" % json.dumps(data))
http_handler.request("POST", http_handler.request("POST",
"/trigger/%s/with/key/%s" % (self.event, self.apikey), "/trigger/%s/with/key/%s" % (self.event, self.apikey),
@ -1571,13 +1581,13 @@ class IFTTT(object):
# logger.debug(u"Ifttt response body: %r" % response.read()) # logger.debug(u"Ifttt response body: %r" % response.read())
if request_status == 200: if request_status == 200:
logger.info(u"Ifttt notifications sent.") logger.info(u"PlexPy Notifier :: Ifttt notification sent.")
return True return True
elif request_status >= 400 and request_status < 500: elif request_status >= 400 and request_status < 500:
logger.info(u"Ifttt request failed: %s" % response.reason) logger.warn(u"PlexPy Notifier :: Ifttt notification failed: %s" % response.reason)
return False return False
else: else:
logger.info(u"Ifttt notification failed serverside.") logger.warn(u"PlexPy Notifier :: Ifttt notification failed.")
return False return False
def test(self): def test(self):
@ -1631,13 +1641,13 @@ class TELEGRAM(object):
request_status = response.status request_status = response.status
if request_status == 200: if request_status == 200:
logger.info(u"Telegram notifications sent.") logger.info(u"PlexPy Notifier :: Telegram notification sent.")
return True return True
elif request_status >= 400 and request_status < 500: elif request_status >= 400 and request_status < 500:
logger.info(u"Telegram request failed: %s" % response.reason) logger.warn(u"PlexPy Notifier :: Telegram notification failed: %s" % response.reason)
return False return False
else: else:
logger.info(u"Telegram notification failed serverside.") logger.warn(u"PlexPy Notifier :: Telegram notification failed.")
return False return False
def updateLibrary(self): def updateLibrary(self):
@ -1708,13 +1718,13 @@ class SLACK(object):
request_status = response.status request_status = response.status
if request_status == 200: if request_status == 200:
logger.info(u"Slack notifications sent.") logger.info(u"PlexPy Notifier :: Slack notification sent.")
return True return True
elif request_status >= 400 and request_status < 500: elif request_status >= 400 and request_status < 500:
logger.info(u"Slack request failed: %s" % response.reason) logger.warn(u"PlexPy Notifier :: Slack notification failed: %s" % response.reason)
return False return False
else: else:
logger.info(u"Slack notification failed serverside.") logger.warn(u"PlexPy Notifier :: Slack notification failed.")
return False return False
def updateLibrary(self): def updateLibrary(self):

View file

@ -16,7 +16,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, helpers, users, http_handler, database from plexpy import logger, helpers, http_handler, database, users
import xmltodict import xmltodict
import json import json
from xml.dom import minidom from xml.dom import minidom
@ -26,7 +26,7 @@ import plexpy
def refresh_users(): def refresh_users():
logger.info("Requesting users list refresh...") logger.info(u"PlexPy PlexTV :: Requesting users list refresh...")
result = PlexTV().get_full_users_list() result = PlexTV().get_full_users_list()
monitor_db = database.MonitorDatabase() monitor_db = database.MonitorDatabase()
@ -55,13 +55,13 @@ def refresh_users():
monitor_db.upsert('users', new_value_dict, control_value_dict) monitor_db.upsert('users', new_value_dict, control_value_dict)
logger.info("Users list refreshed.") logger.info(u"PlexPy PlexTV :: Users list refreshed.")
else: else:
logger.warn("Unable to refresh users list.") logger.warn(u"PlexPy PlexTV :: Unable to refresh users list.")
def get_real_pms_url(): def get_real_pms_url():
logger.info("Requesting URLs for server...") logger.info(u"PlexPy PlexTV :: Requesting URLs for server...")
# Reset any current PMS_URL value # Reset any current PMS_URL value
plexpy.CONFIG.__setattr__('PMS_URL', '') plexpy.CONFIG.__setattr__('PMS_URL', '')
@ -85,15 +85,15 @@ def get_real_pms_url():
if plexpy.CONFIG.PMS_IS_REMOTE and item['local'] == '0': if plexpy.CONFIG.PMS_IS_REMOTE and item['local'] == '0':
plexpy.CONFIG.__setattr__('PMS_URL', item['uri']) plexpy.CONFIG.__setattr__('PMS_URL', item['uri'])
plexpy.CONFIG.write() plexpy.CONFIG.write()
logger.info("Server URL retrieved.") logger.info(u"PlexPy PlexTV :: Server URL retrieved.")
if not plexpy.CONFIG.PMS_IS_REMOTE and item['local'] == '1': if not plexpy.CONFIG.PMS_IS_REMOTE and item['local'] == '1':
plexpy.CONFIG.__setattr__('PMS_URL', item['uri']) plexpy.CONFIG.__setattr__('PMS_URL', item['uri'])
plexpy.CONFIG.write() plexpy.CONFIG.write()
logger.info("Server URL retrieved.") logger.info(u"PlexPy PlexTV :: Server URL retrieved.")
else: else:
plexpy.CONFIG.__setattr__('PMS_URL', fallback_url) plexpy.CONFIG.__setattr__('PMS_URL', fallback_url)
plexpy.CONFIG.write() plexpy.CONFIG.write()
logger.warn("Unable to retrieve server URLs. Using user-defined value.") logger.warn(u"PlexPy PlexTV :: Unable to retrieve server URLs. Using user-defined value.")
else: else:
plexpy.CONFIG.__setattr__('PMS_URL', fallback_url) plexpy.CONFIG.__setattr__('PMS_URL', fallback_url)
plexpy.CONFIG.write() plexpy.CONFIG.write()
@ -213,7 +213,7 @@ class PlexTV(object):
try: try:
xml_parse = minidom.parseString(own_account) xml_parse = minidom.parseString(own_account)
except Exception, e: except Exception as e:
logger.warn("Error parsing XML for Plex account details: %s" % e) logger.warn("Error parsing XML for Plex account details: %s" % e)
return [] return []
except: except:
@ -238,7 +238,7 @@ class PlexTV(object):
try: try:
xml_parse = minidom.parseString(friends_list) xml_parse = minidom.parseString(friends_list)
except Exception, e: except Exception as e:
logger.warn("Error parsing XML for Plex friends list: %s" % e) logger.warn("Error parsing XML for Plex friends list: %s" % e)
except: except:
logger.warn("Error parsing XML for Plex friends list.") logger.warn("Error parsing XML for Plex friends list.")
@ -269,7 +269,7 @@ class PlexTV(object):
try: try:
xml_parse = minidom.parseString(sync_list) xml_parse = minidom.parseString(sync_list)
except Exception, e: except Exception as e:
logger.warn("Error parsing XML for Plex sync lists: %s" % e) logger.warn("Error parsing XML for Plex sync lists: %s" % e)
return [] return []
except: except:
@ -383,7 +383,7 @@ class PlexTV(object):
try: try:
xml_parse = minidom.parseString(plextv_resources) xml_parse = minidom.parseString(plextv_resources)
except Exception, e: except Exception as e:
logger.warn("Error parsing XML for Plex resources: %s" % e) logger.warn("Error parsing XML for Plex resources: %s" % e)
return [] return []
except: except:
@ -430,6 +430,25 @@ class PlexTV(object):
return server_urls return server_urls
def get_server_times(self):
servers = self.get_plextv_server_list(output_format='xml')
server_times = []
try:
xml_head = servers.getElementsByTagName('Server')
except:
logger.warn("Error parsing XML for Plex servers.")
return []
for a in xml_head:
if helpers.get_xml_attr(a, 'machineIdentifier') == plexpy.CONFIG.PMS_IDENTIFIER:
server_times.append({"created_at": helpers.get_xml_attr(a, 'createdAt'),
"updated_at": helpers.get_xml_attr(a, 'updatedAt')
})
break
return server_times
def discover(self): def discover(self):
""" Query plex for all servers online. Returns the ones you own in a selectize format """ """ Query plex for all servers online. Returns the ones you own in a selectize format """
result = self.get_plextv_resources(include_https=True, output_format='raw') result = self.get_plextv_resources(include_https=True, output_format='raw')
@ -464,22 +483,3 @@ class PlexTV(object):
return clean_servers return clean_servers
return json.dumps(clean_servers, indent=4) return json.dumps(clean_servers, indent=4)
def get_server_times(self):
servers = self.get_plextv_server_list(output_format='xml')
server_times = []
try:
xml_head = servers.getElementsByTagName('Server')
except:
logger.warn("Error parsing XML for Plex servers.")
return []
for a in xml_head:
if helpers.get_xml_attr(a, 'machineIdentifier') == plexpy.CONFIG.PMS_IDENTIFIER:
server_times.append({"created_at": helpers.get_xml_attr(a, 'createdAt'),
"updated_at": helpers.get_xml_attr(a, 'updatedAt')
})
break
return server_times

View file

@ -26,12 +26,12 @@ def extract_plexwatch_xml(xml=None):
try: try:
xml_parse = minidom.parseString(clean_xml) xml_parse = minidom.parseString(clean_xml)
except: except:
logger.warn("Error parsing XML for Plexwatch database.") logger.warn(u"PlexPy Importer :: Error parsing XML for Plexwatch database.")
return None return None
xml_head = xml_parse.getElementsByTagName('opt') xml_head = xml_parse.getElementsByTagName('opt')
if not xml_head: if not xml_head:
logger.warn("Error parsing XML for Plexwatch database.") logger.warn(u"PlexPy Importer :: Error parsing XML for Plexwatch database.")
return None return None
for a in xml_head: for a in xml_head:
@ -205,23 +205,23 @@ def validate_database(database=None, table_name=None):
try: try:
connection = sqlite3.connect(database, timeout=20) connection = sqlite3.connect(database, timeout=20)
except sqlite3.OperationalError: except sqlite3.OperationalError:
logger.error('PlexPy Importer :: Invalid database specified.') logger.error(u"PlexPy Importer :: Invalid database specified.")
return 'Invalid database specified.' return 'Invalid database specified.'
except ValueError: except ValueError:
logger.error('PlexPy Importer :: Invalid database specified.') logger.error(u"PlexPy Importer :: Invalid database specified.")
return 'Invalid database specified.' return 'Invalid database specified.'
except: except:
logger.error('PlexPy Importer :: Uncaught exception.') logger.error(u"PlexPy Importer :: Uncaught exception.")
return 'Uncaught exception.' return 'Uncaught exception.'
try: try:
connection.execute('SELECT ratingKey from %s' % table_name) connection.execute('SELECT ratingKey from %s' % table_name)
connection.close() connection.close()
except sqlite3.OperationalError: except sqlite3.OperationalError:
logger.error('PlexPy Importer :: Invalid database specified.') logger.error(u"PlexPy Importer :: Invalid database specified.")
return 'Invalid database specified.' return 'Invalid database specified.'
except: except:
logger.error('PlexPy Importer :: Uncaught exception.') logger.error(u"PlexPy Importer :: Uncaught exception.")
return 'Uncaught exception.' return 'Uncaught exception.'
return 'success' return 'success'
@ -232,16 +232,16 @@ def import_from_plexwatch(database=None, table_name=None, import_ignore_interval
connection = sqlite3.connect(database, timeout=20) connection = sqlite3.connect(database, timeout=20)
connection.row_factory = sqlite3.Row connection.row_factory = sqlite3.Row
except sqlite3.OperationalError: except sqlite3.OperationalError:
logger.error('PlexPy Importer :: Invalid filename.') logger.error(u"PlexPy Importer :: Invalid filename.")
return None return None
except ValueError: except ValueError:
logger.error('PlexPy Importer :: Invalid filename.') logger.error(u"PlexPy Importer :: Invalid filename.")
return None return None
try: try:
connection.execute('SELECT ratingKey from %s' % table_name) connection.execute('SELECT ratingKey from %s' % table_name)
except sqlite3.OperationalError: except sqlite3.OperationalError:
logger.error('PlexPy Importer :: Database specified does not contain the required fields.') logger.error(u"PlexPy Importer :: Database specified does not contain the required fields.")
return None return None
logger.debug(u"PlexPy Importer :: PlexWatch data import in progress...") logger.debug(u"PlexPy Importer :: PlexWatch data import in progress...")

View file

@ -20,7 +20,7 @@ import plexpy
import urllib2 import urllib2
def get_server_friendly_name(): def get_server_friendly_name():
logger.info("Requesting name from server...") logger.info(u"PlexPy Pmsconnect :: Requesting name from server...")
server_name = PmsConnect().get_server_pref(pref='FriendlyName') server_name = PmsConnect().get_server_pref(pref='FriendlyName')
# If friendly name is blank # If friendly name is blank
@ -34,11 +34,12 @@ def get_server_friendly_name():
if server_name and server_name != plexpy.CONFIG.PMS_NAME: if server_name and server_name != plexpy.CONFIG.PMS_NAME:
plexpy.CONFIG.__setattr__('PMS_NAME', server_name) plexpy.CONFIG.__setattr__('PMS_NAME', server_name)
plexpy.CONFIG.write() plexpy.CONFIG.write()
logger.info(u"PlexPy Pmsconnect :: Server name retrieved.")
return server_name return server_name
def refresh_libraries(): def refresh_libraries():
logger.info("Requesting libraries list refresh...") logger.info(u"PlexPy Pmsconnect :: Requesting libraries list refresh...")
library_sections = PmsConnect().get_library_details() library_sections = PmsConnect().get_library_details()
server_id = plexpy.CONFIG.PMS_IDENTIFIER server_id = plexpy.CONFIG.PMS_IDENTIFIER
@ -48,7 +49,7 @@ def refresh_libraries():
else: else:
populate_cards = False populate_cards = False
cards = [] library_keys = []
if library_sections: if library_sections:
monitor_db = database.MonitorDatabase() monitor_db = database.MonitorDatabase()
@ -64,20 +65,21 @@ def refresh_libraries():
'art': section['art'], 'art': section['art'],
'count': section['count'], 'count': section['count'],
'parent_count': section.get('parent_count', None), 'parent_count': section.get('parent_count', None),
'child_count': section.get('child_count', None) 'child_count': section.get('child_count', None),
} }
monitor_db.upsert('library_sections', key_dict=section_keys, value_dict=section_values) monitor_db.upsert('library_sections', key_dict=section_keys, value_dict=section_values)
cards.append(section['key']) library_keys.append(section['key'])
if populate_cards: if populate_cards:
plexpy.CONFIG.__setattr__('HOME_LIBRARY_CARDS', cards) plexpy.CONFIG.__setattr__('HOME_LIBRARY_CARDS', library_keys)
plexpy.CONFIG.write() plexpy.CONFIG.write()
logger.info("Libraries list refreshed.") logger.info(u"PlexPy Pmsconnect :: Libraries list refreshed.")
else: else:
logger.warn("Unable to refresh libraries list.") logger.warn(u"PlexPy Pmsconnect :: Unable to refresh libraries list.")
class PmsConnect(object): class PmsConnect(object):
@ -100,6 +102,7 @@ class PmsConnect(object):
port=port, port=port,
token=plexpy.CONFIG.PMS_TOKEN) token=plexpy.CONFIG.PMS_TOKEN)
def get_sessions(self, output_format=''):
""" """
Return current sessions. Return current sessions.
@ -107,7 +110,6 @@ class PmsConnect(object):
Output: array Output: array
""" """
def get_sessions(self, output_format=''):
uri = '/status/sessions' uri = '/status/sessions'
request = self.request_handler.make_request(uri=uri, request = self.request_handler.make_request(uri=uri,
proto=self.protocol, proto=self.protocol,
@ -116,6 +118,7 @@ class PmsConnect(object):
return request return request
def get_metadata(self, rating_key='', output_format=''):
""" """
Return metadata for request item. Return metadata for request item.
@ -124,7 +127,6 @@ class PmsConnect(object):
Output: array Output: array
""" """
def get_metadata(self, rating_key='', output_format=''):
uri = '/library/metadata/' + rating_key uri = '/library/metadata/' + rating_key
request = self.request_handler.make_request(uri=uri, request = self.request_handler.make_request(uri=uri,
proto=self.protocol, proto=self.protocol,
@ -133,6 +135,7 @@ class PmsConnect(object):
return request return request
def get_metadata_children(self, rating_key='', output_format=''):
""" """
Return metadata for children of the request item. Return metadata for children of the request item.
@ -141,7 +144,6 @@ class PmsConnect(object):
Output: array Output: array
""" """
def get_metadata_children(self, rating_key='', output_format=''):
uri = '/library/metadata/' + rating_key + '/children' uri = '/library/metadata/' + rating_key + '/children'
request = self.request_handler.make_request(uri=uri, request = self.request_handler.make_request(uri=uri,
proto=self.protocol, proto=self.protocol,
@ -150,6 +152,7 @@ class PmsConnect(object):
return request return request
def get_recently_added(self, count='0', output_format=''):
""" """
Return list of recently added items. Return list of recently added items.
@ -158,7 +161,6 @@ class PmsConnect(object):
Output: array Output: array
""" """
def get_recently_added(self, count='0', output_format=''):
uri = '/library/recentlyAdded?X-Plex-Container-Start=0&X-Plex-Container-Size=' + count uri = '/library/recentlyAdded?X-Plex-Container-Start=0&X-Plex-Container-Size=' + count
request = self.request_handler.make_request(uri=uri, request = self.request_handler.make_request(uri=uri,
proto=self.protocol, proto=self.protocol,
@ -167,6 +169,7 @@ class PmsConnect(object):
return request return request
def get_children_list(self, rating_key='', output_format=''):
""" """
Return list of children in requested library item. Return list of children in requested library item.
@ -175,7 +178,6 @@ class PmsConnect(object):
Output: array Output: array
""" """
def get_children_list(self, rating_key='', output_format=''):
uri = '/library/metadata/' + rating_key + '/children' uri = '/library/metadata/' + rating_key + '/children'
request = self.request_handler.make_request(uri=uri, request = self.request_handler.make_request(uri=uri,
proto=self.protocol, proto=self.protocol,
@ -184,6 +186,7 @@ class PmsConnect(object):
return request return request
def get_server_list(self, output_format=''):
""" """
Return list of local servers. Return list of local servers.
@ -191,7 +194,6 @@ class PmsConnect(object):
Output: array Output: array
""" """
def get_server_list(self, output_format=''):
uri = '/servers' uri = '/servers'
request = self.request_handler.make_request(uri=uri, request = self.request_handler.make_request(uri=uri,
proto=self.protocol, proto=self.protocol,
@ -200,6 +202,7 @@ class PmsConnect(object):
return request return request
def get_server_prefs(self, output_format=''):
""" """
Return the local servers preferences. Return the local servers preferences.
@ -207,7 +210,6 @@ class PmsConnect(object):
Output: array Output: array
""" """
def get_server_prefs(self, output_format=''):
uri = '/:/prefs' uri = '/:/prefs'
request = self.request_handler.make_request(uri=uri, request = self.request_handler.make_request(uri=uri,
proto=self.protocol, proto=self.protocol,
@ -216,6 +218,7 @@ class PmsConnect(object):
return request return request
def get_local_server_identity(self, output_format=''):
""" """
Return the local server identity. Return the local server identity.
@ -223,7 +226,6 @@ class PmsConnect(object):
Output: array Output: array
""" """
def get_local_server_identity(self, output_format=''):
uri = '/identity' uri = '/identity'
request = self.request_handler.make_request(uri=uri, request = self.request_handler.make_request(uri=uri,
proto=self.protocol, proto=self.protocol,
@ -232,6 +234,7 @@ class PmsConnect(object):
return request return request
def get_libraries_list(self, output_format=''):
""" """
Return list of libraries on server. Return list of libraries on server.
@ -239,7 +242,6 @@ class PmsConnect(object):
Output: array Output: array
""" """
def get_libraries_list(self, output_format=''):
uri = '/library/sections' uri = '/library/sections'
request = self.request_handler.make_request(uri=uri, request = self.request_handler.make_request(uri=uri,
proto=self.protocol, proto=self.protocol,
@ -248,6 +250,7 @@ class PmsConnect(object):
return request return request
def get_library_list(self, section_key='', list_type='all', count='0', sort_type='', output_format=''):
""" """
Return list of items in library on server. Return list of items in library on server.
@ -255,7 +258,6 @@ class PmsConnect(object):
Output: array Output: array
""" """
def get_library_list(self, section_key='', list_type='all', count='0', sort_type='', output_format=''):
uri = '/library/sections/' + section_key + '/' + list_type +'?X-Plex-Container-Start=0&X-Plex-Container-Size=' + count + sort_type uri = '/library/sections/' + section_key + '/' + list_type +'?X-Plex-Container-Start=0&X-Plex-Container-Size=' + count + sort_type
request = self.request_handler.make_request(uri=uri, request = self.request_handler.make_request(uri=uri,
proto=self.protocol, proto=self.protocol,
@ -264,6 +266,7 @@ class PmsConnect(object):
return request return request
def get_sync_item(self, sync_id=None, output_format=''):
""" """
Return sync item details. Return sync item details.
@ -272,7 +275,6 @@ class PmsConnect(object):
Output: array Output: array
""" """
def get_sync_item(self, sync_id=None, output_format=''):
uri = '/sync/items/' + sync_id uri = '/sync/items/' + sync_id
request = self.request_handler.make_request(uri=uri, request = self.request_handler.make_request(uri=uri,
proto=self.protocol, proto=self.protocol,
@ -281,6 +283,7 @@ class PmsConnect(object):
return request return request
def get_sync_transcode_queue(self, output_format=''):
""" """
Return sync transcode queue. Return sync transcode queue.
@ -288,7 +291,6 @@ class PmsConnect(object):
Output: array Output: array
""" """
def get_sync_transcode_queue(self, output_format=''):
uri = '/sync/transcodeQueue' uri = '/sync/transcodeQueue'
request = self.request_handler.make_request(uri=uri, request = self.request_handler.make_request(uri=uri,
proto=self.protocol, proto=self.protocol,
@ -297,6 +299,7 @@ class PmsConnect(object):
return request return request
def get_search(self, query='', track='', output_format=''):
""" """
Return search results. Return search results.
@ -304,7 +307,6 @@ class PmsConnect(object):
Output: array Output: array
""" """
def get_search(self, query='', track='', output_format=''):
uri = '/search?query=' + urllib2.quote(query.encode('utf8')) + track uri = '/search?query=' + urllib2.quote(query.encode('utf8')) + track
request = self.request_handler.make_request(uri=uri, request = self.request_handler.make_request(uri=uri,
proto=self.protocol, proto=self.protocol,
@ -313,6 +315,7 @@ class PmsConnect(object):
return request return request
def get_account(self, output_format=''):
""" """
Return account details. Return account details.
@ -320,7 +323,6 @@ class PmsConnect(object):
Output: array Output: array
""" """
def get_account(self, output_format=''):
uri = '/myplex/account' uri = '/myplex/account'
request = self.request_handler.make_request(uri=uri, request = self.request_handler.make_request(uri=uri,
proto=self.protocol, proto=self.protocol,
@ -329,6 +331,7 @@ class PmsConnect(object):
return request return request
def put_refresh_reachability(self):
""" """
Refresh Plex remote access port mapping. Refresh Plex remote access port mapping.
@ -336,13 +339,14 @@ class PmsConnect(object):
Output: None Output: None
""" """
def put_refresh_reachability(self):
uri = '/myplex/refreshReachability' uri = '/myplex/refreshReachability'
request = self.request_handler.make_request(uri=uri, request = self.request_handler.make_request(uri=uri,
proto=self.protocol, proto=self.protocol,
request_type='PUT') request_type='PUT')
return request return request
def get_recently_added_details(self, count='0'):
""" """
Return processed and validated list of recently added items. Return processed and validated list of recently added items.
@ -350,13 +354,12 @@ class PmsConnect(object):
Output: array Output: array
""" """
def get_recently_added_details(self, count='0'):
recent = self.get_recently_added(count, output_format='xml') recent = self.get_recently_added(count, output_format='xml')
try: try:
xml_head = recent.getElementsByTagName('MediaContainer') xml_head = recent.getElementsByTagName('MediaContainer')
except: except Exception as e:
logger.warn("Unable to parse XML for get_recently_added.") logger.warn(u"PlexPy Pmsconnect :: Unable to parse XML for get_recently_added: %s." % e)
return [] return []
recents_list = [] recents_list = []
@ -377,7 +380,7 @@ class PmsConnect(object):
'title': helpers.get_xml_attr(item, 'title'), 'title': helpers.get_xml_attr(item, 'title'),
'parent_title': helpers.get_xml_attr(item, 'parentTitle'), 'parent_title': helpers.get_xml_attr(item, 'parentTitle'),
'library_id': helpers.get_xml_attr(item, 'librarySectionID'), 'library_id': helpers.get_xml_attr(item, 'librarySectionID'),
'library_title': helpers.get_xml_attr(item, 'librarySectionTitle'), 'library_name': helpers.get_xml_attr(item, 'librarySectionTitle'),
'thumb': helpers.get_xml_attr(item, 'thumb'), 'thumb': helpers.get_xml_attr(item, 'thumb'),
'added_at': helpers.get_xml_attr(item, 'addedAt') 'added_at': helpers.get_xml_attr(item, 'addedAt')
} }
@ -394,7 +397,7 @@ class PmsConnect(object):
'title': helpers.get_xml_attr(item, 'title'), 'title': helpers.get_xml_attr(item, 'title'),
'parent_title': helpers.get_xml_attr(item, 'parentTitle'), 'parent_title': helpers.get_xml_attr(item, 'parentTitle'),
'library_id': helpers.get_xml_attr(item, 'librarySectionID'), 'library_id': helpers.get_xml_attr(item, 'librarySectionID'),
'library_title': helpers.get_xml_attr(item, 'librarySectionTitle'), 'library_name': helpers.get_xml_attr(item, 'librarySectionTitle'),
'year': helpers.get_xml_attr(item, 'year'), 'year': helpers.get_xml_attr(item, 'year'),
'thumb': helpers.get_xml_attr(item, 'thumb'), 'thumb': helpers.get_xml_attr(item, 'thumb'),
'added_at': helpers.get_xml_attr(item, 'addedAt') 'added_at': helpers.get_xml_attr(item, 'addedAt')
@ -406,6 +409,7 @@ class PmsConnect(object):
output = {'recently_added': sorted(recents_list, key=lambda k: k['added_at'], reverse=True)} output = {'recently_added': sorted(recents_list, key=lambda k: k['added_at'], reverse=True)}
return output return output
def get_metadata_details(self, rating_key=''):
""" """
Return processed and validated metadata list for requested item. Return processed and validated metadata list for requested item.
@ -413,13 +417,12 @@ class PmsConnect(object):
Output: array Output: array
""" """
def get_metadata_details(self, rating_key=''):
metadata = self.get_metadata(str(rating_key), output_format='xml') metadata = self.get_metadata(str(rating_key), output_format='xml')
try: try:
xml_head = metadata.getElementsByTagName('MediaContainer') xml_head = metadata.getElementsByTagName('MediaContainer')
except: except Exception as e:
logger.warn("Unable to parse XML for get_metadata.") logger.warn(u"PlexPy Pmsconnect :: Unable to parse XML for get_metadata: %s: %s." % e)
return [] return []
metadata_list = [] metadata_list = []
@ -440,11 +443,11 @@ class PmsConnect(object):
metadata_main = a.getElementsByTagName('Track')[0] metadata_main = a.getElementsByTagName('Track')[0]
metadata_type = helpers.get_xml_attr(metadata_main, 'type') metadata_type = helpers.get_xml_attr(metadata_main, 'type')
else: else:
logger.debug(u"Metadata failed") logger.debug(u"PlexPy Pmsconnect :: Metadata failed")
return None return None
library_id = helpers.get_xml_attr(a, 'librarySectionID') library_id = helpers.get_xml_attr(a, 'librarySectionID')
library_title = helpers.get_xml_attr(a, 'librarySectionTitle') library_name = helpers.get_xml_attr(a, 'librarySectionTitle')
genres = [] genres = []
actors = [] actors = []
@ -470,7 +473,7 @@ class PmsConnect(object):
if metadata_type == 'movie': if metadata_type == 'movie':
metadata = {'media_type': metadata_type, metadata = {'media_type': metadata_type,
'library_id': library_id, 'library_id': library_id,
'library_title': library_title, 'library_name': library_name,
'rating_key': helpers.get_xml_attr(metadata_main, 'ratingKey'), 'rating_key': helpers.get_xml_attr(metadata_main, 'ratingKey'),
'parent_rating_key': helpers.get_xml_attr(metadata_main, 'parentRatingKey'), 'parent_rating_key': helpers.get_xml_attr(metadata_main, 'parentRatingKey'),
'grandparent_rating_key': helpers.get_xml_attr(metadata_main, 'grandparentRatingKey'), 'grandparent_rating_key': helpers.get_xml_attr(metadata_main, 'grandparentRatingKey'),
@ -505,7 +508,7 @@ class PmsConnect(object):
elif metadata_type == 'show': elif metadata_type == 'show':
metadata = {'media_type': metadata_type, metadata = {'media_type': metadata_type,
'library_id': library_id, 'library_id': library_id,
'library_title': library_title, 'library_name': library_name,
'rating_key': helpers.get_xml_attr(metadata_main, 'ratingKey'), 'rating_key': helpers.get_xml_attr(metadata_main, 'ratingKey'),
'parent_rating_key': helpers.get_xml_attr(metadata_main, 'parentRatingKey'), 'parent_rating_key': helpers.get_xml_attr(metadata_main, 'parentRatingKey'),
'grandparent_rating_key': helpers.get_xml_attr(metadata_main, 'grandparentRatingKey'), 'grandparent_rating_key': helpers.get_xml_attr(metadata_main, 'grandparentRatingKey'),
@ -542,7 +545,7 @@ class PmsConnect(object):
show_details = self.get_metadata_details(parent_rating_key) show_details = self.get_metadata_details(parent_rating_key)
metadata = {'media_type': metadata_type, metadata = {'media_type': metadata_type,
'library_id': library_id, 'library_id': library_id,
'library_title': library_title, 'library_name': library_name,
'rating_key': helpers.get_xml_attr(metadata_main, 'ratingKey'), 'rating_key': helpers.get_xml_attr(metadata_main, 'ratingKey'),
'parent_rating_key': helpers.get_xml_attr(metadata_main, 'parentRatingKey'), 'parent_rating_key': helpers.get_xml_attr(metadata_main, 'parentRatingKey'),
'grandparent_rating_key': helpers.get_xml_attr(metadata_main, 'grandparentRatingKey'), 'grandparent_rating_key': helpers.get_xml_attr(metadata_main, 'grandparentRatingKey'),
@ -579,7 +582,7 @@ class PmsConnect(object):
show_details = self.get_metadata_details(grandparent_rating_key) show_details = self.get_metadata_details(grandparent_rating_key)
metadata = {'media_type': metadata_type, metadata = {'media_type': metadata_type,
'library_id': library_id, 'library_id': library_id,
'library_title': library_title, 'library_name': library_name,
'rating_key': helpers.get_xml_attr(metadata_main, 'ratingKey'), 'rating_key': helpers.get_xml_attr(metadata_main, 'ratingKey'),
'parent_rating_key': helpers.get_xml_attr(metadata_main, 'parentRatingKey'), 'parent_rating_key': helpers.get_xml_attr(metadata_main, 'parentRatingKey'),
'grandparent_rating_key': helpers.get_xml_attr(metadata_main, 'grandparentRatingKey'), 'grandparent_rating_key': helpers.get_xml_attr(metadata_main, 'grandparentRatingKey'),
@ -614,7 +617,7 @@ class PmsConnect(object):
elif metadata_type == 'artist': elif metadata_type == 'artist':
metadata = {'media_type': metadata_type, metadata = {'media_type': metadata_type,
'library_id': library_id, 'library_id': library_id,
'library_title': library_title, 'library_name': library_name,
'rating_key': helpers.get_xml_attr(metadata_main, 'ratingKey'), 'rating_key': helpers.get_xml_attr(metadata_main, 'ratingKey'),
'parent_rating_key': helpers.get_xml_attr(metadata_main, 'parentRatingKey'), 'parent_rating_key': helpers.get_xml_attr(metadata_main, 'parentRatingKey'),
'grandparent_rating_key': helpers.get_xml_attr(metadata_main, 'grandparentRatingKey'), 'grandparent_rating_key': helpers.get_xml_attr(metadata_main, 'grandparentRatingKey'),
@ -651,7 +654,7 @@ class PmsConnect(object):
artist_details = self.get_metadata_details(parent_rating_key) artist_details = self.get_metadata_details(parent_rating_key)
metadata = {'media_type': metadata_type, metadata = {'media_type': metadata_type,
'library_id': library_id, 'library_id': library_id,
'library_title': library_title, 'library_name': library_name,
'rating_key': helpers.get_xml_attr(metadata_main, 'ratingKey'), 'rating_key': helpers.get_xml_attr(metadata_main, 'ratingKey'),
'parent_rating_key': helpers.get_xml_attr(metadata_main, 'parentRatingKey'), 'parent_rating_key': helpers.get_xml_attr(metadata_main, 'parentRatingKey'),
'grandparent_rating_key': helpers.get_xml_attr(metadata_main, 'grandparentRatingKey'), 'grandparent_rating_key': helpers.get_xml_attr(metadata_main, 'grandparentRatingKey'),
@ -688,7 +691,7 @@ class PmsConnect(object):
album_details = self.get_metadata_details(parent_rating_key) album_details = self.get_metadata_details(parent_rating_key)
metadata = {'media_type': metadata_type, metadata = {'media_type': metadata_type,
'library_id': library_id, 'library_id': library_id,
'library_title': library_title, 'library_name': library_name,
'rating_key': helpers.get_xml_attr(metadata_main, 'ratingKey'), 'rating_key': helpers.get_xml_attr(metadata_main, 'ratingKey'),
'parent_rating_key': helpers.get_xml_attr(metadata_main, 'parentRatingKey'), 'parent_rating_key': helpers.get_xml_attr(metadata_main, 'parentRatingKey'),
'grandparent_rating_key': helpers.get_xml_attr(metadata_main, 'grandparentRatingKey'), 'grandparent_rating_key': helpers.get_xml_attr(metadata_main, 'grandparentRatingKey'),
@ -725,6 +728,7 @@ class PmsConnect(object):
return metadata_list return metadata_list
def get_metadata_children_details(self, rating_key=''):
""" """
Return processed and validated metadata list for all children of requested item. Return processed and validated metadata list for all children of requested item.
@ -732,13 +736,12 @@ class PmsConnect(object):
Output: array Output: array
""" """
def get_metadata_children_details(self, rating_key=''):
metadata = self.get_metadata_children(str(rating_key), output_format='xml') metadata = self.get_metadata_children(str(rating_key), output_format='xml')
try: try:
xml_head = metadata.getElementsByTagName('MediaContainer') xml_head = metadata.getElementsByTagName('MediaContainer')
except: except Exception as e:
logger.warn("Unable to parse XML for get_metadata_children.") logger.warn(u"PlexPy Pmsconnect :: Unable to parse XML for get_metadata_children: %s." % e)
metadata_list = [] metadata_list = []
@ -767,6 +770,7 @@ class PmsConnect(object):
output = {'metadata': metadata_list} output = {'metadata': metadata_list}
return output return output
def get_library_metadata_details(self, library_id=''):
""" """
Return processed and validated metadata list for requested library. Return processed and validated metadata list for requested library.
@ -774,13 +778,12 @@ class PmsConnect(object):
Output: array Output: array
""" """
def get_library_metadata_details(self, library_id=''):
libraries_data = self.get_libraries_list(output_format='xml') libraries_data = self.get_libraries_list(output_format='xml')
try: try:
xml_head = libraries_data.getElementsByTagName('MediaContainer') xml_head = libraries_data.getElementsByTagName('MediaContainer')
except: except Exception as e:
logger.warn("Unable to parse XML for get_library_metadata_details.") logger.warn(u"PlexPy Pmsconnect :: Unable to parse XML for get_library_metadata_details: %s." % e)
return [] return []
metadata_list = [] metadata_list = []
@ -814,18 +817,18 @@ class PmsConnect(object):
return metadata_list return metadata_list
def get_current_activity(self):
""" """
Return processed and validated session list. Return processed and validated session list.
Output: array Output: array
""" """
def get_current_activity(self):
session_data = self.get_sessions(output_format='xml') session_data = self.get_sessions(output_format='xml')
try: try:
xml_head = session_data.getElementsByTagName('MediaContainer') xml_head = session_data.getElementsByTagName('MediaContainer')
except: except Exception as e:
logger.warn("Unable to parse XML for get_sessions.") logger.warn(u"PlexPy Pmsconnect :: Unable to parse XML for get_sessions: %s." % e)
return [] return []
session_list = [] session_list = []
@ -863,6 +866,7 @@ class PmsConnect(object):
return output return output
def get_session_each(self, stream_type='', session=None):
""" """
Return selected data from current sessions. Return selected data from current sessions.
This function processes and validates session data This function processes and validates session data
@ -871,7 +875,6 @@ class PmsConnect(object):
session { the session dictionary } session { the session dictionary }
Output: dict Output: dict
""" """
def get_session_each(self, stream_type='', session=None):
session_output = None session_output = None
user_data = users.Users() user_data = users.Users()
@ -905,7 +908,7 @@ class PmsConnect(object):
transcode_container = '' transcode_container = ''
transcode_protocol = '' transcode_protocol = ''
user_details = user_data.get_user_details( user_details = user_data.get_details(
user=helpers.get_xml_attr(session.getElementsByTagName('User')[0], 'title')) user=helpers.get_xml_attr(session.getElementsByTagName('User')[0], 'title'))
if helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'machineIdentifier').endswith('_Track'): if helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'machineIdentifier').endswith('_Track'):
@ -914,6 +917,7 @@ class PmsConnect(object):
machine_id = helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'machineIdentifier') machine_id = helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'machineIdentifier')
session_output = {'session_key': helpers.get_xml_attr(session, 'sessionKey'), session_output = {'session_key': helpers.get_xml_attr(session, 'sessionKey'),
'library_id': helpers.get_xml_attr(session, 'librarySectionID'),
'media_index': helpers.get_xml_attr(session, 'index'), 'media_index': helpers.get_xml_attr(session, 'index'),
'parent_media_index': helpers.get_xml_attr(session, 'parentIndex'), 'parent_media_index': helpers.get_xml_attr(session, 'parentIndex'),
'art': helpers.get_xml_attr(session, 'art'), 'art': helpers.get_xml_attr(session, 'art'),
@ -924,7 +928,7 @@ class PmsConnect(object):
'user': user_details['username'], 'user': user_details['username'],
'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['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(':')[-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'),
@ -1025,7 +1029,7 @@ class PmsConnect(object):
else: else:
use_indexes = 0 use_indexes = 0
user_details = user_data.get_user_details( user_details = user_data.get_details(
user=helpers.get_xml_attr(session.getElementsByTagName('User')[0], 'title')) user=helpers.get_xml_attr(session.getElementsByTagName('User')[0], 'title'))
if helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'machineIdentifier').endswith('_Video'): if helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'machineIdentifier').endswith('_Video'):
@ -1035,6 +1039,7 @@ class PmsConnect(object):
if helpers.get_xml_attr(session, 'type') == 'episode': if helpers.get_xml_attr(session, 'type') == 'episode':
session_output = {'session_key': helpers.get_xml_attr(session, 'sessionKey'), session_output = {'session_key': helpers.get_xml_attr(session, 'sessionKey'),
'library_id': helpers.get_xml_attr(session, 'librarySectionID'),
'media_index': helpers.get_xml_attr(session, 'index'), 'media_index': helpers.get_xml_attr(session, 'index'),
'parent_media_index': helpers.get_xml_attr(session, 'parentIndex'), 'parent_media_index': helpers.get_xml_attr(session, 'parentIndex'),
'art': helpers.get_xml_attr(session, 'art'), 'art': helpers.get_xml_attr(session, 'art'),
@ -1045,7 +1050,7 @@ class PmsConnect(object):
'user': user_details['username'], 'user': user_details['username'],
'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['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(':')[-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'),
@ -1092,6 +1097,7 @@ class PmsConnect(object):
elif helpers.get_xml_attr(session, 'type') == 'movie': elif helpers.get_xml_attr(session, 'type') == 'movie':
session_output = {'session_key': helpers.get_xml_attr(session, 'sessionKey'), session_output = {'session_key': helpers.get_xml_attr(session, 'sessionKey'),
'library_id': helpers.get_xml_attr(session, 'librarySectionID'),
'media_index': helpers.get_xml_attr(session, 'index'), 'media_index': helpers.get_xml_attr(session, 'index'),
'parent_media_index': helpers.get_xml_attr(session, 'parentIndex'), 'parent_media_index': helpers.get_xml_attr(session, 'parentIndex'),
'art': helpers.get_xml_attr(session, 'art'), 'art': helpers.get_xml_attr(session, 'art'),
@ -1102,7 +1108,7 @@ class PmsConnect(object):
'user': user_details['username'], 'user': user_details['username'],
'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['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(':')[-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'),
@ -1149,6 +1155,7 @@ class PmsConnect(object):
elif helpers.get_xml_attr(session, 'type') == 'clip': elif helpers.get_xml_attr(session, 'type') == 'clip':
session_output = {'session_key': helpers.get_xml_attr(session, 'sessionKey'), session_output = {'session_key': helpers.get_xml_attr(session, 'sessionKey'),
'library_id': helpers.get_xml_attr(session, 'librarySectionID'),
'media_index': helpers.get_xml_attr(session, 'index'), 'media_index': helpers.get_xml_attr(session, 'index'),
'parent_media_index': helpers.get_xml_attr(session, 'parentIndex'), 'parent_media_index': helpers.get_xml_attr(session, 'parentIndex'),
'art': helpers.get_xml_attr(session, 'art'), 'art': helpers.get_xml_attr(session, 'art'),
@ -1159,7 +1166,7 @@ class PmsConnect(object):
'user': user_details['username'], 'user': user_details['username'],
'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['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(':')[-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'),
@ -1230,7 +1237,7 @@ class PmsConnect(object):
transcode_container = '' transcode_container = ''
transcode_protocol = '' transcode_protocol = ''
user_details = user_data.get_user_details( user_details = user_data.get_details(
user=helpers.get_xml_attr(session.getElementsByTagName('User')[0], 'title')) user=helpers.get_xml_attr(session.getElementsByTagName('User')[0], 'title'))
if helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'machineIdentifier').endswith('_Photo'): if helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'machineIdentifier').endswith('_Photo'):
@ -1239,6 +1246,7 @@ class PmsConnect(object):
machine_id = helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'machineIdentifier') machine_id = helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'machineIdentifier')
session_output = {'session_key': helpers.get_xml_attr(session, 'sessionKey'), session_output = {'session_key': helpers.get_xml_attr(session, 'sessionKey'),
'library_id': helpers.get_xml_attr(session, 'librarySectionID'),
'media_index': helpers.get_xml_attr(session, 'index'), 'media_index': helpers.get_xml_attr(session, 'index'),
'parent_media_index': helpers.get_xml_attr(session, 'parentIndex'), 'parent_media_index': helpers.get_xml_attr(session, 'parentIndex'),
'art': helpers.get_xml_attr(session, 'art'), 'art': helpers.get_xml_attr(session, 'art'),
@ -1249,7 +1257,7 @@ class PmsConnect(object):
'user': user_details['username'], 'user': user_details['username'],
'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['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(':')[-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'),
@ -1292,7 +1300,7 @@ class PmsConnect(object):
} }
else: else:
logger.warn(u"No known stream types found in session list.") logger.warn(u"PlexPy Pmsconnect :: No known stream types found in session list.")
# Rename Mystery platform names # Rename Mystery platform names
session_output['platform'] = common.PLATFORM_NAME_OVERRIDES.get(session_output['platform'], session_output['platform'] = common.PLATFORM_NAME_OVERRIDES.get(session_output['platform'],
@ -1300,18 +1308,18 @@ class PmsConnect(object):
return session_output return session_output
def get_item_children(self, rating_key=''):
""" """
Return processed and validated children list. Return processed and validated children list.
Output: array Output: array
""" """
def get_item_children(self, rating_key=''):
children_data = self.get_children_list(rating_key, output_format='xml') children_data = self.get_children_list(rating_key, output_format='xml')
try: try:
xml_head = children_data.getElementsByTagName('MediaContainer') xml_head = children_data.getElementsByTagName('MediaContainer')
except: except Exception as e:
logger.warn("Unable to parse XML for get_children_list.") logger.warn(u"PlexPy Pmsconnect :: Unable to parse XML for get_children_list: %s." % e)
return [] return []
children_list = [] children_list = []
@ -1319,7 +1327,7 @@ class PmsConnect(object):
for a in xml_head: for a in xml_head:
if a.getAttribute('size'): if a.getAttribute('size'):
if a.getAttribute('size') == '0': if a.getAttribute('size') == '0':
logger.debug(u"No children data.") logger.debug(u"PlexPy Pmsconnect :: No children data.")
children_list = {'children_count': '0', children_list = {'children_count': '0',
'children_list': [] 'children_list': []
} }
@ -1353,18 +1361,18 @@ class PmsConnect(object):
return output return output
def get_servers_info(self):
""" """
Return the list of local servers. Return the list of local servers.
Output: array Output: array
""" """
def get_servers_info(self):
recent = self.get_server_list(output_format='xml') recent = self.get_server_list(output_format='xml')
try: try:
xml_head = recent.getElementsByTagName('Server') xml_head = recent.getElementsByTagName('Server')
except: except Exception as e:
logger.warn("Unable to parse XML for get_server_list.") logger.warn(u"PlexPy Pmsconnect :: Unable to parse XML for get_server_list: %s." % e)
return [] return []
server_info = [] server_info = []
@ -1380,18 +1388,18 @@ class PmsConnect(object):
return server_info return server_info
def get_server_identity(self):
""" """
Return the local machine identity. Return the local machine identity.
Output: dict Output: dict
""" """
def get_server_identity(self):
identity = self.get_local_server_identity(output_format='xml') identity = self.get_local_server_identity(output_format='xml')
try: try:
xml_head = identity.getElementsByTagName('MediaContainer') xml_head = identity.getElementsByTagName('MediaContainer')
except: except Exception as e:
logger.warn("Unable to parse XML for get_local_server_identity.") logger.warn(u"PlexPy Pmsconnect :: Unable to parse XML for get_local_server_identity: %s." % e)
return [] return []
server_identity = {} server_identity = {}
@ -1402,6 +1410,7 @@ class PmsConnect(object):
return server_identity return server_identity
def get_server_pref(self, pref=None):
""" """
Return a specified server preference. Return a specified server preference.
@ -1409,14 +1418,13 @@ class PmsConnect(object):
Output: string Output: string
""" """
def get_server_pref(self, pref=None):
if pref: if pref:
prefs = self.get_server_prefs(output_format='xml') prefs = self.get_server_prefs(output_format='xml')
try: try:
xml_head = prefs.getElementsByTagName('Setting') xml_head = prefs.getElementsByTagName('Setting')
except: except Exception as e:
logger.warn("Unable to parse XML for get_local_server_name.") logger.warn(u"PlexPy Pmsconnect :: Unable to parse XML for get_local_server_name: %s." % e)
return '' return ''
pref_value = 'None' pref_value = 'None'
@ -1427,21 +1435,21 @@ class PmsConnect(object):
return pref_value return pref_value
else: else:
logger.debug(u"Server preferences queried but no parameter received.") logger.debug(u"PlexPy Pmsconnect :: Server preferences queried but no parameter received.")
return None return None
def get_server_children(self):
""" """
Return processed and validated server libraries list. Return processed and validated server libraries list.
Output: array Output: array
""" """
def get_server_children(self):
libraries_data = self.get_libraries_list(output_format='xml') libraries_data = self.get_libraries_list(output_format='xml')
try: try:
xml_head = libraries_data.getElementsByTagName('MediaContainer') xml_head = libraries_data.getElementsByTagName('MediaContainer')
except: except Exception as e:
logger.warn("Unable to parse XML for get_libraries_list.") logger.warn(u"PlexPy Pmsconnect :: Unable to parse XML for get_libraries_list: %s." % e)
return [] return []
libraries_list = [] libraries_list = []
@ -1449,7 +1457,7 @@ class PmsConnect(object):
for a in xml_head: for a in xml_head:
if a.getAttribute('size'): if a.getAttribute('size'):
if a.getAttribute('size') == '0': if a.getAttribute('size') == '0':
logger.debug(u"No libraries data.") logger.debug(u"PlexPy Pmsconnect :: No libraries data.")
libraries_list = {'libraries_count': '0', libraries_list = {'libraries_count': '0',
'libraries_list': [] 'libraries_list': []
} }
@ -1473,6 +1481,7 @@ class PmsConnect(object):
return output return output
def get_library_children(self, library_type='', section_key='', list_type='all', sort_type = ''):
""" """
Return processed and validated server library items list. Return processed and validated server library items list.
@ -1481,7 +1490,6 @@ class PmsConnect(object):
Output: array Output: array
""" """
def get_library_children(self, library_type='', section_key='', list_type='all', sort_type = ''):
# Currently only grab the library with 1 items so 'size' is not 0 # Currently only grab the library with 1 items so 'size' is not 0
count = '1' count = '1'
@ -1511,8 +1519,8 @@ class PmsConnect(object):
try: try:
xml_head = library_data.getElementsByTagName('MediaContainer') xml_head = library_data.getElementsByTagName('MediaContainer')
except: except Exception as e:
logger.warn("Unable to parse XML for get_library_children.") logger.warn(u"PlexPy Pmsconnect :: Unable to parse XML for get_library_children: %s." % e)
return [] return []
library_list = [] library_list = []
@ -1520,7 +1528,7 @@ class PmsConnect(object):
for a in xml_head: for a in xml_head:
if a.getAttribute('size'): if a.getAttribute('size'):
if a.getAttribute('size') == '0': if a.getAttribute('size') == '0':
logger.debug(u"No library data.") logger.debug(u"PlexPy Pmsconnect :: No library data.")
library_list = {'library_count': '0', library_list = {'library_count': '0',
'library_list': [] 'library_list': []
} }
@ -1543,12 +1551,12 @@ class PmsConnect(object):
return output return output
def get_library_details(self):
""" """
Return processed and validated library statistics. Return processed and validated library statistics.
Output: array Output: array
""" """
def get_library_details(self):
server_libraries = self.get_server_children() server_libraries = self.get_server_children()
server_library_stats = [] server_library_stats = []
@ -1614,6 +1622,7 @@ class PmsConnect(object):
return server_library_stats return server_library_stats
def get_image(self, img=None, width=None, height=None):
""" """
Return image data as array. Return image data as array.
Array contains the image content type and image binary Array contains the image content type and image binary
@ -1623,7 +1632,6 @@ class PmsConnect(object):
height { the image height } height { the image height }
Output: array Output: array
""" """
def get_image(self, img=None, width=None, height=None):
if img: if img:
if width.isdigit() and height.isdigit(): if width.isdigit() and height.isdigit():
uri = '/photo/:/transcode?url=http://127.0.0.1:32400' + img + '&width=' + width + '&height=' + height uri = '/photo/:/transcode?url=http://127.0.0.1:32400' + img + '&width=' + width + '&height=' + height
@ -1637,15 +1645,15 @@ class PmsConnect(object):
return [request, content_type] return [request, content_type]
else: else:
logger.error("Image proxy queries but no input received.") logger.error(u"PlexPy Pmsconnect :: Image proxy queries but no input received.")
return None return None
def get_search_results(self, query=''):
""" """
Return processed list of search results. Return processed list of search results.
Output: array Output: array
""" """
def get_search_results(self, query=''):
search_results = self.get_search(query=query, output_format='xml') search_results = self.get_search(query=query, output_format='xml')
search_results_tracks = self.get_search(query=query, track='&type=10', output_format='xml') search_results_tracks = self.get_search(query=query, track='&type=10', output_format='xml')
@ -1659,8 +1667,8 @@ class PmsConnect(object):
xml_head += search_results_tracks.getElementsByTagName('MediaContainer') xml_head += search_results_tracks.getElementsByTagName('MediaContainer')
except: except:
pass pass
except: except Exception as e:
logger.warn("Unable to parse XML for get_search_result_details.") logger.warn(u"PlexPy Pmsconnect :: Unable to parse XML for get_search_result_details: %s." % e)
return [] return []
search_results_count = 0 search_results_count = 0
@ -1678,7 +1686,7 @@ class PmsConnect(object):
if a.getAttribute('size'): if a.getAttribute('size'):
totalSize += int(a.getAttribute('size')) totalSize += int(a.getAttribute('size'))
if totalSize == 0: if totalSize == 0:
logger.debug(u"No search results.") logger.debug(u"PlexPy Pmsconnect :: No search results.")
search_results_list = {'results_count': search_results_count, search_results_list = {'results_count': search_results_count,
'results_list': [] 'results_list': []
} }
@ -1733,12 +1741,12 @@ class PmsConnect(object):
return output return output
def get_rating_keys_list(self, rating_key='', media_type=''):
""" """
Return processed list of grandparent/parent/child rating keys. Return processed list of grandparent/parent/child rating keys.
Output: array Output: array
""" """
def get_rating_keys_list(self, rating_key='', media_type=''):
if media_type == 'movie': if media_type == 'movie':
key_list = {0: {'rating_key': int(rating_key)}} key_list = {0: {'rating_key': int(rating_key)}}
@ -1750,7 +1758,7 @@ class PmsConnect(object):
match_type = 'index' match_type = 'index'
library_id = None library_id = None
library_title = None library_name = None
# get grandparent rating key # get grandparent rating key
if media_type == 'season' or media_type == 'album': if media_type == 'season' or media_type == 'album':
@ -1758,9 +1766,9 @@ class PmsConnect(object):
metadata = self.get_metadata_details(rating_key=rating_key) metadata = self.get_metadata_details(rating_key=rating_key)
rating_key = metadata['metadata']['parent_rating_key'] rating_key = metadata['metadata']['parent_rating_key']
library_id = metadata['metadata']['library_id'] library_id = metadata['metadata']['library_id']
library_title = metadata['metadata']['library_title'] library_name = metadata['metadata']['library_name']
except: except Exception as e:
logger.warn("Unable to get parent_rating_key for get_rating_keys_list.") logger.warn(u"PlexPy Pmsconnect :: Unable to get parent_rating_key for get_rating_keys_list: %s." % e)
return {} return {}
elif media_type == 'episode' or media_type == 'track': elif media_type == 'episode' or media_type == 'track':
@ -1768,9 +1776,9 @@ class PmsConnect(object):
metadata = self.get_metadata_details(rating_key=rating_key) metadata = self.get_metadata_details(rating_key=rating_key)
rating_key = metadata['metadata']['grandparent_rating_key'] rating_key = metadata['metadata']['grandparent_rating_key']
library_id = metadata['metadata']['library_id'] library_id = metadata['metadata']['library_id']
library_title = metadata['metadata']['library_title'] library_name = metadata['metadata']['library_name']
except: except Exception as e:
logger.warn("Unable to get grandparent_rating_key for get_rating_keys_list.") logger.warn(u"PlexPy Pmsconnect :: Unable to get grandparent_rating_key for get_rating_keys_list: %s." % e)
return {} return {}
# get parent_rating_keys # get parent_rating_keys
@ -1778,8 +1786,8 @@ class PmsConnect(object):
try: try:
xml_head = metadata.getElementsByTagName('MediaContainer') xml_head = metadata.getElementsByTagName('MediaContainer')
except: except Exception as e:
logger.warn("Unable to parse XML for get_rating_keys_list.") logger.warn(u"PlexPy Pmsconnect :: Unable to parse XML for get_rating_keys_list: %s." % e)
return {} return {}
for a in xml_head: for a in xml_head:
@ -1806,8 +1814,8 @@ class PmsConnect(object):
try: try:
xml_head = metadata.getElementsByTagName('MediaContainer') xml_head = metadata.getElementsByTagName('MediaContainer')
except: except Exception as e:
logger.warn("Unable to parse XML for get_rating_keys_list.") logger.warn(u"PlexPy Pmsconnect :: Unable to parse XML for get_rating_keys_list: %s." % e)
return {} return {}
for a in xml_head: for a in xml_head:
@ -1843,7 +1851,7 @@ class PmsConnect(object):
{'rating_key': int(rating_key), {'rating_key': int(rating_key),
'children': parents }, 'children': parents },
'library_id': library_id, 'library_id': library_id,
'library_title': library_title 'library_name': library_name
} }
return key_list return key_list
@ -1855,8 +1863,8 @@ class PmsConnect(object):
try: try:
xml_head = account_data.getElementsByTagName('MyPlex') xml_head = account_data.getElementsByTagName('MyPlex')
except: except Exception as e:
logger.warn("Unable to parse XML for get_server_response.") logger.warn(u"PlexPy Pmsconnect :: Unable to parse XML for get_server_response: %s." % e)
return None return None
server_response = {} server_response = {}

View file

@ -21,28 +21,28 @@ class Users(object):
def __init__(self): def __init__(self):
pass pass
def get_user_list(self, kwargs=None): def get_datatables_list(self, kwargs=None):
data_tables = datatables.DataTables() data_tables = datatables.DataTables()
custom_where = ['users.deleted_user', 0] custom_where = ['users.deleted_user', 0]
columns = ['users.user_id as user_id', columns = ['users.user_id',
'users.custom_avatar_url as user_thumb', 'users.username',
'(case when users.friendly_name is null then users.username else \ 'users.friendly_name',
users.friendly_name end) as friendly_name', 'users.thumb AS user_thumb',
'MAX(session_history.started) as last_seen', 'users.custom_avatar_url AS custom_thumb',
'session_history.ip_address as ip_address', 'COUNT(session_history.id) AS plays',
'COUNT(session_history.id) as plays', 'MAX(session_history.started) AS last_seen',
'session_history.platform as platform', 'session_history_metadata.full_title AS last_watched',
'session_history.player as player', 'session_history.ip_address',
'session_history_metadata.full_title as last_watched', 'session_history.platform',
'session_history.player',
'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',
'session_history_metadata.media_type', 'session_history_metadata.media_type',
'session_history.rating_key as rating_key', 'session_history.rating_key',
'session_history_media_info.video_decision', 'session_history_media_info.video_decision',
'users.username as user',
'users.do_notify as do_notify', 'users.do_notify as do_notify',
'users.keep_history as keep_history' 'users.keep_history as keep_history'
] ]
@ -61,8 +61,8 @@ class Users(object):
['session_history.id', 'session_history_metadata.id'], ['session_history.id', 'session_history_metadata.id'],
['session_history.id', 'session_history_media_info.id']], ['session_history.id', 'session_history_media_info.id']],
kwargs=kwargs) kwargs=kwargs)
except: except Exception as e:
logger.warn("Unable to execute database query.") logger.warn(u"PlexPy Users :: Unable to execute database query for get_list: %s." % e)
return {'recordsFiltered': 0, return {'recordsFiltered': 0,
'recordsTotal': 0, 'recordsTotal': 0,
'draw': 0, 'draw': 0,
@ -80,28 +80,30 @@ class Users(object):
else: else:
thumb = item['thumb'] thumb = item['thumb']
if not item['user_thumb'] or item['user_thumb'] == '': if item['custom_thumb'] and item['custom_thumb'] != item['user_thumb']:
user_thumb = common.DEFAULT_USER_THUMB user_thumb = item['custom_thumb']
else: elif item['user_thumb']:
user_thumb = item['user_thumb'] user_thumb = item['user_thumb']
else:
user_thumb = common.DEFAULT_USER_THUMB
# Rename Mystery platform names # Rename Mystery platform names
platform = common.PLATFORM_NAME_OVERRIDES.get(item['platform'], item['platform']) platform = common.PLATFORM_NAME_OVERRIDES.get(item['platform'], item['platform'])
row = {'plays': item['plays'], row = {'user_id': item['user_id'],
'last_seen': item['last_seen'], 'username': item['username'],
'friendly_name': item['friendly_name'], 'friendly_name': item['friendly_name'],
'user_thumb': user_thumb,
'plays': item['plays'],
'last_seen': item['last_seen'],
'last_watched': item['last_watched'],
'ip_address': item['ip_address'], 'ip_address': item['ip_address'],
'platform': platform, 'platform': platform,
'player': item['player'], 'player': item['player'],
'last_watched': item['last_watched'],
'thumb': thumb, 'thumb': thumb,
'media_type': item['media_type'], 'media_type': item['media_type'],
'rating_key': item['rating_key'], 'rating_key': item['rating_key'],
'video_decision': item['video_decision'], 'video_decision': item['video_decision'],
'user_thumb': user_thumb,
'user': item['user'],
'user_id': item['user_id'],
'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'])
} }
@ -116,35 +118,34 @@ class Users(object):
return dict return dict
def get_user_unique_ips(self, kwargs=None, custom_where=None): def get_datatables_unique_ips(self, user_id=None, kwargs=None):
data_tables = datatables.DataTables() data_tables = datatables.DataTables()
# Change custom_where column name due to ambiguous column name after JOIN custom_where = ['users.user_id', user_id]
custom_where[0][0] = 'custom_user_id' if custom_where[0][0] == 'user_id' else custom_where[0][0]
columns = ['session_history.id', columns = ['session_history.id',
'session_history.started as last_seen', 'session_history.started AS last_seen',
'session_history.ip_address as ip_address', 'session_history.ip_address',
'COUNT(session_history.id) as play_count', 'COUNT(session_history.id) AS play_count',
'session_history.platform as platform', 'session_history.platform',
'session_history.player as player', 'session_history.player',
'session_history_metadata.full_title as last_watched', 'session_history_metadata.full_title AS last_watched',
'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',
'session_history_metadata.media_type', 'session_history_metadata.media_type',
'session_history.rating_key as rating_key', 'session_history.rating_key',
'session_history_media_info.video_decision', 'session_history_media_info.video_decision',
'session_history.user as 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 \
users.friendly_name end) as friendly_name' users.friendly_name END) AS friendly_name'
] ]
try: try:
query = data_tables.ssp_query(table_name='session_history', query = data_tables.ssp_query(table_name='session_history',
columns=columns, columns=columns,
custom_where=custom_where, custom_where=[custom_where],
group_by=['ip_address'], group_by=['ip_address'],
join_types=['JOIN', join_types=['JOIN',
'JOIN', 'JOIN',
@ -156,8 +157,8 @@ class Users(object):
['session_history.id', 'session_history_metadata.id'], ['session_history.id', 'session_history_metadata.id'],
['session_history.id', 'session_history_media_info.id']], ['session_history.id', 'session_history_media_info.id']],
kwargs=kwargs) kwargs=kwargs)
except: except Exception as e:
logger.warn("Unable to execute database query.") logger.warn(u"PlexPy Users :: Unable to execute database query for get_unique_ips: %s." % e)
return {'recordsFiltered': 0, return {'recordsFiltered': 0,
'recordsTotal': 0, 'recordsTotal': 0,
'draw': 0, 'draw': 0,
@ -178,18 +179,18 @@ class Users(object):
# Rename Mystery platform names # Rename Mystery platform names
platform = common.PLATFORM_NAME_OVERRIDES.get(item["platform"], item["platform"]) platform = common.PLATFORM_NAME_OVERRIDES.get(item["platform"], item["platform"])
row = {"id": item['id'], row = {'id': item['id'],
"last_seen": item['last_seen'], 'last_seen': item['last_seen'],
"ip_address": item['ip_address'], 'ip_address': item['ip_address'],
"play_count": item['play_count'], 'play_count': item['play_count'],
"platform": platform, 'platform': platform,
"player": item['player'], 'player': item['player'],
"last_watched": item['last_watched'], 'last_watched': item['last_watched'],
"thumb": thumb, 'thumb': thumb,
"media_type": item['media_type'], 'media_type': item['media_type'],
"rating_key": item['rating_key'], 'rating_key': item['rating_key'],
"video_decision": item['video_decision'], 'video_decision': item['video_decision'],
"friendly_name": item['friendly_name'] 'friendly_name': item['friendly_name']
} }
rows.append(row) rows.append(row)
@ -202,286 +203,169 @@ class Users(object):
return dict return dict
# TODO: The getter and setter for this needs to become a config getter/setter for more than just friendlyname def set_config(self, user_id=None, friendly_name='', custom_thumb='', do_notify=1, keep_history=1):
def set_user_friendly_name(self, user=None, user_id=None, friendly_name=None, do_notify=0, keep_history=1): if str(user_id).isdigit():
if user_id:
if friendly_name.strip() == '':
friendly_name = None
monitor_db = database.MonitorDatabase() monitor_db = database.MonitorDatabase()
control_value_dict = {"user_id": user_id} key_dict = {'user_id': user_id}
new_value_dict = {"friendly_name": friendly_name, value_dict = {'friendly_name': friendly_name,
"do_notify": do_notify, 'custom_avatar_url': custom_thumb,
"keep_history": keep_history} 'do_notify': do_notify,
'keep_history': keep_history}
try: try:
monitor_db.upsert('users', new_value_dict, control_value_dict) monitor_db.upsert('users', value_dict, key_dict)
except Exception, e: except Exception as e:
logger.debug(u"Uncaught exception %s" % e) logger.warn(u"PlexPy Users :: Unable to execute database query for set_config: %s." % e)
if user:
if friendly_name.strip() == '':
friendly_name = None
monitor_db = database.MonitorDatabase() def get_details(self, user_id=None, user=None):
control_value_dict = {"username": user}
new_value_dict = {"friendly_name": friendly_name,
"do_notify": do_notify,
"keep_history": keep_history}
try:
monitor_db.upsert('users', new_value_dict, control_value_dict)
except Exception, e:
logger.debug(u"Uncaught exception %s" % e)
def set_user_profile_url(self, user=None, user_id=None, profile_url=None):
if user_id:
if profile_url.strip() == '':
profile_url = None
monitor_db = database.MonitorDatabase()
control_value_dict = {"user_id": user_id}
new_value_dict = {"custom_avatar_url": profile_url}
try:
monitor_db.upsert('users', new_value_dict, control_value_dict)
except Exception, e:
logger.debug(u"Uncaught exception %s" % e)
if user:
if profile_url.strip() == '':
profile_url = None
monitor_db = database.MonitorDatabase()
control_value_dict = {"username": user}
new_value_dict = {"custom_avatar_url": profile_url}
try:
monitor_db.upsert('users', new_value_dict, control_value_dict)
except Exception, e:
logger.debug(u"Uncaught exception %s" % e)
def get_user_friendly_name(self, user=None, user_id=None):
if user_id:
monitor_db = database.MonitorDatabase()
query = 'select username, ' \
'(CASE WHEN friendly_name IS NULL THEN username ELSE friendly_name END) as friendly_name,' \
'do_notify, keep_history, custom_avatar_url as thumb ' \
'FROM users WHERE user_id = ?'
result = monitor_db.select(query, args=[user_id])
if result:
user_detail = {'user_id': user_id,
'user': result[0]['username'],
'friendly_name': result[0]['friendly_name'],
'thumb': result[0]['thumb'],
'do_notify': helpers.checked(result[0]['do_notify']),
'keep_history': helpers.checked(result[0]['keep_history'])
}
return user_detail
else:
user_detail = {'user_id': user_id,
'user': '',
'friendly_name': '',
'do_notify': '',
'thumb': '',
'keep_history': ''}
return user_detail
elif user:
monitor_db = database.MonitorDatabase()
query = 'select user_id, ' \
'(CASE WHEN friendly_name IS NULL THEN username ELSE friendly_name END) as friendly_name,' \
'do_notify, keep_history, custom_avatar_url as thumb ' \
'FROM users WHERE username = ?'
result = monitor_db.select(query, args=[user])
if result:
user_detail = {'user_id': result[0]['user_id'],
'user': user,
'friendly_name': result[0]['friendly_name'],
'thumb': result[0]['thumb'],
'do_notify': helpers.checked(result[0]['do_notify']),
'keep_history': helpers.checked(result[0]['keep_history'])}
return user_detail
else:
user_detail = {'user_id': None,
'user': user,
'friendly_name': '',
'do_notify': '',
'thumb': '',
'keep_history': ''}
return user_detail
return None
def get_user_id(self, user=None):
if user:
try:
monitor_db = database.MonitorDatabase()
query = 'select user_id FROM users WHERE username = ?'
result = monitor_db.select_single(query, args=[user])
if result:
return result['user_id']
else:
return None
except:
return None
return None
def get_user_details(self, user=None, user_id=None):
from plexpy import plextv from plexpy import plextv
monitor_db = database.MonitorDatabase() monitor_db = database.MonitorDatabase()
if user: try:
query = 'SELECT user_id, username, friendly_name, email, ' \ if str(user_id).isdigit():
'custom_avatar_url as thumb, is_home_user, is_allow_sync, is_restricted, do_notify ' \ query = 'SELECT user_id, username, friendly_name, thumb AS user_thumb, custom_avatar_url AS custom_thumb, ' \
'email, is_home_user, is_allow_sync, is_restricted, do_notify, keep_history ' \
'FROM users ' \ 'FROM users ' \
'WHERE username = ? ' \ 'WHERE user_id = ? '
'UNION ALL ' \ result = monitor_db.select(query, args=[user_id])
'SELECT null, user, null, null, null, null, null, null, null ' \ elif user:
'FROM session_history ' \ query = 'SELECT user_id, username, friendly_name, thumb AS user_thumb, custom_avatar_url AS custom_thumb, ' \
'WHERE user = ? ' \ 'email, is_home_user, is_allow_sync, is_restricted, do_notify, keep_history ' \
'GROUP BY user ' \
'LIMIT 1'
result = monitor_db.select(query, args=[user, user])
elif user_id:
query = 'SELECT user_id, username, friendly_name, email, ' \
'custom_avatar_url as thumb, is_home_user, is_allow_sync, is_restricted, do_notify ' \
'FROM users ' \ 'FROM users ' \
'WHERE user_id = ? ' \ 'WHERE username = ? '
'UNION ALL ' \ result = monitor_db.select(query, args=[user])
'SELECT user_id, user, null, null, null, null, null, null, null ' \
'FROM session_history ' \
'WHERE user_id = ? ' \
'GROUP BY user ' \
'LIMIT 1'
result = monitor_db.select(query, args=[user_id, user_id])
else: else:
result = None result = []
except Exception as e:
logger.warn(u"PlexPy Users :: Unable to execute database query for get_details: %s." % e)
result = []
if result: if result:
user_details = {} user_details = {}
for item in result: for item in result:
if not item['friendly_name']: if item['friendly_name']:
friendly_name = item['username']
else:
friendly_name = item['friendly_name'] friendly_name = item['friendly_name']
if not item['thumb'] or item['thumb'] == '':
user_thumb = common.DEFAULT_USER_THUMB
else: else:
user_thumb = item['thumb'] friendly_name = item['username']
user_details = {"user_id": item['user_id'], if item['custom_thumb'] and item['custom_thumb'] != item['user_thumb']:
"username": item['username'], user_thumb = item['custom_thumb']
"friendly_name": friendly_name, elif item['user_thumb']:
"email": item['email'], user_thumb = item['user_thumb']
"thumb": user_thumb, else:
"is_home_user": item['is_home_user'], user_thumb = common.DEFAULT_USER_THUMB
"is_allow_sync": item['is_allow_sync'],
"is_restricted": item['is_restricted'], user_details = {'user_id': item['user_id'],
"do_notify": item['do_notify'] 'username': item['username'],
'friendly_name': friendly_name,
'user_thumb': user_thumb,
'email': item['email'],
'is_home_user': item['is_home_user'],
'is_allow_sync': item['is_allow_sync'],
'is_restricted': item['is_restricted'],
'do_notify': item['do_notify'],
'keep_history': item['keep_history']
} }
return user_details return user_details
else: else:
logger.warn(u"PlexPy :: Unable to retrieve user from local database. Requesting user list refresh.") logger.warn(u"PlexPy Users :: Unable to retrieve user from local database. Requesting user list refresh.")
# 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
if user: try:
if str(user_id).isdigit():
# Refresh users # Refresh users
plextv.refresh_users() plextv.refresh_users()
query = 'SELECT user_id, username, friendly_name, email, ' \ query = 'SELECT user_id, username, friendly_name, thumb AS user_thumb, custom_avatar_url AS custom_thumb, ' \
'custom_avatar_url as thumb, is_home_user, is_allow_sync, is_restricted, do_notify ' \ 'email, is_home_user, is_allow_sync, is_restricted, do_notify, keep_history ' \
'FROM users ' \ 'FROM users ' \
'WHERE username = ? ' \ 'WHERE user_id = ? '
'UNION ALL ' \ result = monitor_db.select(query, args=[user_id])
'SELECT null, user, null, null, null, null, null, null, null ' \ elif user:
'FROM session_history ' \ query = 'SELECT user_id, username, friendly_name, thumb AS user_thumb, custom_avatar_url AS custom_thumb, ' \
'WHERE user = ? ' \ 'email, is_home_user, is_allow_sync, is_restricted, do_notify, keep_history ' \
'GROUP BY user ' \
'LIMIT 1'
result = monitor_db.select(query, args=[user, user])
elif user_id:
# Refresh users
plextv.refresh_users()
query = 'SELECT user_id, username, friendly_name, email, ' \
'custom_avatar_url as thumb, is_home_user, is_allow_sync, is_restricted, do_notify ' \
'FROM users ' \ 'FROM users ' \
'WHERE user_id = ? ' \ 'WHERE username = ? '
'UNION ALL ' \ result = monitor_db.select(query, args=[user])
'SELECT user_id, user, null, null, null, null, null, null, null ' \
'FROM session_history ' \
'WHERE user_id = ? ' \
'GROUP BY user ' \
'LIMIT 1'
result = monitor_db.select(query, args=[user_id, user_id])
else: else:
result = None result = []
except Exception as e:
logger.warn(u"PlexPy Users :: Unable to execute database query for get_details: %s." % e)
result = []
if result: if result:
user_details = {} user_details = {}
for item in result: for item in result:
if not item['friendly_name']: if item['friendly_name']:
friendly_name = item['username']
else:
friendly_name = item['friendly_name'] friendly_name = item['friendly_name']
if not item['thumb'] or item['thumb'] == '':
user_thumb = common.DEFAULT_USER_THUMB
else: else:
user_thumb = item['thumb'] friendly_name = item['username']
user_details = {"user_id": item['user_id'], if item['custom_thumb'] and item['custom_thumb'] != item['user_thumb']:
"username": item['username'], user_thumb = item['custom_thumb']
"friendly_name": friendly_name, elif item['user_thumb']:
"email": item['email'], user_thumb = item['user_thumb']
"thumb": user_thumb, else:
"is_home_user": item['is_home_user'], user_thumb = common.DEFAULT_USER_THUMB
"is_allow_sync": item['is_allow_sync'],
"is_restricted": item['is_restricted'], user_details = {'user_id': item['user_id'],
"do_notify": item['do_notify'] 'username': item['username'],
'friendly_name': friendly_name,
'user_thumb': user_thumb,
'email': item['email'],
'is_home_user': item['is_home_user'],
'is_allow_sync': item['is_allow_sync'],
'is_restricted': item['is_restricted'],
'do_notify': item['do_notify'],
'keep_history': item['keep_history']
} }
return user_details return user_details
else: else:
# 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 {"user_id": None, return {'user_id': None,
"username": 'Local', 'username': 'Local',
"friendly_name": 'Local', 'friendly_name': 'Local',
"email": '', 'user_thumb': common.DEFAULT_USER_THUMB,
"thumb": '', 'email': '',
"is_home_user": 0, 'is_home_user': 0,
"is_allow_sync": 0, 'is_allow_sync': 0,
"is_restricted": 0, 'is_restricted': 0,
"do_notify": 0 'do_notify': 0,
'keep_history': 0
} }
def get_user_watch_time_stats(self, user=None, user_id=None): def get_watch_time_stats(self, user_id=None):
monitor_db = database.MonitorDatabase() monitor_db = database.MonitorDatabase()
time_queries = [1, 7, 30, 0] time_queries = [1, 7, 30, 0]
user_watch_time_stats = [] user_watch_time_stats = []
for days in time_queries: for days in time_queries:
try:
if days > 0: if days > 0:
if user_id: if str(user_id).isdigit():
query = 'SELECT (SUM(stopped - started) - ' \ query = 'SELECT (SUM(stopped - started) - ' \
'SUM(CASE WHEN paused_counter is null THEN 0 ELSE paused_counter END)) as total_time, ' \ ' SUM(CASE WHEN paused_counter is null THEN 0 ELSE paused_counter END)) as total_time, ' \
'COUNT(id) AS total_plays ' \ 'COUNT(id) AS total_plays ' \
'FROM session_history ' \ 'FROM session_history ' \
'WHERE datetime(stopped, "unixepoch", "localtime") >= datetime("now", "-%s days", "localtime") ' \ 'WHERE datetime(stopped, "unixepoch", "localtime") >= datetime("now", "-%s days", "localtime") ' \
'AND user_id = ?' % days 'AND user_id = ?' % days
result = monitor_db.select(query, args=[user_id]) result = monitor_db.select(query, args=[user_id])
elif user:
query = 'SELECT (SUM(stopped - started) - ' \
'SUM(CASE WHEN paused_counter is null THEN 0 ELSE paused_counter END)) as total_time, ' \
'COUNT(id) AS total_plays ' \
'FROM session_history ' \
'WHERE datetime(stopped, "unixepoch", "localtime") >= datetime("now", "-%s days", "localtime") ' \
'AND user = ?' % days
result = monitor_db.select(query, args=[user])
else: else:
result = []
else:
if str(user_id).isdigit():
query = 'SELECT (SUM(stopped - started) - ' \ query = 'SELECT (SUM(stopped - started) - ' \
'SUM(CASE WHEN paused_counter is null THEN 0 ELSE paused_counter END)) as total_time, ' \ ' SUM(CASE WHEN paused_counter is null THEN 0 ELSE paused_counter END)) as total_time, ' \
'COUNT(id) AS total_plays ' \ 'COUNT(id) AS total_plays ' \
'FROM session_history ' \ 'FROM session_history ' \
'WHERE user = ?' 'WHERE user_id = ?'
result = monitor_db.select(query, args=[user]) result = monitor_db.select(query, args=[user_id])
else:
result = []
except Exception as e:
logger.warn(u"PlexPy Users :: Unable to execute database query for get_watch_time_stats: %s." % e)
result = []
for item in result: for item in result:
if item['total_time']: if item['total_time']:
@ -500,14 +384,14 @@ class Users(object):
return user_watch_time_stats return user_watch_time_stats
def get_user_player_stats(self, user=None, user_id=None): def get_player_stats(self, user_id=None):
monitor_db = database.MonitorDatabase() monitor_db = database.MonitorDatabase()
player_stats = [] player_stats = []
result_id = 0 result_id = 0
try: try:
if user_id: if str(user_id).isdigit():
query = 'SELECT player, COUNT(player) as player_count, platform ' \ query = 'SELECT player, COUNT(player) as player_count, platform ' \
'FROM session_history ' \ 'FROM session_history ' \
'WHERE user_id = ? ' \ 'WHERE user_id = ? ' \
@ -515,15 +399,10 @@ class Users(object):
'ORDER BY player_count DESC' 'ORDER BY player_count DESC'
result = monitor_db.select(query, args=[user_id]) result = monitor_db.select(query, args=[user_id])
else: else:
query = 'SELECT player, COUNT(player) as player_count, platform ' \ result = []
'FROM session_history ' \ except Exception as e:
'WHERE user = ? ' \ logger.warn(u"PlexPy Users :: Unable to execute database query for get_player_stats: %s." % e)
'GROUP BY player ' \ result = []
'ORDER BY player_count DESC'
result = monitor_db.select(query, args=[user])
except:
logger.warn("Unable to execute database query.")
return None
for item in result: for item in result:
# Rename Mystery platform names # Rename Mystery platform names
@ -538,3 +417,140 @@ class Users(object):
result_id += 1 result_id += 1
return player_stats return player_stats
def get_recently_watched(self, user_id=None, limit='10'):
monitor_db = database.MonitorDatabase()
recently_watched = []
if not limit.isdigit():
limit = '10'
try:
if str(user_id).isdigit():
query = 'SELECT session_history.id, session_history.media_type, session_history.rating_key, session_history.parent_rating_key, ' \
'title, parent_title, grandparent_title, thumb, parent_thumb, grandparent_thumb, media_index, parent_media_index, ' \
'year, started, user ' \
'FROM session_history_metadata ' \
'JOIN session_history ON session_history_metadata.id = session_history.id ' \
'WHERE user_id = ? ' \
'GROUP BY (CASE WHEN session_history.media_type = "track" THEN session_history.parent_rating_key ' \
' ELSE session_history.rating_key END) ' \
'ORDER BY started DESC LIMIT ?'
result = monitor_db.select(query, args=[user_id, limit])
else:
result = []
except Exception as e:
logger.warn(u"PlexPy Users :: Unable to execute database query for get_recently_watched: %s." % e)
result = []
for row in result:
if row['media_type'] == 'episode' and row['parent_thumb']:
thumb = row['parent_thumb']
elif row['media_type'] == 'episode':
thumb = row['grandparent_thumb']
else:
thumb = row['thumb']
recent_output = {'row_id': row['id'],
'type': row['media_type'],
'rating_key': row['rating_key'],
'title': row['title'],
'parent_title': row['parent_title'],
'grandparent_title': row['grandparent_title'],
'thumb': thumb,
'media_index': row['media_index'],
'parent_media_index': row['parent_media_index'],
'year': row['year'],
'time': row['started'],
'user': row['user']
}
recently_watched.append(recent_output)
return recently_watched
def delete_all_history(self, user_id=None):
monitor_db = database.MonitorDatabase()
try:
if str(user_id).isdigit():
logger.info(u"PlexPy DataFactory :: Deleting all history for user id %s from database." % user_id)
session_history_media_info_del = \
monitor_db.action('DELETE FROM '
'session_history_media_info '
'WHERE session_history_media_info.id IN (SELECT session_history_media_info.id '
'FROM session_history_media_info '
'JOIN session_history ON session_history_media_info.id = session_history.id '
'WHERE session_history.user_id = ?)', [user_id])
session_history_metadata_del = \
monitor_db.action('DELETE FROM '
'session_history_metadata '
'WHERE session_history_metadata.id IN (SELECT session_history_metadata.id '
'FROM session_history_metadata '
'JOIN session_history ON session_history_metadata.id = session_history.id '
'WHERE session_history.user_id = ?)', [user_id])
session_history_del = \
monitor_db.action('DELETE FROM '
'session_history '
'WHERE session_history.user_id = ?', [user_id])
return 'Deleted all items for user_id %s.' % user_id
else:
return 'Unable to delete items. Input user_id not valid.'
except Exception as e:
logger.warn(u"PlexPy Users :: Unable to execute database query for delete_all_history: %s." % e)
def delete(self, user_id=None):
monitor_db = database.MonitorDatabase()
try:
if str(user_id).isdigit():
self.delete_all_history(user_id)
logger.info(u"PlexPy DataFactory :: Deleting user with id %s from database." % user_id)
monitor_db.action('UPDATE users SET deleted_user = 1 WHERE user_id = ?', [user_id])
monitor_db.action('UPDATE users SET keep_history = 0 WHERE user_id = ?', [user_id])
monitor_db.action('UPDATE users SET do_notify = 0 WHERE user_id = ?', [user_id])
return 'Deleted user with id %s.' % user_id
else:
return 'Unable to delete user, user_id not valid.'
except Exception as e:
logger.warn(u"PlexPy Users :: Unable to execute database query for delete: %s." % e)
def undelete(self, user_id=None, username=None):
monitor_db = database.MonitorDatabase()
try:
if user_id and str(user_id).isdigit():
logger.info(u"PlexPy DataFactory :: Re-adding user with id %s to database." % user_id)
monitor_db.action('UPDATE users SET deleted_user = 0 WHERE user_id = ?', [user_id])
monitor_db.action('UPDATE users SET keep_history = 1 WHERE user_id = ?', [user_id])
monitor_db.action('UPDATE users SET do_notify = 1 WHERE user_id = ?', [user_id])
return 'Re-added user with id %s.' % user_id
elif username:
logger.info(u"PlexPy DataFactory :: Re-adding user with username %s to database." % username)
monitor_db.action('UPDATE users SET deleted_user = 0 WHERE username = ?', [username])
monitor_db.action('UPDATE users SET keep_history = 1 WHERE username = ?', [username])
monitor_db.action('UPDATE users SET do_notify = 1 WHERE username = ?', [username])
return 'Re-added user with username %s.' % username
else:
return 'Unable to re-add user, user_id or username not valid.'
except Exception as e:
logger.warn(u"PlexPy Users :: Unable to execute database query for undelete: %s." % e)
# Keep method for PlexWatch import
def get_user_id(self, user=None):
if user:
try:
monitor_db = database.MonitorDatabase()
query = 'SELECT user_id FROM users WHERE username = ?'
result = monitor_db.select_single(query, args=[user])
if result:
return result['user_id']
else:
return None
except:
return None
return None

File diff suppressed because it is too large Load diff