diff --git a/API.md b/API.md index 88edaab3..2e4016ec 100644 --- a/API.md +++ b/API.md @@ -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 -``` \ No newline at end of file +``` + diff --git a/data/interfaces/default/base.html b/data/interfaces/default/base.html index 79599e72..a606fcea 100644 --- a/data/interfaces/default/base.html +++ b/data/interfaces/default/base.html @@ -244,6 +244,25 @@ + + % if _session['user_group'] != 'admin':
@@ -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(' ' + msg, false, true, 5000) + } else { + showMsg(' ' + 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(' ' + msg, false, true, 5000) + } else { + showMsg(' ' + msg, false, true, 5000, true) + } notification_log_table.draw(); } }); - } + }); }); var timer; diff --git a/data/interfaces/default/settings.html b/data/interfaces/default/settings.html index 03a76092..fb04258f 100644 --- a/data/interfaces/default/settings.html +++ b/data/interfaces/default/settings.html @@ -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 @@ Log File: - ${os.path.join(config['log_dir'],'plexpy.log')} + ${os.path.join(config['log_dir'], logger.FILENAME)} Backup Directory: @@ -198,24 +198,39 @@
-
- +
+
+ + + + +
-
- +
+
+ + + + +
-
- +
+
+ + + + +
@@ -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!

+
+ +

+ Enable to cache images from Plex to reduce API calls and improve loading times. +

+
@@ -2056,7 +2079,7 @@ $(document).ready(function() { postSaveChecks(); return false; } else { - showMsg(' Please verify your settings.', false, true, 2000, true) + showMsg(' 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(' ' + msg, false, true, 5000) + } else { + showMsg(' ' + 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(' ' + msg, false, true, 5000) + } else { + showMsg(' ' + 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(' ' + msg, false, true, 5000) + } else { + showMsg(' ' + msg, false, true, 5000, true) + } + } + }); + }); + }); + if ($("#api_enabled").is(":checked")) { $("#apioptions").show(); } else { @@ -2235,7 +2320,7 @@ $(document).ready(function() { $("#pms-verify").html(''); $('#pms-verify').fadeIn('fast'); $("#pms-ip-group").addClass("has-error"); - showMsg(' Could not verify your server.', false, true, 2000, true) + showMsg(' Could not verify your server.', false, true, 5000, true) } } }); @@ -2243,7 +2328,7 @@ $(document).ready(function() { $("#pms-verify").html(''); $('#pms-verify').fadeIn('fast'); $("#pms-ip-group").addClass("has-error"); - showMsg(' Could not verify your server.', false, true, 2000, true) + showMsg(' 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("
" + data + "
", false, true, 3000); }); + $.get("/osxnotifyregister", { 'app': osx_notify_app }, function (data) { showMsg("
" + data + "
", false, true, 3000); }); }) pms_version = false; diff --git a/plexpy/api.py b/plexpy/api.py index 5d1d3b58..5f38fcd1 100644 --- a/plexpy/api.py +++ b/plexpy/api.py @@ -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)) diff --git a/plexpy/api2.py b/plexpy/api2.py index 65ca2ee5..99d65ed8 100644 --- a/plexpy/api2.py +++ b/plexpy/api2.py @@ -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)) diff --git a/plexpy/config.py b/plexpy/config.py index 790c4688..f2f3b012 100644 --- a/plexpy/config.py +++ b/plexpy/config.py @@ -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), diff --git a/plexpy/datafactory.py b/plexpy/datafactory.py index 8fce4f84..4110c70b 100644 --- a/plexpy/datafactory.py +++ b/plexpy/datafactory.py @@ -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.' \ No newline at end of file + return False \ No newline at end of file diff --git a/plexpy/pmsconnect.py b/plexpy/pmsconnect.py index 65eab009..e0a4c6f5 100644 --- a/plexpy/pmsconnect.py +++ b/plexpy/pmsconnect.py @@ -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=''): """ diff --git a/plexpy/webserve.py b/plexpy/webserve.py index 4578336c..a4a92aa2 100644 --- a/plexpy/webserve.py +++ b/plexpy/webserve.py @@ -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('
', '').replace('
', '') - s = '
%s
' % 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 = ' ' * (2*n) + l[n:] + filt[tl][2] += '
' + 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 '
%s
' % 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