Cleanup image caching and logs

* Prettier confirm modal dialogues
* Setting to disable image caching
This commit is contained in:
JonnyWong16 2016-05-12 00:04:31 -07:00
parent baf44a97b4
commit e79f6d5617
10 changed files with 505 additions and 352 deletions

549
API.md
View file

@ -70,6 +70,10 @@ Returns:
```
### delete_cache
Delete and recreate the cache directory.
### delete_datatable_media_info_cache
Delete the media info table cache for a specific library.
@ -85,6 +89,10 @@ Returns:
```
### delete_image_cache
Delete and recreate the image cache directory.
### delete_library
Delete a library section from PlexPy. Also erases all history for the library.
@ -138,6 +146,10 @@ Return the api docs as a dict where commands are keys, docstring are value.
Return the api docs formatted with markdown.
### download_log
Download the PlexPy log file.
### edit_library
Update a library section on PlexPy.
@ -189,60 +201,60 @@ Returns:
json:
{"stream_count": 3,
"session":
[{"art": "/library/metadata/1219/art/1462175063",
"aspect_ratio": "1.78",
"audio_channels": "6",
"audio_codec": "ac3",
"audio_decision": "transcode",
"bif_thumb": "/library/parts/274169/indexes/sd/",
"bitrate": "10617",
"container": "mkv",
"content_rating": "TV-MA",
"duration": "2998290",
"friendly_name": "Mother of Dragons",
"grandparent_rating_key": "1219",
"grandparent_thumb": "/library/metadata/1219/thumb/1462175063",
"grandparent_title": "Game of Thrones",
"height": "1078",
"indexes": 1,
"ip_address": "xxx.xxx.xxx.xxx",
"labels": [],
"machine_id": "83f189w617623ccs6a1lqpby",
"media_index": "1",
"media_type": "episode",
"parent_media_index": "6",
"parent_rating_key": "153036",
"parent_thumb": "/library/metadata/153036/thumb/1462175062",
"parent_title": "",
"platform": "Chrome",
"player": "Plex Web (Chrome)",
"progress_percent": "0",
"rating_key": "153037",
"section_id": "2",
"session_key": "291",
"state": "playing",
"throttled": "1",
"thumb": "/library/metadata/153037/thumb/1462175060",
"title": "The Red Woman",
"transcode_audio_channels": "2",
"transcode_audio_codec": "aac",
"transcode_container": "mkv",
"transcode_height": "1078",
"transcode_key": "tiv5p524wcupe8nxegc26s9k9",
"transcode_progress": 2,
"transcode_protocol": "http",
"transcode_speed": "0.0",
"transcode_video_codec": "h264",
"transcode_width": "1920",
"user": "DanyKhaleesi69",
"user_id": 8008135,
"user_thumb": "https://plex.tv/users/568gwwoib5t98a3a/avatar",
"video_codec": "h264",
"video_decision": "copy",
"video_framerate": "24p",
"video_resolution": "1080",
"view_offset": "",
"width": "1920",
[{"art": "/library/metadata/1219/art/1462175063",
"aspect_ratio": "1.78",
"audio_channels": "6",
"audio_codec": "ac3",
"audio_decision": "transcode",
"bif_thumb": "/library/parts/274169/indexes/sd/",
"bitrate": "10617",
"container": "mkv",
"content_rating": "TV-MA",
"duration": "2998290",
"friendly_name": "Mother of Dragons",
"grandparent_rating_key": "1219",
"grandparent_thumb": "/library/metadata/1219/thumb/1462175063",
"grandparent_title": "Game of Thrones",
"height": "1078",
"indexes": 1,
"ip_address": "xxx.xxx.xxx.xxx",
"labels": [],
"machine_id": "83f189w617623ccs6a1lqpby",
"media_index": "1",
"media_type": "episode",
"parent_media_index": "6",
"parent_rating_key": "153036",
"parent_thumb": "/library/metadata/153036/thumb/1462175062",
"parent_title": "",
"platform": "Chrome",
"player": "Plex Web (Chrome)",
"progress_percent": "0",
"rating_key": "153037",
"section_id": "2",
"session_key": "291",
"state": "playing",
"throttled": "1",
"thumb": "/library/metadata/153037/thumb/1462175060",
"title": "The Red Woman",
"transcode_audio_channels": "2",
"transcode_audio_codec": "aac",
"transcode_container": "mkv",
"transcode_height": "1078",
"transcode_key": "tiv5p524wcupe8nxegc26s9k9",
"transcode_progress": 2,
"transcode_protocol": "http",
"transcode_speed": "0.0",
"transcode_video_codec": "h264",
"transcode_width": "1920",
"user": "DanyKhaleesi69",
"user_id": 8008135,
"user_thumb": "https://plex.tv/users/568gwwoib5t98a3a/avatar",
"video_codec": "h264",
"video_decision": "copy",
"video_framerate": "24p",
"video_resolution": "1080",
"view_offset": "",
"width": "1920",
"year": "2016"
},
{...},
@ -381,22 +393,22 @@ Returns:
{"stat_id": "top_tv",
"stat_type": "total_plays",
"rows":
[{"content_rating": "TV-MA",
"friendly_name": "",
"grandparent_thumb": "/library/metadata/1219/thumb/1462175063",
"labels": [],
"last_play": 1462380698,
"media_type": "episode",
"platform": "",
"platform_type": "",
"rating_key": 1219,
"row_id": 1116,
"section_id": 2,
"thumb": "",
"title": "Game of Thrones",
"total_duration": 213302,
"total_plays": 69,
"user": "",
[{"content_rating": "TV-MA",
"friendly_name": "",
"grandparent_thumb": "/library/metadata/1219/thumb/1462175063",
"labels": [],
"last_play": 1462380698,
"media_type": "episode",
"platform": "",
"platform_type": "",
"rating_key": 1219,
"row_id": 1116,
"section_id": 2,
"thumb": "",
"title": "Game of Thrones",
"total_duration": 213302,
"total_plays": 69,
"user": "",
"users_watched": ""
},
{...},
@ -443,13 +455,13 @@ Optional parameters:
Returns:
json:
[{"art": "/:/resources/show-fanart.jpg",
"child_count": "3745",
"count": "62",
"parent_count": "240",
[{"art": "/:/resources/show-fanart.jpg",
"child_count": "3745",
"count": "62",
"parent_count": "240",
"section_id": "2",
"section_name": "TV Shows",
"section_type": "show",
"section_name": "TV Shows",
"section_type": "show",
"thumb": "/:/resources/show.png"
},
{...},
@ -479,30 +491,30 @@ Returns:
"recordsTotal": 10,
"recordsFiltered": 10,
"data":
[{"child_count": 3745,
"content_rating": "TV-MA",
"count": 62,
"do_notify": "Checked",
"do_notify_created": "Checked",
"duration": 1578037,
"id": 1128,
"keep_history": "Checked",
"labels": [],
"last_accessed": 1462693216,
"last_played": "Game of Thrones - The Red Woman",
"library_art": "/:/resources/show-fanart.jpg",
"library_thumb": "",
"media_index": 1,
"media_type": "episode",
"parent_count": 240,
"parent_media_index": 6,
"parent_title": "",
"plays": 772,
"rating_key": 153037,
"section_id": 2,
"section_name": "TV Shows",
"section_type": "Show",
"thumb": "/library/metadata/153036/thumb/1462175062",
[{"child_count": 3745,
"content_rating": "TV-MA",
"count": 62,
"do_notify": "Checked",
"do_notify_created": "Checked",
"duration": 1578037,
"id": 1128,
"keep_history": "Checked",
"labels": [],
"last_accessed": 1462693216,
"last_played": "Game of Thrones - The Red Woman",
"library_art": "/:/resources/show-fanart.jpg",
"library_thumb": "",
"media_index": 1,
"media_type": "episode",
"parent_count": 240,
"parent_media_index": 6,
"parent_title": "",
"plays": 772,
"rating_key": 153037,
"section_id": 2,
"section_name": "TV Shows",
"section_type": "Show",
"thumb": "/library/metadata/153036/thumb/1462175062",
"year": 2016
},
{...},
@ -538,27 +550,27 @@ Returns:
"filtered_file_size": 2616760056742,
"total_file_size": 2616760056742,
"data":
[{"added_at": "1403553078",
"audio_channels": "",
"audio_codec": "",
"bitrate": "",
"container": "",
"file_size": 253660175293,
"grandparent_rating_key": "",
"last_played": 1462380698,
"media_index": "1",
"media_type": "show",
"parent_media_index": "",
"parent_rating_key": "",
"play_count": 15,
"rating_key": "1219",
"section_id": 2,
"section_type": "show",
"thumb": "/library/metadata/1219/thumb/1436265995",
"title": "Game of Thrones",
"video_codec": "",
"video_framerate": "",
"video_resolution": "",
[{"added_at": "1403553078",
"audio_channels": "",
"audio_codec": "",
"bitrate": "",
"container": "",
"file_size": 253660175293,
"grandparent_rating_key": "",
"last_played": 1462380698,
"media_index": "1",
"media_type": "show",
"parent_media_index": "",
"parent_rating_key": "",
"play_count": 15,
"rating_key": "1219",
"section_id": 2,
"section_type": "show",
"thumb": "/library/metadata/1219/thumb/1436265995",
"title": "Game of Thrones",
"video_codec": "",
"video_framerate": "",
"video_resolution": "",
"year": "2011"
},
{...},
@ -631,51 +643,51 @@ Returns:
json:
{"metadata":
{"actors": [
"Kit Harington",
"Emilia Clarke",
"Isaac Hempstead-Wright",
"Maisie Williams",
"Liam Cunningham",
],
"added_at": "1461572396",
"art": "/library/metadata/1219/art/1462175063",
"content_rating": "TV-MA",
"Kit Harington",
"Emilia Clarke",
"Isaac Hempstead-Wright",
"Maisie Williams",
"Liam Cunningham",
],
"added_at": "1461572396",
"art": "/library/metadata/1219/art/1462175063",
"content_rating": "TV-MA",
"directors": [
"Jeremy Podeswa"
],
"duration": "2998290",
],
"duration": "2998290",
"genres": [
"Adventure",
"Drama",
"Adventure",
"Drama",
"Fantasy"
],
"grandparent_rating_key": "1219",
"grandparent_thumb": "/library/metadata/1219/thumb/1462175063",
"grandparent_title": "Game of Thrones",
"guid": "com.plexapp.agents.thetvdb://121361/6/1?lang=en",
"labels": [],
"last_viewed_at": "1462165717",
"library_name": "TV Shows",
"media_index": "1",
"media_type": "episode",
"originally_available_at": "2016-04-24",
"parent_media_index": "6",
"parent_rating_key": "153036",
"parent_thumb": "/library/metadata/153036/thumb/1462175062",
"parent_title": "",
"rating": "7.8",
"rating_key": "153037",
"section_id": "2",
"studio": "HBO",
"summary": "Jon Snow is dead. Daenerys meets a strong man. Cersei sees her daughter again.",
"tagline": "",
"thumb": "/library/metadata/153037/thumb/1462175060",
"title": "The Red Woman",
"updated_at": "1462175060",
],
"grandparent_rating_key": "1219",
"grandparent_thumb": "/library/metadata/1219/thumb/1462175063",
"grandparent_title": "Game of Thrones",
"guid": "com.plexapp.agents.thetvdb://121361/6/1?lang=en",
"labels": [],
"last_viewed_at": "1462165717",
"library_name": "TV Shows",
"media_index": "1",
"media_type": "episode",
"originally_available_at": "2016-04-24",
"parent_media_index": "6",
"parent_rating_key": "153036",
"parent_thumb": "/library/metadata/153036/thumb/1462175062",
"parent_title": "",
"rating": "7.8",
"rating_key": "153037",
"section_id": "2",
"studio": "HBO",
"summary": "Jon Snow is dead. Daenerys meets a strong man. Cersei sees her daughter again.",
"tagline": "",
"thumb": "/library/metadata/153037/thumb/1462175060",
"title": "The Red Woman",
"updated_at": "1462175060",
"writers": [
"David Benioff",
"David Benioff",
"D. B. Weiss"
],
],
"year": "2016"
}
}
@ -720,20 +732,20 @@ Returns:
"recordsTotal": 1039,
"recordsFiltered": 163,
"data":
[{"agent_id": 13,
"agent_name": "Telegram",
"body_text": "Game of Thrones - S06E01 - The Red Woman [Transcode].",
"id": 1000,
"notify_action": "play",
"poster_url": "http://i.imgur.com/ZSqS8Ri.jpg",
"rating_key": 153037,
"script_args": "[]",
"session_key": 147,
"subject_text": "PlexPy (Winterfell-Server)",
"timestamp": 1462253821,
"user": "DanyKhaleesi69",
[{"agent_id": 13,
"agent_name": "Telegram",
"body_text": "Game of Thrones - S06E01 - The Red Woman [Transcode].",
"id": 1000,
"notify_action": "play",
"poster_url": "http://i.imgur.com/ZSqS8Ri.jpg",
"rating_key": 153037,
"script_args": "[]",
"session_key": 147,
"subject_text": "PlexPy (Winterfell-Server)",
"timestamp": 1462253821,
"user": "DanyKhaleesi69",
"user_id": 8008135
},
},
{...},
{...}
]
@ -996,8 +1008,8 @@ Optional parameters:
Returns:
json:
[["May 08, 2016 09:35:37",
"DEBUG",
[["May 08, 2016 09:35:37",
"DEBUG",
"Auth: Came in with a super-token, authorization succeeded."
],
[...],
@ -1019,21 +1031,21 @@ Optional parameters:
Returns:
json:
{"recently_added":
[{"added_at": "1461572396",
"grandparent_rating_key": "1219",
"grandparent_thumb": "/library/metadata/1219/thumb/1462175063",
"grandparent_title": "Game of Thrones",
"library_name": "",
"media_index": "1",
"media_type": "episode",
"parent_media_index": "6",
"parent_rating_key": "153036",
"parent_thumb": "/library/metadata/153036/thumb/1462175062",
"parent_title": "",
"rating_key": "153037",
"section_id": "2",
"thumb": "/library/metadata/153037/thumb/1462175060",
"title": "The Red Woman",
[{"added_at": "1461572396",
"grandparent_rating_key": "1219",
"grandparent_thumb": "/library/metadata/1219/thumb/1462175063",
"grandparent_title": "Game of Thrones",
"library_name": "",
"media_index": "1",
"media_type": "episode",
"parent_media_index": "6",
"parent_rating_key": "153036",
"parent_thumb": "/library/metadata/153036/thumb/1462175062",
"parent_title": "",
"rating_key": "153037",
"section_id": "2",
"thumb": "/library/metadata/153037/thumb/1462175060",
"title": "The Red Woman",
"year": "2016"
},
{...},
@ -1108,12 +1120,12 @@ Optional parameters:
Returns:
json:
[{"clientIdentifier": "ds48g4r354a8v9byrrtr697g3g79w",
"httpsRequired": "0",
"ip": "xxx.xxx.xxx.xxx",
"label": "Winterfell-Server",
"local": "1",
"port": "32400",
[{"clientIdentifier": "ds48g4r354a8v9byrrtr697g3g79w",
"httpsRequired": "0",
"ip": "xxx.xxx.xxx.xxx",
"label": "Winterfell-Server",
"local": "1",
"port": "32400",
"value": "xxx.xxx.xxx.xxx"
},
{...},
@ -1237,26 +1249,26 @@ Optional parameters:
Returns:
json:
[{"content_type": "video",
"device_name": "Tyrion's iPad",
"failure": "",
"friendly_name": "Tyrion Lannister",
"item_complete_count": "0",
"item_count": "1",
"item_downloaded_count": "0",
"item_downloaded_percent_complete": 0,
"metadata_type": "movie",
"music_bitrate": "192",
"photo_quality": "74",
"platform": "iOS",
"rating_key": "154092",
"root_title": "Deadpool",
"state": "pending",
"sync_id": "11617019",
"title": "Deadpool",
"total_size": "0",
"user_id": "328871",
"username": "DrukenDwarfMan",
[{"content_type": "video",
"device_name": "Tyrion's iPad",
"failure": "",
"friendly_name": "Tyrion Lannister",
"item_complete_count": "0",
"item_count": "1",
"item_downloaded_count": "0",
"item_downloaded_percent_complete": 0,
"metadata_type": "movie",
"music_bitrate": "192",
"photo_quality": "74",
"platform": "iOS",
"rating_key": "154092",
"root_title": "Deadpool",
"state": "pending",
"sync_id": "11617019",
"title": "Deadpool",
"total_size": "0",
"user_id": "328871",
"username": "DrukenDwarfMan",
"video_quality": "60"
},
{...},
@ -1286,24 +1298,24 @@ Returns:
"recordsTotal": 2344,
"recordsFiltered": 10,
"data":
[{"friendly_name": "Jon Snow",
"id": 1121,
"ip_address": "xxx.xxx.xxx.xxx",
"last_played": "Game of Thrones - The Red Woman",
"last_seen": 1462591869,
"media_index": 1,
"media_type": "episode",
"parent_media_index": 6,
"parent_title": "",
"platform": "Chrome",
"play_count": 149,
"player": "Plex Web (Chrome)",
"rating_key": 153037,
"thumb": "/library/metadata/153036/thumb/1462175062",
"transcode_decision": "transcode",
"user_id": 328871,
[{"friendly_name": "Jon Snow",
"id": 1121,
"ip_address": "xxx.xxx.xxx.xxx",
"last_played": "Game of Thrones - The Red Woman",
"last_seen": 1462591869,
"media_index": 1,
"media_type": "episode",
"parent_media_index": 6,
"parent_title": "",
"platform": "Chrome",
"play_count": 149,
"player": "Plex Web (Chrome)",
"rating_key": 153037,
"thumb": "/library/metadata/153036/thumb/1462175062",
"transcode_decision": "transcode",
"user_id": 328871,
"year": 2016
},
},
{...},
{...}
]
@ -1343,17 +1355,17 @@ Optional parameters:
Returns:
json:
[{"email": "Jon.Snow.1337@CastleBlack.com",
"filter_all": "",
"filter_movies": "",
"filter_music": "",
"filter_photos": "",
"filter_tv": "",
"is_allow_sync": null,
"is_home_user": "1",
"is_restricted": "0",
"thumb": "https://plex.tv/users/k10w42309cynaopq/avatar",
"user_id": "328871",
[{"email": "Jon.Snow.1337@CastleBlack.com",
"filter_all": "",
"filter_movies": "",
"filter_music": "",
"filter_photos": "",
"filter_tv": "",
"is_allow_sync": null,
"is_home_user": "1",
"is_restricted": "0",
"thumb": "https://plex.tv/users/k10w42309cynaopq/avatar",
"user_id": "328871",
"username": "Jon Snow"
},
{...},
@ -1383,29 +1395,29 @@ Returns:
"recordsTotal": 10,
"recordsFiltered": 10,
"data":
[{"allow_guest": "Checked",
"do_notify": "Checked",
"duration": 2998290,
"friendly_name": "Jon Snow",
"id": 1121,
"ip_address": "xxx.xxx.xxx.xxx",
"keep_history": "Checked",
"last_played": "Game of Thrones - The Red Woman",
"last_seen": 1462591869,
"media_index": 1,
"media_type": "episode",
"parent_media_index": 6,
"parent_title": "",
"platform": "Chrome",
"player": "Plex Web (Chrome)",
"plays": 487,
"rating_key": 153037,
"thumb": "/library/metadata/153036/thumb/1462175062",
"transcode_decision": "transcode",
"user_id": 328871,
"user_thumb": "https://plex.tv/users/568gwwoib5t98a3a/avatar",
[{"allow_guest": "Checked",
"do_notify": "Checked",
"duration": 2998290,
"friendly_name": "Jon Snow",
"id": 1121,
"ip_address": "xxx.xxx.xxx.xxx",
"keep_history": "Checked",
"last_played": "Game of Thrones - The Red Woman",
"last_seen": 1462591869,
"media_index": 1,
"media_type": "episode",
"parent_media_index": 6,
"parent_title": "",
"platform": "Chrome",
"player": "Plex Web (Chrome)",
"plays": 487,
"rating_key": 153037,
"thumb": "/library/metadata/153036/thumb/1462175062",
"transcode_decision": "transcode",
"user_id": 328871,
"user_thumb": "https://plex.tv/users/568gwwoib5t98a3a/avatar",
"year": 2016
},
},
{...},
{...}
]
@ -1467,7 +1479,7 @@ Required parameters:
Returns:
json:
{"results_count": 69,
{"results_count": 69,
"results_list":
{"movie":
[{...},
@ -1553,4 +1565,5 @@ Optional parameters:
Returns:
None
```
```

View file

@ -244,6 +244,25 @@
</nav>
</div>
<div id="confirm-modal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="confirm-modal">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true"><i class="fa fa-remove"></i></button>
<h4 class="modal-title">Confirm</h4>
</div>
<div class="modal-body">
<div id="confirm-message" style="text-align: center; margin-top: 20px; margin-bottom: 20px;">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-dark" data-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-danger btn-ok" data-dismiss="modal" id="confirm-button">Confirm</button>
</div>
</div>
</div>
</div>
% if _session['user_group'] != 'admin':
<div id="admin-login-modal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="admin-login-modal">
<div class="modal-dialog" role="document">
@ -310,18 +329,20 @@ ${next.headerIncludes()}
$('#updatebar').show();
}
$("#nav-shutdown").click(function () {
var r = confirm("Are you sure you want to shutdown PlexPy?");
if (r == true) {
$("#nav-shutdown").click(function() {
$("#confirm-message").text("Are you sure you want to shutdown PlexPy?");
$('#confirm-modal').modal();
$('#confirm-modal').one('click', '#confirm-button', function () {
window.location.href = "shutdown";
}
});
});
$("#nav-restart").click(function () {
var r = confirm("Are you sure you want to restart PlexPy?");
if (r == true) {
$("#nav-restart").click(function() {
$("#confirm-message").text("Are you sure you want to restart PlexPy?");
$('#confirm-modal').modal();
$('#confirm-modal').one('click', '#confirm-button', function () {
window.location.href = "restart";
}
});
});
$("#nav-update").first().one("click", function () {

View file

@ -22,8 +22,8 @@
</div>
<div class="button-bar">
<button class="btn btn-dark" id="download-plexpylog"><i class="fa fa-download"></i> Download log</button>
<button class="btn btn-dark" id="clear-logs"><i class="fa fa-trash-o"></i> Clear log</button>
<button class="btn btn-dark" id="clear-notify-logs" style="display: none;"><i class="fa fa-trash-o"></i> Clear log</button>
<button class="btn btn-dark" id="clear-logs"><i class="fa fa-trash-o"></i> Clear logs</button>
<button class="btn btn-dark" id="clear-notify-logs" style="display: none;"><i class="fa fa-trash-o"></i> Clear logs</button>
</div>
</div>
<div class='table-card-back'>
@ -189,10 +189,24 @@
});
$("#clear-logs").click(function () {
var r = confirm("Are you sure you want to clear the PlexPy log?");
if (r == true) {
window.location.href = "clearLogs";
}
$("#confirm-message").text("Are you sure you want to clear the PlexPy logs?");
$('#confirm-modal').modal();
$('#confirm-modal').one('click', '#confirm-button', function () {
$.ajax({
url: 'delete_logs',
type: 'POST',
complete: function (xhr, status) {
result = $.parseJSON(xhr.responseText);
msg = result.message;
if (result.result == 'success') {
showMsg('<i class="fa fa-check"></i> ' + msg, false, true, 5000)
} else {
showMsg('<i class="fa fa-times"></i> ' + msg, false, true, 5000, true)
}
log_table.draw();
}
});
});
});
$("#download-plexpylog").click(function () {
@ -201,16 +215,24 @@
$("#clear-notify-logs").click(function () {
var r = confirm("Are you sure you want to clear the PlexPy notification log?");
if (r == true) {
$("#confirm-message").text("Are you sure you want to clear the PlexPy notification logs?");
$('#confirm-modal').modal();
$('#confirm-modal').one('click', '#confirm-button', function () {
$.ajax({
url: 'delete_notification_log',
type: 'POST',
success: function (data) {
complete: function (xhr, status) {
result = $.parseJSON(xhr.responseText);
msg = result.message;
if (result.result == 'success') {
showMsg('<i class="fa fa-check"></i> ' + msg, false, true, 5000)
} else {
showMsg('<i class="fa fa-times"></i> ' + msg, false, true, 5000, true)
}
notification_log_table.draw();
}
});
}
});
});
var timer;

View file

@ -4,7 +4,7 @@
import sys
import plexpy
from plexpy import common, notifiers, versioncheck
from plexpy import common, logger, notifiers, versioncheck
from plexpy.helpers import anon_url
available_notification_agents = sorted(notifiers.available_notification_agents(), key=lambda k: k['name'])
@ -84,7 +84,7 @@
</tr>
<tr>
<td>Log File:</td>
<td><a class="no-highlight" href="logFile" target="_blank">${os.path.join(config['log_dir'],'plexpy.log')}</a></td>
<td><a class="no-highlight" href="logFile" target="_blank">${os.path.join(config['log_dir'], logger.FILENAME)}</a></td>
</tr>
<tr>
<td>Backup Directory:</td>
@ -198,24 +198,39 @@
<div class="form-group">
<label for="backup_dir">Backup Directory</label>
<div class="row">
<div class="col-md-6">
<input type="text" class="form-control directory-settings" id="backup_dir" name="backup_dir" value="${config['backup_dir']}">
<div class="col-md-8">
<div class="input-group">
<input type="text" class="form-control directory-settings" id="backup_dir" name="backup_dir" value="${config['backup_dir']}">
<span class="input-group-btn">
<button class="btn btn-form" type="button" id="backup_database">Backup Database</button>
</span>
</div>
</div>
</div>
</div>
<div class="form-group">
<label for="cache_dir">Cache Directory</label>
<div class="row">
<div class="col-md-6">
<input type="text" class="form-control directory-settings" id="cache_dir" name="cache_dir" value="${config['cache_dir']}">
<div class="col-md-8">
<div class="input-group">
<input type="text" class="form-control directory-settings" id="cache_dir" name="cache_dir" value="${config['cache_dir']}">
<span class="input-group-btn">
<button class="btn btn-form" type="button" id="clear_cache">Clear Cache</button>
</span>
</div>
</div>
</div>
</div>
<div class="form-group">
<label for="log_dir">Log Directory</label>
<div class="row">
<div class="col-md-6">
<input type="text" class="form-control directory-settings" id="log_dir" name="log_dir" value="${config['log_dir']}">
<div class="col-md-8">
<div class="input-group">
<input type="text" class="form-control directory-settings" id="log_dir" name="log_dir" value="${config['log_dir']}">
<span class="input-group-btn">
<button class="btn btn-form" type="button" id="clear_logs">Clear Logs</button>
</span>
</div>
</div>
</div>
</div>
@ -724,6 +739,14 @@
Note: Only logs from the time this setting is enabled will be masked. Do not post your logs publically without masking sensitive information!
</p>
</div>
<div class="checkbox">
<label>
<input type="checkbox" id="cache_images" name="cache_images" value="1" ${config['cache_images']}> Cache Plex Images
</label>
<p class="help-block">
Enable to cache images from Plex to reduce API calls and improve loading times.
</p>
</div>
<div class="form-group">
<label for="anon_redirect">Anonymous Redirect</label>
<div class="row">
@ -2056,7 +2079,7 @@ $(document).ready(function() {
postSaveChecks();
return false;
} else {
showMsg('<i class="fa fa-exclamation-circle"></i>&nbspPlease verify your settings.', false, true, 2000, true)
showMsg('<i class="fa fa-exclamation-circle"></i> Please verify your settings.', false, true, 5000, true)
}
}
@ -2069,17 +2092,19 @@ $(document).ready(function() {
});
$("#menu_link_shutdown").click(function() {
var r = confirm("Are you sure you want to shutdown PlexPy?");
if (r == true) {
$("#confirm-message").text("Are you sure you want to shutdown PlexPy?");
$('#confirm-modal').modal();
$('#confirm-modal').one('click', '#confirm-button', function () {
window.location.href = "shutdown";
}
});
});
$("#menu_link_restart").click(function() {
var r = confirm("Are you sure you want to restart PlexPy?");
if (r == true) {
$("#confirm-message").text("Are you sure you want to restart PlexPy?");
$('#confirm-modal').modal();
$('#confirm-modal').one('click', '#confirm-button', function () {
window.location.href = "restart";
}
});
});
$("#menu_link_update_check").click(function() {
@ -2094,6 +2119,66 @@ $(document).ready(function() {
window.location.href = "restart";
});
$("#backup_database").click(function () {
$("#confirm-message").text("Are you sure you want to create a backup of the PlexPy database?");
$('#confirm-modal').modal();
$('#confirm-modal').one('click', '#confirm-button', function () {
$.ajax({
url: 'backup_db',
type: 'POST',
complete: function (xhr, status) {
result = $.parseJSON(xhr.responseText);
msg = result.message;
if (result.result == 'success') {
showMsg('<i class="fa fa-check"></i> ' + msg, false, true, 5000)
} else {
showMsg('<i class="fa fa-times"></i> ' + msg, false, true, 5000, true)
}
}
});
});
});
$("#clear_cache").click(function () {
$("#confirm-message").text("Are you sure you want to clear the PlexPy cache?");
$('#confirm-modal').modal();
$('#confirm-modal').one('click', '#confirm-button', function () {
$.ajax({
url: 'delete_cache',
type: 'POST',
complete: function (xhr, status) {
result = $.parseJSON(xhr.responseText);
msg = result.message;
if (result.result == 'success') {
showMsg('<i class="fa fa-check"></i> ' + msg, false, true, 5000)
} else {
showMsg('<i class="fa fa-times"></i> ' + msg, false, true, 5000, true)
}
}
});
});
});
$("#clear_logs").click(function () {
$("#confirm-message").text("Are you sure you want to clear the PlexPy logs?");
$('#confirm-modal').modal();
$('#confirm-modal').one('click', '#confirm-button', function () {
$.ajax({
url: 'delete_logs',
type: 'POST',
complete: function (xhr, status) {
result = $.parseJSON(xhr.responseText);
msg = result.message;
if (result.result == 'success') {
showMsg('<i class="fa fa-check"></i> ' + msg, false, true, 5000)
} else {
showMsg('<i class="fa fa-times"></i> ' + msg, false, true, 5000, true)
}
}
});
});
});
if ($("#api_enabled").is(":checked")) {
$("#apioptions").show();
} else {
@ -2235,7 +2320,7 @@ $(document).ready(function() {
$("#pms-verify").html('<i class="fa fa-close"></i>');
$('#pms-verify').fadeIn('fast');
$("#pms-ip-group").addClass("has-error");
showMsg('<i class="fa fa-exclamation-circle"></i>&nbspCould not verify your server.', false, true, 2000, true)
showMsg('<i class="fa fa-exclamation-circle"></i> Could not verify your server.', false, true, 5000, true)
}
}
});
@ -2243,7 +2328,7 @@ $(document).ready(function() {
$("#pms-verify").html('<i class="fa fa-close"></i>');
$('#pms-verify').fadeIn('fast');
$("#pms-ip-group").addClass("has-error");
showMsg('<i class="fa fa-exclamation-circle"></i>&nbspCould not verify your server.', false, true, 2000, true)
showMsg('<i class="fa fa-exclamation-circle"></i> Could not verify your server.', false, true, 5000, true)
}
}
@ -2326,7 +2411,7 @@ $(document).ready(function() {
$('#osxnotifyregister').click(function () {
var osx_notify_app = $("#osx_notify_reg").val();
$.get("/osxnotifyregister", { 'app': osx_notify_app }, function (data) { showMsg("<div class='msg'><span class='ui-icon ui-icon-check'></span>" + data + "</div>", false, true, 3000); });
$.get("/osxnotifyregister", { 'app': osx_notify_app }, function (data) { showMsg("<div class='msg'><span class='fa fa-check'></span>" + data + "</div>", false, true, 3000); });
})
pms_version = false;

View file

@ -214,7 +214,7 @@ class Api(object):
}
]
"""
logfile = os.path.join(plexpy.CONFIG.LOG_DIR, 'plexpy.log')
logfile = os.path.join(plexpy.CONFIG.LOG_DIR, logger.FILENAME)
templog = []
start = int(kwargs.get('start', 0))
end = int(kwargs.get('end', 0))

View file

@ -148,7 +148,7 @@ class API2:
```
"""
logfile = os.path.join(plexpy.CONFIG.LOG_DIR, 'plexpy.log')
logfile = os.path.join(plexpy.CONFIG.LOG_DIR, logger.FILENAME)
templog = []
start = int(kwargs.get('start', 0))
end = int(kwargs.get('end', 0))

View file

@ -86,6 +86,7 @@ _CONFIG_DEFINITIONS = {
'BUFFER_WAIT': (int, 'Monitoring', 900),
'BACKUP_DIR': (str, 'General', ''),
'CACHE_DIR': (str, 'General', ''),
'CACHE_IMAGES': (int, 'General', 1),
'CACHE_SIZEMB': (int, 'Advanced', 32),
'CHECK_GITHUB': (int, 'General', 1),
'CHECK_GITHUB_INTERVAL': (int, 'General', 360),

View file

@ -1301,7 +1301,7 @@ class DataFactory(object):
logger.info(u"PlexPy DataFactory :: Clearing notification logs from database.")
monitor_db.action('DELETE FROM notify_log')
monitor_db.action('VACUUM')
return 'Cleared notification logs.'
return True
except Exception as e:
logger.warn(u"PlexPy DataFactory :: Unable to execute database query for delete_notification_log: %s." % e)
return 'Unable to clear notification logs.'
return False

View file

@ -1917,7 +1917,7 @@ class PmsConnect(object):
return result[0], result[1]
else:
logger.error(u"PlexPy Pmsconnect :: Image proxy queries but no input received.")
logger.error(u"PlexPy Pmsconnect :: Image proxy queried but no input received.")
def get_search_results(self, query=''):
"""

View file

@ -1948,17 +1948,9 @@ class WebInterface(object):
if 'search[regex]' in kwargs:
search_regex = kwargs.get('search[regex]', "")
def oh_i_feel_so_dirty(s):
""" Really inefficient helper to only allow one pre tag,
atleast it better then regex..
"""
s = s.encode('utf-8').replace('<pre>', '').replace('</pre>', '')
s = '<pre>%s</pre>' % s
return s
filt = []
fa = filt.append
with open(os.path.join(plexpy.CONFIG.LOG_DIR, 'plexpy.log')) as f:
with open(os.path.join(plexpy.CONFIG.LOG_DIR, logger.FILENAME)) as f:
for l in f.readlines():
try:
temp_loglevel_and_time = l.split('- ')
@ -1966,11 +1958,11 @@ class WebInterface(object):
msg = l.split(' : ')[1].replace('\n', '')
fa([temp_loglevel_and_time[0], loglvl, msg])
except IndexError:
# Add traceback message to previous msg..
# Add traceback message to previous msg.
tl = (len(filt) - 1)
filt[tl][2] += ' ' + l
# Inject the pre tag since we only want it on tracebacks
filt[tl][2] = oh_i_feel_so_dirty(filt[tl][2])
n = len(l) - len(l.lstrip(' '))
l = '&nbsp;' * (2*n) + l[n:]
filt[tl][2] += '<br>' + l
continue
filtered = []
@ -2112,20 +2104,27 @@ class WebInterface(object):
"""
data_factory = datafactory.DataFactory()
result = data_factory.delete_notification_log()
result = result if result else 'no data received'
res = 'success' if result else 'error'
msg = 'Cleared notification logs.' if result else 'Failed to clear notification logs.'
return {'message': result}
return {'result': res, 'message': msg}
@cherrypy.expose
@cherrypy.tools.json_out()
@requireAuth(member_of("admin"))
def clearLogs(self):
def delete_logs(self):
log_file = logger.FILENAME
try:
open(os.path.join(plexpy.CONFIG.LOG_DIR, 'plexpy.log'), 'w').close()
open(os.path.join(plexpy.CONFIG.LOG_DIR, log_file), 'w').close()
result = 'success'
msg = 'Cleared the %s file.' % log_file
logger.info(msg)
except Exception as e:
logger.exception(u'Failed to delete plexpy.log %s' % e)
result = 'error'
msg = 'Failed to clear the %s file.' % log_file
logger.exception(u'Failed to clear the %s file: %s.' % (log_file, e))
logger.info(u'plexpy.log cleared')
raise cherrypy.HTTPRedirect("logs")
return {'result': result, 'message': msg}
@cherrypy.expose
@requireAuth(member_of("admin"))
@ -2151,7 +2150,7 @@ class WebInterface(object):
@requireAuth(member_of("admin"))
def logFile(self):
try:
with open(os.path.join(plexpy.CONFIG.LOG_DIR, 'plexpy.log'), 'r') as f:
with open(os.path.join(plexpy.CONFIG.LOG_DIR, logger.FILENAME), 'r') as f:
return '<pre>%s</pre>' % f.read()
except IOError as e:
return "Log file not found."
@ -2282,7 +2281,8 @@ class WebInterface(object):
"buffer_wait": plexpy.CONFIG.BUFFER_WAIT,
"group_history_tables": checked(plexpy.CONFIG.GROUP_HISTORY_TABLES),
"git_token": plexpy.CONFIG.GIT_TOKEN,
"imgur_client_id": plexpy.CONFIG.IMGUR_CLIENT_ID
"imgur_client_id": plexpy.CONFIG.IMGUR_CLIENT_ID,
"cache_images": checked(plexpy.CONFIG.CACHE_IMAGES)
}
return serve_template(templatename="settings.html", title="Settings", config=config)
@ -2304,7 +2304,7 @@ class WebInterface(object):
"ip_logging_enable", "movie_logging_enable", "tv_logging_enable", "music_logging_enable",
"notify_consecutive", "notify_upload_posters", "notify_recently_added", "notify_recently_added_grandparent",
"monitor_pms_updates", "monitor_remote_access", "get_file_sizes", "log_blacklist", "http_hash_password",
"allow_guest_access"
"allow_guest_access", "cache_images"
]
for checked_config in checked_configs:
if checked_config not in kwargs:
@ -2443,9 +2443,9 @@ class WebInterface(object):
result = database.make_backup()
if result:
return {'message': 'Database backup successful.'}
return {'result': 'success', 'message': 'Database backup successful.'}
else:
return {'message': 'Database backup failed.'}
return {'result': 'error', 'message': 'Database backup failed.'}
@cherrypy.expose
@requireAuth(member_of("admin"))
@ -2834,15 +2834,15 @@ class WebInterface(object):
@cherrypy.expose
@requireAuth()
def pms_image_proxy(self, img='', ratingkey=None, width='0', height='0', fallback=None, **kwargs):
""" Grabs the images from pms and saved them to disk """
def pms_image_proxy(self, img='', rating_key=None, width='0', height='0', fallback=None, **kwargs):
""" Gets an image from the PMS and saves it to the image cache directory. """
if not img and not ratingkey:
logger.debug('No image input received')
if not img and not rating_key:
logger.error('No image input received.')
return
if ratingkey and not img:
img = '/library/metadata/%s/thumb/1337' % ratingkey
if rating_key and not img:
img = '/library/metadata/%s/thumb/1337' % rating_key
img_string = img.rsplit('/', 1)[0]
img_string += '%s%s' % (width, height)
@ -2867,7 +2867,7 @@ class WebInterface(object):
if result and result[0]:
cherrypy.response.headers['Content-type'] = result[1]
if 'indexes' not in img:
if plexpy.CONFIG.CACHE_IMAGES and 'indexes' not in img:
with open(ffp, 'wb') as f:
f.write(result[0])
@ -2876,7 +2876,7 @@ class WebInterface(object):
raise
except Exception as e:
logger.debug('Failed to get image %s file %s falling back to %s' % (img, fp, e))
logger.exception(u'Failed to get image %s, falling back to %s.' % (img, fallback))
fbi = None
if fallback == 'poster':
fbi = common.DEFAULT_POSTER_THUMB
@ -2894,38 +2894,49 @@ class WebInterface(object):
@requireAuth(member_of("admin"))
@addtoapi()
def download_log(self):
""" Download the PlexPy log file. """
log_file = logger.FILENAME
try:
logger.logger.flush()
except:
pass
return serve_download(os.path.join(plexpy.CONFIG.LOG_DIR, 'plexpy.log'), name='plexpy.log')
return serve_download(os.path.join(plexpy.CONFIG.LOG_DIR, log_file), name=log_file)
@cherrypy.expose
@cherrypy.tools.json_out()
@requireAuth(member_of("admin"))
@addtoapi()
def delete_image_cache(self):
""" Deletes the image cache dir and recreates it """
cache_dir = os.path.join(plexpy.CONFIG.CACHE_DIR, 'images')
""" Delete and recreate the image cache directory. """
return self.delete_cache(folder='images')
@cherrypy.expose
@cherrypy.tools.json_out()
@requireAuth(member_of("admin"))
@addtoapi()
def delete_cache(self, folder=''):
""" Delete and recreate the cache directory. """
cache_dir = os.path.join(plexpy.CONFIG.CACHE_DIR, folder)
result = 'success'
msg = 'Deleted your cache images'
msg = 'Cleared the %scache.' % (folder + ' ' if folder else '')
try:
shutil.rmtree(cache_dir, ignore_errors=True)
except OSError as e:
result = 'error'
msg = 'Failed to delete %s %s' % (cache_dir, e)
logger.exception(msg)
return
msg = 'Failed to delete %s.' % cache_dir
logger.exception(u'Failed to delete %s: %s.' % (cache_dir, e))
return {'result': result, 'message': msg}
try:
os.makedirs(cache_dir)
except OSError as e:
result = 'error'
msg = 'Failed to make %s %s' % (cache_dir, e)
logger.exception(msg)
return
msg = 'Failed to make %s.' % cache_dir
logger.exception(u'Failed to create %s: %s.' % (cache_dir, e))
return {'result': result, 'message': msg}
logger.info(msg)
return {'result': result, 'message': msg}
@cherrypy.expose