From 6e5cd82dfb9cc31c9c1a2c8ad31fc5395876fd7c Mon Sep 17 00:00:00 2001 From: Eric Solari Date: Tue, 15 Mar 2016 22:24:08 -0500 Subject: [PATCH 01/30] Add CherryPy Environment Option --- PlexPy.py | 1 + plexpy/config.py | 1 + plexpy/webstart.py | 1 + 3 files changed, 3 insertions(+) diff --git a/PlexPy.py b/PlexPy.py index 15e3212e..4062c948 100755 --- a/PlexPy.py +++ b/PlexPy.py @@ -181,6 +181,7 @@ def main(): 'http_port': http_port, 'http_host': plexpy.CONFIG.HTTP_HOST, 'http_root': plexpy.CONFIG.HTTP_ROOT, + 'http_environment': plexpy.CONFIG.HTTP_ENVIRONMENT, 'http_proxy': plexpy.CONFIG.HTTP_PROXY, 'enable_https': plexpy.CONFIG.ENABLE_HTTPS, 'https_cert': plexpy.CONFIG.HTTPS_CERT, diff --git a/plexpy/config.py b/plexpy/config.py index ccb05c6d..996a3c18 100644 --- a/plexpy/config.py +++ b/plexpy/config.py @@ -142,6 +142,7 @@ _CONFIG_DEFINITIONS = { 'HTTPS_KEY': (str, 'General', ''), 'HTTPS_DOMAIN': (str, 'General', 'localhost'), 'HTTPS_IP': (str, 'General', '127.0.0.1'), + 'HTTP_ENVIRONMENT': (str, 'General', 'production'), 'HTTP_HOST': (str, 'General', '0.0.0.0'), 'HTTP_PASSWORD': (str, 'General', ''), 'HTTP_PORT': (int, 'General', 8181), diff --git a/plexpy/webstart.py b/plexpy/webstart.py index b1eae170..36760dd5 100644 --- a/plexpy/webstart.py +++ b/plexpy/webstart.py @@ -46,6 +46,7 @@ def initialize(options): options_dict = { 'server.socket_port': options['http_port'], 'server.socket_host': options['http_host'], + 'environment': options['http_environment'], 'server.thread_pool': 10, 'tools.encode.on': True, 'tools.encode.encoding': 'utf-8', From 3fe6db4d42092a9265058edc862963fc10ccab72 Mon Sep 17 00:00:00 2001 From: JonnyWong16 Date: Tue, 15 Mar 2016 20:42:45 -0700 Subject: [PATCH 02/30] Fix "Check GitHub for updates" not rescheduling when toggling setting --- plexpy/webserve.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plexpy/webserve.py b/plexpy/webserve.py index 913f9e6a..89fb862e 100644 --- a/plexpy/webserve.py +++ b/plexpy/webserve.py @@ -1308,7 +1308,8 @@ class WebInterface(object): refresh_users = False # If we change any monitoring settings, make sure we reschedule tasks. - if kwargs.get('monitoring_interval') != str(plexpy.CONFIG.MONITORING_INTERVAL) or \ + if kwargs.get('check_github') != plexpy.CONFIG.CHECK_GITHUB or \ + kwargs.get('monitoring_interval') != str(plexpy.CONFIG.MONITORING_INTERVAL) or \ kwargs.get('refresh_libraries_interval') != str(plexpy.CONFIG.REFRESH_LIBRARIES_INTERVAL) or \ kwargs.get('refresh_users_interval') != str(plexpy.CONFIG.REFRESH_USERS_INTERVAL) or \ kwargs.get('notify_recently_added') != plexpy.CONFIG.NOTIFY_RECENTLY_ADDED or \ From 498a0742221e00bf10ff65b514e895b3e919bf38 Mon Sep 17 00:00:00 2001 From: JonnyWong16 Date: Tue, 15 Mar 2016 23:49:27 -0700 Subject: [PATCH 03/30] Add user GitHub API Token to settings --- data/interfaces/default/settings.html | 26 ++++++++++++++++++++++++++ plexpy/config.py | 1 + plexpy/versioncheck.py | 2 ++ plexpy/webserve.py | 3 ++- 4 files changed, 31 insertions(+), 1 deletion(-) diff --git a/data/interfaces/default/settings.html b/data/interfaces/default/settings.html index e2a3f895..d4b92359 100644 --- a/data/interfaces/default/settings.html +++ b/data/interfaces/default/settings.html @@ -142,6 +142,18 @@ available_notification_agents = sorted(notifiers.available_notification_agents()

If you have Git installed, allow periodic checks for updates.

+
+
+ +
+
+ +
+
+

Optional: Use your own GitHub API token when checking for updates. +

+
+

Display Settings

@@ -1990,6 +2002,20 @@ $(document).ready(function() { } }); + if ($("#check_github").is(":checked")) { + $("#git_update_options").show(); + } else { + $("#git_update_options").hide(); + } + + $("#check_github").click(function(){ + if ($("#check_github").is(":checked")) { + $("#git_update_options").slideDown(); + } else { + $("#git_update_options").slideUp(); + } + }); + $( ".http-settings" ).change(function() { httpChanged = true; }); diff --git a/plexpy/config.py b/plexpy/config.py index ccb05c6d..a687de68 100644 --- a/plexpy/config.py +++ b/plexpy/config.py @@ -111,6 +111,7 @@ _CONFIG_DEFINITIONS = { 'GET_FILE_SIZES_HOLD': (dict, 'General', {'section_ids': [], 'rating_keys': []}), 'GIT_BRANCH': (str, 'General', 'master'), 'GIT_PATH': (str, 'General', ''), + 'GIT_TOKEN': (str, 'General', ''), 'GIT_USER': (str, 'General', 'drzoidberg33'), 'GRAPH_TYPE': (str, 'General', 'plays'), 'GRAPH_DAYS': (int, 'General', 30), diff --git a/plexpy/versioncheck.py b/plexpy/versioncheck.py index 1c37c9de..23bc9566 100644 --- a/plexpy/versioncheck.py +++ b/plexpy/versioncheck.py @@ -124,6 +124,7 @@ def checkGithub(): # Get the latest version available from github logger.info('Retrieving latest version information from GitHub') url = 'https://api.github.com/repos/%s/plexpy/commits/%s' % (plexpy.CONFIG.GIT_USER, plexpy.CONFIG.GIT_BRANCH) + if plexpy.CONFIG.GIT_TOKEN: url = url + '?access_token=%s' % plexpy.CONFIG.GIT_TOKEN version = request.request_json(url, timeout=20, validator=lambda x: type(x) == dict) if version is None: @@ -144,6 +145,7 @@ def checkGithub(): logger.info('Comparing currently installed version with latest GitHub version') url = 'https://api.github.com/repos/%s/plexpy/compare/%s...%s' % (plexpy.CONFIG.GIT_USER, plexpy.LATEST_VERSION, plexpy.CURRENT_VERSION) + if plexpy.CONFIG.GIT_TOKEN: url = url + '?access_token=%s' % plexpy.CONFIG.GIT_TOKEN commits = request.request_json(url, timeout=20, whitelist_status_code=404, validator=lambda x: type(x) == dict) if commits is None: diff --git a/plexpy/webserve.py b/plexpy/webserve.py index 89fb862e..aa1d1427 100644 --- a/plexpy/webserve.py +++ b/plexpy/webserve.py @@ -1261,7 +1261,8 @@ class WebInterface(object): "home_library_cards": json.dumps(plexpy.CONFIG.HOME_LIBRARY_CARDS), "buffer_threshold": plexpy.CONFIG.BUFFER_THRESHOLD, "buffer_wait": plexpy.CONFIG.BUFFER_WAIT, - "group_history_tables": checked(plexpy.CONFIG.GROUP_HISTORY_TABLES) + "group_history_tables": checked(plexpy.CONFIG.GROUP_HISTORY_TABLES), + "git_token": plexpy.CONFIG.GIT_TOKEN } return serve_template(templatename="settings.html", title="Settings", config=config) From ed8c7c1052edb132c8352b2dc4e8374b8ab9d571 Mon Sep 17 00:00:00 2001 From: JonnyWong16 Date: Tue, 15 Mar 2016 23:49:35 -0700 Subject: [PATCH 04/30] Filter out tokens/keys/passwords from logger --- plexpy/config.py | 17 +++++++++++++++++ plexpy/logger.py | 25 +++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/plexpy/config.py b/plexpy/config.py index a687de68..6a872680 100644 --- a/plexpy/config.py +++ b/plexpy/config.py @@ -432,6 +432,9 @@ _CONFIG_DEFINITIONS = { 'XBMC_ON_PMSUPDATE': (int, 'XBMC', 0) } +_BLACKLIST_KEYS = ['_APITOKEN', '_TOKEN', '_KEY', '_SECRET', '_PASSWORD', '_APIKEY', '_ID'] +_WHITELIST_KEYS = ['HTTPS_KEY', 'UPDATE_SECTION_IDS'] + # pylint:disable=R0902 # it might be nice to refactor for fewer instance variables @@ -445,6 +448,18 @@ class Config(object): for key in _CONFIG_DEFINITIONS.keys(): self.check_setting(key) self._upgrade() + self._blacklist() + + def _blacklist(self): + """ Add tokens and passwords to blacklisted words in logger """ + blacklist = [] + + for key, subkeys in self._config.iteritems(): + for subkey, value in subkeys.iteritems(): + if value and subkey.upper() not in _WHITELIST_KEYS and any(bk in subkey.upper() for bk in _BLACKLIST_KEYS): + blacklist.append(value) + + plexpy.logger._BLACKLIST_WORDS = blacklist def _define(self, name): key = name.upper() @@ -504,6 +519,8 @@ class Config(object): except IOError as e: plexpy.logger.error("Error writing configuration file: %s", e) + self._blacklist() + def __getattr__(self, name): """ Returns something from the ini unless it is a real property diff --git a/plexpy/logger.py b/plexpy/logger.py index 8e11333b..fbbe89d2 100644 --- a/plexpy/logger.py +++ b/plexpy/logger.py @@ -33,6 +33,8 @@ FILENAME = "plexpy.log" MAX_SIZE = 1000000 # 1 MB MAX_FILES = 5 +_BLACKLIST_WORDS = [] + # PlexPy logger logger = logging.getLogger("plexpy") @@ -62,6 +64,26 @@ class NoThreadFilter(logging.Filter): return not record.threadName == self.threadName +# Taken from Hellowlol/HTPC-Manager +class BlacklistFilter(logging.Filter): + """ + Log filter for blacklisted tokens and passwords + """ + def __init__(self): + pass + + def filter(self, record): + for item in _BLACKLIST_WORDS: + try: + if item in record.msg: + record.msg = record.msg.replace(item[:-2], 8 * '*') + if any(item in str(arg) for arg in record.args): + record.args = tuple(arg.replace(item[:-2], 8 * '*') for arg in record.args) + except: + pass + return True + + @contextlib.contextmanager def listener(): """ @@ -153,6 +175,7 @@ def initLogger(console=False, log_dir=False, verbose=False): # Add list logger loglist_handler = LogListHandler() loglist_handler.setLevel(logging.DEBUG) + loglist_handler.addFilter(BlacklistFilter()) logger.addHandler(loglist_handler) @@ -164,6 +187,7 @@ def initLogger(console=False, log_dir=False, verbose=False): file_handler = handlers.RotatingFileHandler(filename, maxBytes=MAX_SIZE, backupCount=MAX_FILES) file_handler.setLevel(logging.DEBUG) file_handler.setFormatter(file_formatter) + file_handler.addFilter(BlacklistFilter()) logger.addHandler(file_handler) @@ -173,6 +197,7 @@ def initLogger(console=False, log_dir=False, verbose=False): console_handler = logging.StreamHandler() console_handler.setFormatter(console_formatter) console_handler.setLevel(logging.DEBUG) + console_handler.addFilter(BlacklistFilter()) logger.addHandler(console_handler) From c35b79e6420034e1acd34bf4e355be5c36717286 Mon Sep 17 00:00:00 2001 From: Vilsol Date: Wed, 16 Mar 2016 16:33:56 +0000 Subject: [PATCH 05/30] Update Arnold Quotes --- plexpy/webserve.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/plexpy/webserve.py b/plexpy/webserve.py index aa1d1427..6699effb 100644 --- a/plexpy/webserve.py +++ b/plexpy/webserve.py @@ -2224,8 +2224,7 @@ class WebInterface(object): 'I need your clothes, your boots and your motorcycle.', 'No, it\'s not a tumor. It\'s not a tumor!', 'I LIED!', - 'See you at the party, Richter!', - 'Are you Sarah Conner?', + 'Are you Sarah Connor?', 'I\'m a cop you idiot!', 'Come with me if you want to live.', 'Who is your daddy and what does he do?' @@ -2250,4 +2249,4 @@ class WebInterface(object): def check_pms_updater(self): pms_connect = pmsconnect.PmsConnect() result = pms_connect.get_update_staus() - return json.dumps(result) \ No newline at end of file + return json.dumps(result) From b04ed83963356776c2093f4ee3c088818bbb577b Mon Sep 17 00:00:00 2001 From: JonnyWong16 Date: Wed, 16 Mar 2016 19:13:29 -0700 Subject: [PATCH 06/30] Make sure build_notify_text returns two values --- plexpy/notification_handler.py | 39 ++++++++++++++-------------------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/plexpy/notification_handler.py b/plexpy/notification_handler.py index a855f305..18828e68 100644 --- a/plexpy/notification_handler.py +++ b/plexpy/notification_handler.py @@ -325,11 +325,9 @@ def notify_timeline(timeline_data=None, notify_action=None): notify_action=notify_action) # Set the notification state in the db - set_notify_state(session={}, - notify_action=notify_action, + set_notify_state(notify_action=notify_action, agent_info=agent, - notify_strings=notify_strings, - metadata={}) + notify_strings=notify_strings) if agent['on_intdown'] and notify_action == 'intdown': # Build and send notification @@ -343,11 +341,9 @@ def notify_timeline(timeline_data=None, notify_action=None): notify_action=notify_action) # Set the notification state in the db - set_notify_state(session={}, - notify_action=notify_action, + set_notify_state(notify_action=notify_action, agent_info=agent, - notify_strings=notify_strings, - metadata={}) + notify_strings=notify_strings) if agent['on_extup'] and notify_action == 'extup': # Build and send notification @@ -361,11 +357,9 @@ def notify_timeline(timeline_data=None, notify_action=None): notify_action=notify_action) # Set the notification state in the db - set_notify_state(session={}, - notify_action=notify_action, + set_notify_state(notify_action=notify_action, agent_info=agent, - notify_strings=notify_strings, - metadata={}) + notify_strings=notify_strings) if agent['on_intup'] and notify_action == 'intup': # Build and send notification @@ -379,11 +373,9 @@ def notify_timeline(timeline_data=None, notify_action=None): notify_action=notify_action) # Set the notification state in the db - set_notify_state(session={}, - notify_action=notify_action, + set_notify_state(notify_action=notify_action, agent_info=agent, - notify_strings=notify_strings, - metadata={}) + notify_strings=notify_strings) if agent['on_pmsupdate'] and notify_action == 'pmsupdate': # Build and send notification @@ -397,11 +389,9 @@ def notify_timeline(timeline_data=None, notify_action=None): notify_action=notify_action) # Set the notification state in the db - set_notify_state(session={}, - notify_action=notify_action, + set_notify_state(notify_action=notify_action, agent_info=agent, - notify_strings=notify_strings, - metadata={}) + notify_strings=notify_strings) else: logger.debug(u"PlexPy NotificationHandler :: Notify timeline called but incomplete data received.") @@ -426,11 +416,14 @@ def get_notify_state(session): return notify_states -def set_notify_state(session, notify_action, agent_info, notify_strings, metadata): +def set_notify_state(notify_action, agent_info, notify_strings, session=None, metadata=None): if notify_action and agent_info: monitor_db = database.MonitorDatabase() + session = session or {} + metadata = metadata or {} + if notify_strings[2]: script_args = '[' + ', '.join(notify_strings[2]) + ']' else: @@ -496,7 +489,7 @@ def build_notify_text(session=None, timeline=None, notify_action=None, agent_id= metadata = metadata_list['metadata'] else: logger.error(u"PlexPy NotificationHandler :: Unable to retrieve metadata for rating_key %s" % str(rating_key)) - return [] + return [None, None, None], None # Check for exclusion tags if metadata['media_type'] == 'movie': @@ -918,7 +911,7 @@ def build_notify_text(session=None, timeline=None, notify_action=None, agent_id= else: return [subject_text, body_text, script_args], metadata else: - return None + return [None, None, None], None def build_server_notify_text(notify_action=None, agent_id=None): From c45a48896253810b033dcb41cf24faf7945609c0 Mon Sep 17 00:00:00 2001 From: JonnyWong16 Date: Sat, 19 Mar 2016 20:45:49 -0700 Subject: [PATCH 07/30] Remove experimental from Facebook and Scripts --- data/interfaces/default/settings.html | 12 ++++++------ plexpy/notifiers.py | 15 +++++++-------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/data/interfaces/default/settings.html b/data/interfaces/default/settings.html index d4b92359..d00f105d 100644 --- a/data/interfaces/default/settings.html +++ b/data/interfaces/default/settings.html @@ -1110,12 +1110,12 @@ available_notification_agents = sorted(notifiers.available_notification_agents() YYYY Numeric, four digits - Eg., 1999, 2003 + E.g. 1999, 2003 YY Numeric, two digits - Eg., 99, 03 + E.g. 99, 03 @@ -1193,7 +1193,7 @@ available_notification_agents = sorted(notifiers.available_notification_agents() Do Numeric, with suffix - Eg., 1st, 2nd ... 31st. + E.g. 1st, 2nd ... 31st. @@ -1329,12 +1329,12 @@ available_notification_agents = sorted(notifiers.available_notification_agents() ZZ UTC offset - Eg., +0100, -0700 + E.g. +0100, -0700 Z UTC offset - Eg., +01:00, -07:00 + E.g. +01:00, -07:00 @@ -1350,7 +1350,7 @@ available_notification_agents = sorted(notifiers.available_notification_agents() X Unix timestamp - Eg., 1456887825 + E.g. 1456887825 diff --git a/plexpy/notifiers.py b/plexpy/notifiers.py index 17f67142..ffce9b4b 100644 --- a/plexpy/notifiers.py +++ b/plexpy/notifiers.py @@ -2006,12 +2006,11 @@ class Scripts(object): logger.error(u"PlexPy Notifiers :: Failed to run script: %s" % e) def return_config_options(self): - config_option = [{'label': 'Warning', - 'description': 'Script notifications are currently experimental!

\ - Supported file types: ' + ', '.join(self.script_exts), + config_option = [{'label': 'Supported File Types', + 'description': ', '.join(self.script_exts), 'input_type': 'help' }, - {'label': 'Script folder', + {'label': 'Script Folder', 'value': plexpy.CONFIG.SCRIPTS_FOLDER, 'name': 'scripts_folder', 'description': 'Add your script folder.', @@ -2253,13 +2252,12 @@ class FacebookNotifier(object): def return_config_options(self): config_option = [{'label': 'Instructions', - 'description': 'Facebook notifications are currently experimental!

\ - Step 1: Visit \ + 'description': 'Step 1: Visit \ Facebook Developers to add a new app using basic setup.
\ Step 2: Go to Settings > Basic and fill in a \ Contact Email.
\ Step 3: Go to Settings > Advanced and fill in \ - Valid OAuth redirect URIs with your PlexPy URL (i.e. http://localhost:8181).
\ + Valid OAuth redirect URIs with your PlexPy URL (e.g. http://localhost:8181).
\ Step 4: Go to App Review and toggle public to Yes.
\ Step 5: Fill in the PlexPy URL below with the exact same URL from Step 3.
\ Step 6: Fill in the App ID and App Secret below.
\ @@ -2270,7 +2268,8 @@ class FacebookNotifier(object): {'label': 'PlexPy URL', 'value': self.redirect_uri, 'name': 'facebook_redirect_uri', - 'description': 'Your PlexPy URL. This will tell Facebook where to redirect you after authorization.', + 'description': 'Your PlexPy URL. This will tell Facebook where to redirect you after authorization.\ + (e.g. http://localhost:8181)', 'input_type': 'text' }, {'label': 'Facebook App ID', From 1d01d0bff1c6c6d9cecf01723cb0ea7133d616ee Mon Sep 17 00:00:00 2001 From: JonnyWong16 Date: Sat, 19 Mar 2016 22:24:09 -0700 Subject: [PATCH 08/30] Add FeatHub feature requests and guidelines modal popup --- README.md | 12 ++++---- data/interfaces/default/settings.html | 43 +++++++++++++++++++++++++-- 2 files changed, 48 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index d613581e..c83a4610 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ This project is based on code from [Headphones](https://github.com/rembo10/headp * PlexPy [forum thread](https://forums.plex.tv/discussion/169591/plexpy-another-plex-monitoring-program) ## Features + * Responsive web design viewable on desktop, tablet and mobile web browsers. * Themed to complement Plex/Web. * Easy configuration setup (no separate web server required). @@ -65,13 +66,14 @@ This project is based on code from [Headphones](https://github.com/rembo10/headp ## Feature Requests -1. Search for similar existing 'issues', feature requests can be recognized by the blue `enhancement` label. -2. If a similar request exists, post a comment (+1, or add a new idea to the existing request). -3. If no similar requests exist, you can create a new one. -4. Provide a clear title to easily identify the feature request. -5. Tag your feature request with `[Feature Request]` so it can be identified easily. +Feature requests are handled on [FeatHub](http://feathub.com/drzoidberg33/plexpy). + +1. Search the existing requests to see if your suggestion has already been submitted. +2. If a similar request exists, give it a thumbs up (+1), or add additional comments to the request. +3. If no similar requests exist, you can create a new one. Make sure to provide a clear title to easily identify the feature request. ## License + This is free software under the GPL v3 open source license. Feel free to do with it what you wish, but any modification must be open sourced. A copy of the license is included. This software includes Highsoft software libraries which you may freely distribute for non-commercial use. Commerical users must licence this software, for more information visit https://shop.highsoft.com/faq/non-commercial#non-commercial-redistribution. \ No newline at end of file diff --git a/data/interfaces/default/settings.html b/data/interfaces/default/settings.html index d00f105d..deaa1619 100644 --- a/data/interfaces/default/settings.html +++ b/data/interfaces/default/settings.html @@ -110,13 +110,21 @@ available_notification_agents = sorted(notifiers.available_notification_agents() Plex Forums: https://forums.plex.tv/discussion/169591/plexpy-another-plex-monitoring-program + + Source: + https://github.com/drzoidberg33/plexpy + Wiki: https://github.com/drzoidberg33/plexpy/wiki - Source: - https://github.com/drzoidberg33/plexpy + Issues: + https://github.com/drzoidberg33/plexpy/issues + + + Feature Requests: + http://feathub.com/drzoidberg33/plexpy Gitter Chat: @@ -1870,6 +1878,26 @@ available_notification_agents = sorted(notifiers.available_notification_agents() + @@ -2337,6 +2365,17 @@ $(document).ready(function() { var c = this.checked ? '#eb8600' : '#737373'; $('#notify_recently_added_grandparent_note').css('color', c); }); + + $('.guidelines-modal-link').on('click', function (e) { + e.preventDefault(); + $('#guidelines-link').attr('href', $('#source-link').attr('href')); + $('#guidelines-type').text($(this).data('id')) + $('#guidelines-modal').modal(); + $('#guidelines-continue').attr('href', $(this).attr('href')).on('click', function () { + $('#guidelines-modal').modal('hide'); + }); + }); + }); \ No newline at end of file From b743cca7bc3b016bdcc63c8f3c03a67b63a9433a Mon Sep 17 00:00:00 2001 From: JonnyWong16 Date: Sat, 19 Mar 2016 23:27:26 -0700 Subject: [PATCH 09/30] Add summary to Facebook posts --- plexpy/helpers.py | 3 ++- plexpy/notifiers.py | 42 ++++++++++++++++++++++-------------------- 2 files changed, 24 insertions(+), 21 deletions(-) diff --git a/plexpy/helpers.py b/plexpy/helpers.py index 7e2c3573..30ebc7c6 100644 --- a/plexpy/helpers.py +++ b/plexpy/helpers.py @@ -552,7 +552,8 @@ def uploadToImgur(imgPath, imgTitle=''): response = json.loads(response.read()) if response.get('status') == 200: - logger.debug(u"PlexPy Helpers :: Image uploaded to Imgur.") + t = '\'' + imgTitle + '\' ' if imgTitle else '' + logger.debug(u"PlexPy Helpers :: Image %suploaded to Imgur." % t) img_url = response.get('data').get('link', '') elif response.get('status') >= 400 and response.get('status') < 500: logger.warn(u"PlexPy Helpers :: Unable to upload image to Imgur: %s" % response.reason) diff --git a/plexpy/notifiers.py b/plexpy/notifiers.py index ffce9b4b..12ec62bd 100644 --- a/plexpy/notifiers.py +++ b/plexpy/notifiers.py @@ -2169,50 +2169,53 @@ class FacebookNotifier(object): if self.incl_poster and 'metadata' in kwargs: metadata = kwargs['metadata'] poster_url = metadata.get('poster_url','') + caption = '' if poster_url: if metadata['media_type'] == 'movie': - title = metadata['title'] - subtitle = metadata['year'] + title = '%s (%s)' % (metadata['title'], metadata['year']) + subtitle = metadata['summary'] rating_key = metadata['rating_key'] if metadata.get('imdb_url',''): poster_link = metadata.get('imdb_url', '') - caption = 'View on IMDB.' + caption = 'View on IMDB' elif metadata.get('themoviedb_url',''): poster_link = metadata.get('themoviedb_url', '') - caption = 'View on The Movie Database.' + caption = 'View on The Movie Database' elif metadata['media_type'] == 'show': - title = metadata['title'] - subtitle = metadata['year'] + title = '%s (%s)' % (metadata['title'], metadata['year']) + subtitle = metadata['summary'] rating_key = metadata['rating_key'] if metadata.get('thetvdb_url',''): poster_link = metadata.get('thetvdb_url', '') - caption = 'View on TheTVDB.' + caption = 'View on TheTVDB' elif metadata.get('themoviedb_url',''): poster_link = metadata.get('themoviedb_url', '') - caption = 'View on The Movie Database.' + caption = 'View on The Movie Database' elif metadata['media_type'] == 'episode': - title = '%s - %s' % (metadata['grandparent_title'], metadata['title']) - subtitle = 'S%s %s E%s' % (metadata['parent_media_index'], - '\xc2\xb7'.decode('utf8'), - metadata['media_index']) + title = '%s - %s (S%s %s E%s)' % (metadata['grandparent_title'], + metadata['title'], + metadata['parent_media_index'], + '\xc2\xb7'.decode('utf8'), + metadata['media_index']) + subtitle = metadata['summary'] rating_key = metadata['rating_key'] if metadata.get('thetvdb_url',''): poster_link = metadata.get('thetvdb_url', '') - caption = 'View on TheTVDB.' + caption = 'View on TheTVDB' elif metadata.get('themoviedb_url',''): poster_link = metadata.get('themoviedb_url', '') - caption = 'View on The Movie Database.' + caption = 'View on The Movie Database' elif metadata['media_type'] == 'artist': title = metadata['title'] - subtitle = '' + subtitle = metadata['summary'] rating_key = metadata['rating_key'] if metadata.get('lastfm_url',''): poster_link = metadata.get('lastfm_url', '') - caption = 'View on Last.fm.' + caption = 'View on Last.fm' elif metadata['media_type'] == 'track': title = '%s - %s' % (metadata['grandparent_title'], metadata['title']) @@ -2220,23 +2223,22 @@ class FacebookNotifier(object): rating_key = metadata['parent_rating_key'] if metadata.get('lastfm_url',''): poster_link = metadata.get('lastfm_url', '') - caption = 'View on Last.fm.' + caption = 'View on Last.fm' # Build Facebook post attachment if self.incl_pmslink: - caption = 'View on Plex Web.' + caption = 'View on Plex Web' attachment['link'] = 'http://app.plex.tv/web/app#!/server/' + plexpy.CONFIG.PMS_IDENTIFIER + \ '/details/%2Flibrary%2Fmetadata%2F' + rating_key - attachment['caption'] = caption elif poster_link: attachment['link'] = poster_link - attachment['caption'] = caption else: attachment['link'] = poster_url attachment['picture'] = poster_url attachment['name'] = title attachment['description'] = subtitle + attachment['caption'] = caption try: api.put_wall_post(profile_id=self.group_id, message=message, attachment=attachment) From 52361cd505c9b17cc138ab07cca8111dbab5be2a Mon Sep 17 00:00:00 2001 From: JonnyWong16 Date: Sun, 20 Mar 2016 17:06:58 -0700 Subject: [PATCH 10/30] Catch error if unable to retrieve poster for notification --- plexpy/notification_handler.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/plexpy/notification_handler.py b/plexpy/notification_handler.py index 18828e68..dbbbcbf9 100644 --- a/plexpy/notification_handler.py +++ b/plexpy/notification_handler.py @@ -625,11 +625,14 @@ def build_notify_text(session=None, timeline=None, notify_action=None, agent_id= # If no previous poster_url if not poster_url and plexpy.CONFIG.NOTIFY_UPLOAD_POSTERS: - # Retrieve the poster from Plex and cache to file - urllib.urlretrieve(plexpy.CONFIG.PMS_URL + thumb + '?X-Plex-Token=' + plexpy.CONFIG.PMS_TOKEN, - os.path.join(plexpy.CONFIG.CACHE_DIR, 'cache-poster.jpg')) - # Upload thumb to Imgur and get link - poster_url = helpers.uploadToImgur(os.path.join(plexpy.CONFIG.CACHE_DIR, 'cache-poster.jpg'), poster_title) + try: + # Retrieve the poster from Plex and cache to file + urllib.urlretrieve(plexpy.CONFIG.PMS_URL + thumb + '?X-Plex-Token=' + plexpy.CONFIG.PMS_TOKEN, + os.path.join(plexpy.CONFIG.CACHE_DIR, 'cache-poster.jpg')) + # Upload thumb to Imgur and get link + poster_url = helpers.uploadToImgur(os.path.join(plexpy.CONFIG.CACHE_DIR, 'cache-poster.jpg'), poster_title) + except Exception as e: + logger.error(u"PlexPy Notifier :: Unable to retrieve poster for rating_key %s: %s." % (str(rating_key), e)) metadata['poster_url'] = poster_url From afed5841e732968dc317c84bcaa711b0bca2f27b Mon Sep 17 00:00:00 2001 From: JonnyWong16 Date: Sun, 20 Mar 2016 17:17:50 -0700 Subject: [PATCH 11/30] Remove old notify_log table upgrades --- plexpy/__init__.py | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/plexpy/__init__.py b/plexpy/__init__.py index 5d32d075..93fedad3 100644 --- a/plexpy/__init__.py +++ b/plexpy/__init__.py @@ -729,30 +729,6 @@ def dbcheck(): 'ALTER TABLE users ADD COLUMN deleted_user INTEGER DEFAULT 0' ) - # Upgrade notify_log table from earlier versions - try: - c_db.execute('SELECT on_pause FROM notify_log') - except sqlite3.OperationalError: - logger.debug(u"Altering database. Updating database table notify_log.") - c_db.execute( - 'ALTER TABLE notify_log ADD COLUMN on_pause INTEGER' - ) - c_db.execute( - 'ALTER TABLE notify_log ADD COLUMN on_resume INTEGER' - ) - c_db.execute( - 'ALTER TABLE notify_log ADD COLUMN on_buffer INTEGER' - ) - - # Upgrade notify_log table from earlier versions - try: - c_db.execute('SELECT on_created FROM notify_log') - except sqlite3.OperationalError: - logger.debug(u"Altering database. Updating database table notify_log.") - c_db.execute( - 'ALTER TABLE notify_log ADD COLUMN on_created INTEGER' - ) - # Upgrade notify_log table from earlier versions try: c_db.execute('SELECT poster_url FROM notify_log') From 2259a960584aa9cdb6f14b93f9b202b00a5e68b0 Mon Sep 17 00:00:00 2001 From: JonnyWong16 Date: Mon, 21 Mar 2016 18:53:56 -0700 Subject: [PATCH 12/30] Use default poster for Facebook if unable to upload poster --- plexpy/notifiers.py | 139 +++++++++++++++++++++++--------------------- 1 file changed, 73 insertions(+), 66 deletions(-) diff --git a/plexpy/notifiers.py b/plexpy/notifiers.py index 12ec62bd..435953fd 100644 --- a/plexpy/notifiers.py +++ b/plexpy/notifiers.py @@ -2169,76 +2169,83 @@ class FacebookNotifier(object): if self.incl_poster and 'metadata' in kwargs: metadata = kwargs['metadata'] poster_url = metadata.get('poster_url','') + poster_link = '' caption = '' - if poster_url: - if metadata['media_type'] == 'movie': - title = '%s (%s)' % (metadata['title'], metadata['year']) - subtitle = metadata['summary'] - rating_key = metadata['rating_key'] - if metadata.get('imdb_url',''): - poster_link = metadata.get('imdb_url', '') - caption = 'View on IMDB' - elif metadata.get('themoviedb_url',''): - poster_link = metadata.get('themoviedb_url', '') - caption = 'View on The Movie Database' - - elif metadata['media_type'] == 'show': - title = '%s (%s)' % (metadata['title'], metadata['year']) - subtitle = metadata['summary'] - rating_key = metadata['rating_key'] - if metadata.get('thetvdb_url',''): - poster_link = metadata.get('thetvdb_url', '') - caption = 'View on TheTVDB' - elif metadata.get('themoviedb_url',''): - poster_link = metadata.get('themoviedb_url', '') - caption = 'View on The Movie Database' - - elif metadata['media_type'] == 'episode': - title = '%s - %s (S%s %s E%s)' % (metadata['grandparent_title'], - metadata['title'], - metadata['parent_media_index'], - '\xc2\xb7'.decode('utf8'), - metadata['media_index']) - subtitle = metadata['summary'] - rating_key = metadata['rating_key'] - if metadata.get('thetvdb_url',''): - poster_link = metadata.get('thetvdb_url', '') - caption = 'View on TheTVDB' - elif metadata.get('themoviedb_url',''): - poster_link = metadata.get('themoviedb_url', '') - caption = 'View on The Movie Database' - - elif metadata['media_type'] == 'artist': - title = metadata['title'] - subtitle = metadata['summary'] - rating_key = metadata['rating_key'] - if metadata.get('lastfm_url',''): - poster_link = metadata.get('lastfm_url', '') - caption = 'View on Last.fm' - - elif metadata['media_type'] == 'track': - title = '%s - %s' % (metadata['grandparent_title'], metadata['title']) - subtitle = metadata['parent_title'] - rating_key = metadata['parent_rating_key'] - if metadata.get('lastfm_url',''): - poster_link = metadata.get('lastfm_url', '') - caption = 'View on Last.fm' - - # Build Facebook post attachment - if self.incl_pmslink: - caption = 'View on Plex Web' - attachment['link'] = 'http://app.plex.tv/web/app#!/server/' + plexpy.CONFIG.PMS_IDENTIFIER + \ - '/details/%2Flibrary%2Fmetadata%2F' + rating_key - elif poster_link: - attachment['link'] = poster_link + # Use default posters if no poster_url + if not poster_url: + if metadata['media_type'] in ['artist', 'track']: + poster_url = 'https://raw.githubusercontent.com/drzoidberg33/plexpy/master/data/interfaces/default/images/cover.png' else: - attachment['link'] = poster_url + poster_url = 'https://raw.githubusercontent.com/drzoidberg33/plexpy/master/data/interfaces/default/images/poster.png' - attachment['picture'] = poster_url - attachment['name'] = title - attachment['description'] = subtitle - attachment['caption'] = caption + if metadata['media_type'] == 'movie': + title = '%s (%s)' % (metadata['title'], metadata['year']) + subtitle = metadata['summary'] + rating_key = metadata['rating_key'] + if metadata.get('imdb_url',''): + poster_link = metadata.get('imdb_url', '') + caption = 'View on IMDB' + elif metadata.get('themoviedb_url',''): + poster_link = metadata.get('themoviedb_url', '') + caption = 'View on The Movie Database' + + elif metadata['media_type'] == 'show': + title = '%s (%s)' % (metadata['title'], metadata['year']) + subtitle = metadata['summary'] + rating_key = metadata['rating_key'] + if metadata.get('thetvdb_url',''): + poster_link = metadata.get('thetvdb_url', '') + caption = 'View on TheTVDB' + elif metadata.get('themoviedb_url',''): + poster_link = metadata.get('themoviedb_url', '') + caption = 'View on The Movie Database' + + elif metadata['media_type'] == 'episode': + title = '%s - %s (S%s %s E%s)' % (metadata['grandparent_title'], + metadata['title'], + metadata['parent_media_index'], + '\xc2\xb7'.decode('utf8'), + metadata['media_index']) + subtitle = metadata['summary'] + rating_key = metadata['rating_key'] + if metadata.get('thetvdb_url',''): + poster_link = metadata.get('thetvdb_url', '') + caption = 'View on TheTVDB' + elif metadata.get('themoviedb_url',''): + poster_link = metadata.get('themoviedb_url', '') + caption = 'View on The Movie Database' + + elif metadata['media_type'] == 'artist': + title = metadata['title'] + subtitle = metadata['summary'] + rating_key = metadata['rating_key'] + if metadata.get('lastfm_url',''): + poster_link = metadata.get('lastfm_url', '') + caption = 'View on Last.fm' + + elif metadata['media_type'] == 'track': + title = '%s - %s' % (metadata['grandparent_title'], metadata['title']) + subtitle = metadata['parent_title'] + rating_key = metadata['parent_rating_key'] + if metadata.get('lastfm_url',''): + poster_link = metadata.get('lastfm_url', '') + caption = 'View on Last.fm' + + # Build Facebook post attachment + if self.incl_pmslink: + caption = 'View on Plex Web' + attachment['link'] = 'http://app.plex.tv/web/app#!/server/' + plexpy.CONFIG.PMS_IDENTIFIER + \ + '/details/%2Flibrary%2Fmetadata%2F' + rating_key + elif poster_link: + attachment['link'] = poster_link + else: + attachment['link'] = poster_url + + attachment['picture'] = poster_url + attachment['name'] = title + attachment['description'] = subtitle + attachment['caption'] = caption try: api.put_wall_post(profile_id=self.group_id, message=message, attachment=attachment) From 85e0c6d3cd21d6bbcc0de60b774d356e59db2353 Mon Sep 17 00:00:00 2001 From: Chrisophogus Date: Wed, 23 Mar 2016 20:14:48 +0000 Subject: [PATCH 13/30] Extra Arnie Added some additional Arnie quotes. --- plexpy/webserve.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/plexpy/webserve.py b/plexpy/webserve.py index 6699effb..c54b7d87 100644 --- a/plexpy/webserve.py +++ b/plexpy/webserve.py @@ -2228,6 +2228,14 @@ class WebInterface(object): 'I\'m a cop you idiot!', 'Come with me if you want to live.', 'Who is your daddy and what does he do?' + 'Oh, cookies! I can\'t wait to toss them.' + 'Can you hurry up. My horse is getting tired.' + 'What killed the dinosaurs? The Ice Age!' + 'That\'s for sleeping with my wife!' + 'Remember when I said I’d kill you last … I lied!' + 'You want to be a farmer? Here\'s a couple of acres' + 'Now, this is the plan. Get your ass to Mars.' + 'I just had a terrible thought... what if this is a dream?' ] random_number = randint(0, len(quote_list) - 1) From f783b08b7867339d4a60112bcf688e3a178fcdf6 Mon Sep 17 00:00:00 2001 From: Chrisophogus Date: Wed, 23 Mar 2016 20:52:50 +0000 Subject: [PATCH 14/30] Additional changes --- plexpy/webserve.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/plexpy/webserve.py b/plexpy/webserve.py index c54b7d87..a2ea8981 100644 --- a/plexpy/webserve.py +++ b/plexpy/webserve.py @@ -2227,15 +2227,15 @@ class WebInterface(object): 'Are you Sarah Connor?', 'I\'m a cop you idiot!', 'Come with me if you want to live.', - 'Who is your daddy and what does he do?' - 'Oh, cookies! I can\'t wait to toss them.' - 'Can you hurry up. My horse is getting tired.' - 'What killed the dinosaurs? The Ice Age!' - 'That\'s for sleeping with my wife!' - 'Remember when I said I’d kill you last … I lied!' - 'You want to be a farmer? Here\'s a couple of acres' - 'Now, this is the plan. Get your ass to Mars.' - 'I just had a terrible thought... what if this is a dream?' + 'Who is your daddy and what does he do?', + 'Oh, cookies! I can\'t wait to toss them.', + 'Can you hurry up. My horse is getting tired.', + 'What killed the dinosaurs? The Ice Age!', + 'That\'s for sleeping with my wife!', + 'Remember when I said I’d kill you last … I lied!', + 'You want to be a farmer? Here\'s a couple of acres', + 'Now, this is the plan. Get your ass to Mars.', + 'I just had a terrible thought... what if this is a dream?' ] random_number = randint(0, len(quote_list) - 1) From c8f1cb0a0af5d912d3afc0fef19091ef4942065a Mon Sep 17 00:00:00 2001 From: JonnyWong16 Date: Fri, 25 Mar 2016 09:12:40 -0700 Subject: [PATCH 15/30] Start PlexPy for different environment variables --- PlexPy.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/PlexPy.py b/PlexPy.py index 15e3212e..258233a3 100755 --- a/PlexPy.py +++ b/PlexPy.py @@ -1,4 +1,9 @@ -#!/usr/bin/env python +#!/bin/sh +''''which python >/dev/null 2>&1 && exec python "$0" "$@" # ''' +''''which python2 >/dev/null 2>&1 && exec python2 "$0" "$@" # ''' +''''which python2.7 >/dev/null 2>&1 && exec python2.7 "$0" "$@" # ''' +''''exec echo "Error: Python not found!" # ''' + # -*- coding: utf-8 -*- # This file is part of PlexPy. From a3f398390cd5abf7240425d2f0087b2ddae040d3 Mon Sep 17 00:00:00 2001 From: JonnyWong16 Date: Fri, 25 Mar 2016 09:16:24 -0700 Subject: [PATCH 16/30] Clean up Arnie quotes --- plexpy/webserve.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/plexpy/webserve.py b/plexpy/webserve.py index a2ea8981..244ea7a2 100644 --- a/plexpy/webserve.py +++ b/plexpy/webserve.py @@ -2228,14 +2228,14 @@ class WebInterface(object): 'I\'m a cop you idiot!', 'Come with me if you want to live.', 'Who is your daddy and what does he do?', - 'Oh, cookies! I can\'t wait to toss them.', - 'Can you hurry up. My horse is getting tired.', - 'What killed the dinosaurs? The Ice Age!', - 'That\'s for sleeping with my wife!', - 'Remember when I said I’d kill you last … I lied!', - 'You want to be a farmer? Here\'s a couple of acres', - 'Now, this is the plan. Get your ass to Mars.', - 'I just had a terrible thought... what if this is a dream?' + 'Oh, cookies! I can\'t wait to toss them.', + 'Can you hurry up. My horse is getting tired.', + 'What killed the dinosaurs? The Ice Age!', + 'That\'s for sleeping with my wife!', + 'Remember when I said I’d kill you last... I lied!', + 'You want to be a farmer? Here\'s a couple of acres', + 'Now, this is the plan. Get your ass to Mars.', + 'I just had a terrible thought... What if this is a dream?' ] random_number = randint(0, len(quote_list) - 1) From 0b126278f91005060a346a802b28d52f052aeac8 Mon Sep 17 00:00:00 2001 From: JonnyWong16 Date: Fri, 25 Mar 2016 11:50:11 -0700 Subject: [PATCH 17/30] Fix blacklisting of blank strings from ed8c7c1 --- plexpy/config.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plexpy/config.py b/plexpy/config.py index ceb12ca5..a5c28feb 100644 --- a/plexpy/config.py +++ b/plexpy/config.py @@ -457,10 +457,10 @@ class Config(object): for key, subkeys in self._config.iteritems(): for subkey, value in subkeys.iteritems(): - if value and subkey.upper() not in _WHITELIST_KEYS and any(bk in subkey.upper() for bk in _BLACKLIST_KEYS): - blacklist.append(value) + if str(value).strip() and subkey.upper() not in _WHITELIST_KEYS and any(bk in subkey.upper() for bk in _BLACKLIST_KEYS): + blacklist.append(str(value).strip()) - plexpy.logger._BLACKLIST_WORDS = blacklist + plexpy.logger._BLACKLIST_WORDS = filter(None, blacklist) def _define(self, name): key = name.upper() From 98d4484e6c16b85173862602dc3b393884f861f0 Mon Sep 17 00:00:00 2001 From: JonnyWong16 Date: Fri, 25 Mar 2016 13:20:25 -0700 Subject: [PATCH 18/30] Update CONTRIBUTING.md --- CONTRIBUTING.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ea47c243..b0c6a04b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,7 +1,7 @@ # Contributing to PlexPy ## Issues -In case you read this because you are posting an issue, please take a minute and conside the things below. The issue tracker is not a support forum. It is primarily intended to submit bugs, improvements or feature requests. However, we are glad to help you, and make sure the problem is not caused by PlexPy, but don't expect step-by-step answers. +In case you read this because you are posting an issue, please take a minute and conside the things below. The issue tracker is not a support forum. It is primarily intended to submit bugs. However, we are glad to help you, and make sure the problem is not caused by PlexPy, but don't expect step-by-step answers. ##### Many issues can simply be solved by: @@ -35,11 +35,11 @@ In case you read this because you are posting an issue, please take a minute and ## Feature Requests -1. Search for similar existing 'issues', feature requests can be recognized by the blue `enhancement` label. -2. If a similar request exists, post a comment (+1, or add a new idea to the existing request). -3. If no similar requests exist, you can create a new one. -4. Provide a clear title to easily identify the feature request. -5. Tag your feature request with `[Feature Request]` so it can be identified easily. +Feature requests are handled on [FeatHub](http://feathub.com/drzoidberg33/plexpy). + +1. Search the existing requests to see if your suggestion has already been submitted. +2. If a similar request exists, give it a thumbs up (+1), or add additional comments to the request. +3. If no similar requests exist, you can create a new one. Make sure to provide a clear title to easily identify the feature request. ## Pull Requests If you think you can contribute code to the PlexPy repository, do not hesitate to submit a pull request. From cc7bcbf9d5b37f1d131ba0d5befec028fd3dc3d4 Mon Sep 17 00:00:00 2001 From: JonnyWong16 Date: Fri, 25 Mar 2016 13:20:50 -0700 Subject: [PATCH 19/30] Change log directory to log file in "Help & Info" --- data/interfaces/default/settings.html | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/data/interfaces/default/settings.html b/data/interfaces/default/settings.html index deaa1619..62a40a2e 100644 --- a/data/interfaces/default/settings.html +++ b/data/interfaces/default/settings.html @@ -1,5 +1,6 @@ <%inherit file="base.html"/> <%! +import os import sys import plexpy from plexpy import notifiers, common, versioncheck @@ -80,6 +81,10 @@ available_notification_agents = sorted(notifiers.available_notification_agents() Database File: ${plexpy.DB_FILE} + + Log File: + ${os.path.join(config['log_dir'],'plexpy.log')} + Backup Directory: ${config['backup_dir']} @@ -88,10 +93,6 @@ available_notification_agents = sorted(notifiers.available_notification_agents() Cache Directory: ${config['cache_dir']} - - Log Directory: - ${config['log_dir']} - % if plexpy.ARGS: Arguments: From 29db2e958f0091b117704a31287c29bf229523e7 Mon Sep 17 00:00:00 2001 From: JonnyWong16 Date: Fri, 25 Mar 2016 13:24:24 -0700 Subject: [PATCH 20/30] Hide Plex notification agent --- plexpy/notifiers.py | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/plexpy/notifiers.py b/plexpy/notifiers.py index 435953fd..4acc6f85 100644 --- a/plexpy/notifiers.py +++ b/plexpy/notifiers.py @@ -114,24 +114,24 @@ def available_notification_agents(): 'on_intup': plexpy.CONFIG.XBMC_ON_INTUP, 'on_pmsupdate': plexpy.CONFIG.XBMC_ON_PMSUPDATE }, - {'name': 'Plex', - 'id': AGENT_IDS['Plex'], - 'config_prefix': 'plex', - 'has_config': True, - 'state': checked(plexpy.CONFIG.PLEX_ENABLED), - 'on_play': plexpy.CONFIG.PLEX_ON_PLAY, - 'on_stop': plexpy.CONFIG.PLEX_ON_STOP, - 'on_pause': plexpy.CONFIG.PLEX_ON_PAUSE, - 'on_resume': plexpy.CONFIG.PLEX_ON_RESUME, - 'on_buffer': plexpy.CONFIG.PLEX_ON_BUFFER, - 'on_watched': plexpy.CONFIG.PLEX_ON_WATCHED, - 'on_created': plexpy.CONFIG.PLEX_ON_CREATED, - 'on_extdown': plexpy.CONFIG.PLEX_ON_EXTDOWN, - 'on_intdown': plexpy.CONFIG.PLEX_ON_INTDOWN, - 'on_extup': plexpy.CONFIG.PLEX_ON_EXTUP, - 'on_intup': plexpy.CONFIG.PLEX_ON_INTUP, - 'on_pmsupdate': plexpy.CONFIG.PLEX_ON_PMSUPDATE - }, + #{'name': 'Plex', + # 'id': AGENT_IDS['Plex'], + # 'config_prefix': 'plex', + # 'has_config': True, + # 'state': checked(plexpy.CONFIG.PLEX_ENABLED), + # 'on_play': plexpy.CONFIG.PLEX_ON_PLAY, + # 'on_stop': plexpy.CONFIG.PLEX_ON_STOP, + # 'on_pause': plexpy.CONFIG.PLEX_ON_PAUSE, + # 'on_resume': plexpy.CONFIG.PLEX_ON_RESUME, + # 'on_buffer': plexpy.CONFIG.PLEX_ON_BUFFER, + # 'on_watched': plexpy.CONFIG.PLEX_ON_WATCHED, + # 'on_created': plexpy.CONFIG.PLEX_ON_CREATED, + # 'on_extdown': plexpy.CONFIG.PLEX_ON_EXTDOWN, + # 'on_intdown': plexpy.CONFIG.PLEX_ON_INTDOWN, + # 'on_extup': plexpy.CONFIG.PLEX_ON_EXTUP, + # 'on_intup': plexpy.CONFIG.PLEX_ON_INTUP, + # 'on_pmsupdate': plexpy.CONFIG.PLEX_ON_PMSUPDATE + # }, {'name': 'NotifyMyAndroid', 'id': AGENT_IDS['NMA'], 'config_prefix': 'nma', From fbf4a524c1720f2b242b21cd7b12cc2338816686 Mon Sep 17 00:00:00 2001 From: JonnyWong16 Date: Fri, 25 Mar 2016 15:39:31 -0700 Subject: [PATCH 21/30] Catch URLError when uploading to Imgur --- plexpy/helpers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plexpy/helpers.py b/plexpy/helpers.py index 30ebc7c6..ab3e9b29 100644 --- a/plexpy/helpers.py +++ b/plexpy/helpers.py @@ -559,7 +559,7 @@ def uploadToImgur(imgPath, imgTitle=''): logger.warn(u"PlexPy Helpers :: Unable to upload image to Imgur: %s" % response.reason) else: logger.warn(u"PlexPy Helpers :: Unable to upload image to Imgur.") - except urllib2.HTTPError as e: + except (urllib2.HTTPError, urllib2.URLError) as e: logger.warn(u"PlexPy Helpers :: Unable to upload image to Imgur: %s" % e) return img_url \ No newline at end of file From 568e4a5ee8ff6d25c4b2fa796e9d3f5222f44f52 Mon Sep 17 00:00:00 2001 From: JonnyWong16 Date: Sat, 26 Mar 2016 10:00:58 -0700 Subject: [PATCH 22/30] Fix blacklist logging again ed8c7c1 --- plexpy/logger.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plexpy/logger.py b/plexpy/logger.py index fbbe89d2..52e4cbc4 100644 --- a/plexpy/logger.py +++ b/plexpy/logger.py @@ -76,9 +76,9 @@ class BlacklistFilter(logging.Filter): for item in _BLACKLIST_WORDS: try: if item in record.msg: - record.msg = record.msg.replace(item[:-2], 8 * '*') + record.msg = record.msg.replace(item, 8 * '*' + item[-2:]) if any(item in str(arg) for arg in record.args): - record.args = tuple(arg.replace(item[:-2], 8 * '*') for arg in record.args) + record.args = tuple(arg.replace(item, 8 * '*' + item[-2:]) for arg in record.args) except: pass return True From ff0e724ee531103890ad87b7dd3a958570af0cc3 Mon Sep 17 00:00:00 2001 From: Chris Date: Sat, 26 Mar 2016 19:59:12 +0100 Subject: [PATCH 23/30] Fix unicode logging with 1252 encoded locale on Windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaces the abbreviation for months in the log output with numerals. Works around logging exceptions on Windows during March ("Mär") with Swiss-German locale on Windows, which is encoded with Windows-1252. --- plexpy/logger.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plexpy/logger.py b/plexpy/logger.py index 52e4cbc4..8eee7c0c 100644 --- a/plexpy/logger.py +++ b/plexpy/logger.py @@ -183,7 +183,7 @@ def initLogger(console=False, log_dir=False, verbose=False): if log_dir: filename = os.path.join(log_dir, FILENAME) - file_formatter = logging.Formatter('%(asctime)s - %(levelname)-7s :: %(threadName)s : %(message)s', '%d-%b-%Y %H:%M:%S') + file_formatter = logging.Formatter('%(asctime)s - %(levelname)-7s :: %(threadName)s : %(message)s', '%d-%m-%Y %H:%M:%S') file_handler = handlers.RotatingFileHandler(filename, maxBytes=MAX_SIZE, backupCount=MAX_FILES) file_handler.setLevel(logging.DEBUG) file_handler.setFormatter(file_formatter) @@ -193,7 +193,7 @@ def initLogger(console=False, log_dir=False, verbose=False): # Setup console logger if console: - console_formatter = logging.Formatter('%(asctime)s - %(levelname)s :: %(threadName)s : %(message)s', '%d-%b-%Y %H:%M:%S') + console_formatter = logging.Formatter('%(asctime)s - %(levelname)s :: %(threadName)s : %(message)s', '%d-%m-%Y %H:%M:%S') console_handler = logging.StreamHandler() console_handler.setFormatter(console_formatter) console_handler.setLevel(logging.DEBUG) From 005829ab72c2ce2ea6dd183200e3c3b848d550f0 Mon Sep 17 00:00:00 2001 From: Marty Zalega Date: Sun, 27 Mar 2016 10:46:09 +1000 Subject: [PATCH 24/30] Allow formatting of ifttt event key with action name --- plexpy/notifiers.py | 13 ++++++++----- plexpy/webserve.py | 2 +- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/plexpy/notifiers.py b/plexpy/notifiers.py index 435953fd..be9ea373 100644 --- a/plexpy/notifiers.py +++ b/plexpy/notifiers.py @@ -436,7 +436,7 @@ def get_notification_agent_config(agent_id): return [] -def send_notification(agent_id, subject, body, **kwargs): +def send_notification(agent_id, subject, body, notify_action, **kwargs): if str(agent_id).isdigit(): agent_id = int(agent_id) @@ -478,7 +478,7 @@ def send_notification(agent_id, subject, body, **kwargs): tweet.notify(subject=subject, message=body) elif agent_id == 12: iftttClient = IFTTT() - iftttClient.notify(subject=subject, message=body) + iftttClient.notify(subject=subject, message=body, action=notify_action) elif agent_id == 13: telegramClient = TELEGRAM() telegramClient.notify(message=body, event=subject) @@ -1604,10 +1604,11 @@ class IFTTT(object): self.apikey = plexpy.CONFIG.IFTTT_KEY self.event = plexpy.CONFIG.IFTTT_EVENT - def notify(self, message, subject): + def notify(self, message, subject, action): if not message or not subject: return + event = unicode(self.event).format(action=action) http_handler = HTTPSConnection("maker.ifttt.com") data = {'value1': subject.encode("utf-8"), @@ -1616,7 +1617,7 @@ class IFTTT(object): # logger.debug(u"Ifttt SENDING: %s" % json.dumps(data)) http_handler.request("POST", - "/trigger/%s/with/key/%s" % (self.event, self.apikey), + "/trigger/%s/with/key/%s" % (event, self.apikey), headers={'Content-type': "application/json"}, body=json.dumps(data)) response = http_handler.getresponse() @@ -1649,7 +1650,9 @@ class IFTTT(object): {'label': 'Ifttt Event', 'value': self.event, 'name': 'ifttt_event', - 'description': 'The Ifttt maker event to fire. The notification subject and body will be sent' + 'description': 'The Ifttt maker event to fire. You can include' + ' the {action} to be substituted with the action name.' + ' The notification subject and body will be sent' ' as value1 and value2 respectively.', 'input_type': 'text' } diff --git a/plexpy/webserve.py b/plexpy/webserve.py index 6699effb..b73364cb 100644 --- a/plexpy/webserve.py +++ b/plexpy/webserve.py @@ -1456,7 +1456,7 @@ class WebInterface(object): if this_agent: logger.debug(u"Sending test %s notification." % this_agent['name']) - notifiers.send_notification(this_agent['id'], subject, body, **kwargs) + notifiers.send_notification(this_agent['id'], subject, body, 'test', **kwargs) return "Notification sent." else: logger.debug(u"Unable to send test notification, invalid notification agent ID %s." % agent_id) From 252145cf58612afab8e56c77283866bf6c31d780 Mon Sep 17 00:00:00 2001 From: JonnyWong16 Date: Fri, 25 Mar 2016 13:06:39 -0700 Subject: [PATCH 25/30] Enable PlexPy dev environment using --dev flag --- PlexPy.py | 41 ++++++++++++++++++++++++----------------- plexpy/__init__.py | 2 ++ plexpy/config.py | 7 +++++-- plexpy/webstart.py | 13 ++++++++++--- 4 files changed, 41 insertions(+), 22 deletions(-) diff --git a/PlexPy.py b/PlexPy.py index 027692eb..b601fcee 100755 --- a/PlexPy.py +++ b/PlexPy.py @@ -81,11 +81,14 @@ def main(): '-d', '--daemon', action='store_true', help='Run as a daemon') parser.add_argument( '-p', '--port', type=int, help='Force PlexPy to run on a specified port') + parser.add_argument( + '--dev', action='store_true', help='Start PlexPy in the development environment') parser.add_argument( '--datadir', help='Specify a directory where to store your data files') - parser.add_argument('--config', help='Specify a config file to use') - parser.add_argument('--nolaunch', action='store_true', - help='Prevent browser from launching on startup') + parser.add_argument( + '--config', help='Specify a config file to use') + parser.add_argument( + '--nolaunch', action='store_true', help='Prevent browser from launching on startup') parser.add_argument( '--pidfile', help='Create a pid file (only relevant when running as a daemon)') @@ -100,6 +103,10 @@ def main(): logger.initLogger(console=not plexpy.QUIET, log_dir=False, verbose=plexpy.VERBOSE) + if args.dev: + plexpy.DEV = True + logger.debug(u"PlexPy is running in the dev environment.") + if args.daemon: if sys.platform == 'win32': sys.stderr.write( @@ -164,6 +171,19 @@ def main(): # Read config and start logging plexpy.initialize(config_file) + # Start the background threads + plexpy.start() + + # Open connection for websocket + if plexpy.CONFIG.MONITORING_USE_WEBSOCKET: + try: + web_socket.start_thread() + except: + logger.warn(u"Websocket :: Unable to open connection.") + # Fallback to polling + plexpy.POLLING_FAILOVER = True + plexpy.initialize_scheduler() + # Force the http port if neccessary if args.port: http_port = args.port @@ -196,21 +216,8 @@ def main(): } webstart.initialize(web_config) - # Start the background threads - plexpy.start() - - # Open connection for websocket - if plexpy.CONFIG.MONITORING_USE_WEBSOCKET: - try: - web_socket.start_thread() - except: - logger.warn(u"Websocket :: Unable to open connection.") - # Fallback to polling - plexpy.POLLING_FAILOVER = True - plexpy.initialize_scheduler() - # Open webbrowser - if plexpy.CONFIG.LAUNCH_BROWSER and not args.nolaunch: + if plexpy.CONFIG.LAUNCH_BROWSER and not args.nolaunch and not plexpy.DEV: plexpy.launch_browser(plexpy.CONFIG.HTTP_HOST, http_port, plexpy.CONFIG.HTTP_ROOT) diff --git a/plexpy/__init__.py b/plexpy/__init__.py index 93fedad3..fcc0bc32 100644 --- a/plexpy/__init__.py +++ b/plexpy/__init__.py @@ -74,6 +74,8 @@ UMASK = None POLLING_FAILOVER = False +DEV = False + def initialize(config_file): with INIT_LOCK: diff --git a/plexpy/config.py b/plexpy/config.py index a5c28feb..3419f58d 100644 --- a/plexpy/config.py +++ b/plexpy/config.py @@ -449,7 +449,9 @@ class Config(object): for key in _CONFIG_DEFINITIONS.keys(): self.check_setting(key) self._upgrade() - self._blacklist() + + if not plexpy.DEV: + self._blacklist() def _blacklist(self): """ Add tokens and passwords to blacklisted words in logger """ @@ -520,7 +522,8 @@ class Config(object): except IOError as e: plexpy.logger.error("Error writing configuration file: %s", e) - self._blacklist() + if not plexpy.DEV: + self._blacklist() def __getattr__(self, name): """ diff --git a/plexpy/webstart.py b/plexpy/webstart.py index 36760dd5..e22b89c1 100644 --- a/plexpy/webstart.py +++ b/plexpy/webstart.py @@ -51,8 +51,6 @@ def initialize(options): 'tools.encode.on': True, 'tools.encode.encoding': 'utf-8', 'tools.decode.on': True, - 'log.screen': False, - 'engine.autoreload.on': False, } if enable_https: @@ -62,6 +60,10 @@ def initialize(options): else: protocol = "http" + if plexpy.DEV: + options_dict['environment'] = "test_suite" + options_dict['engine.autoreload.on'] = True + logger.info("Starting PlexPy web server on %s://%s:%d/", protocol, options['http_host'], options['http_port']) cherrypy.config.update(options_dict) @@ -120,7 +122,12 @@ def initialize(options): try: cherrypy.process.servers.check_port(str(options['http_host']), options['http_port']) - cherrypy.server.start() + if not plexpy.DEV: + cherrypy.server.start() + else: + cherrypy.engine.signals.subscribe() + cherrypy.engine.start() + cherrypy.engine.block() except IOError: sys.stderr.write('Failed to start on port: %i. Is something else running?\n' % (options['http_port'])) sys.exit(1) From ba6ef4d62986ecd428fcf8328f37a8776d8b5a65 Mon Sep 17 00:00:00 2001 From: JonnyWong16 Date: Sun, 27 Mar 2016 15:18:41 -0700 Subject: [PATCH 26/30] Add toggle for log blacklist and mask public IP addresses --- data/interfaces/default/settings.html | 7 ++++ plexpy/config.py | 8 ++--- plexpy/logger.py | 50 ++++++++++++++++++++++++--- plexpy/webserve.py | 3 +- 4 files changed, 58 insertions(+), 10 deletions(-) diff --git a/data/interfaces/default/settings.html b/data/interfaces/default/settings.html index 62a40a2e..53295722 100644 --- a/data/interfaces/default/settings.html +++ b/data/interfaces/default/settings.html @@ -190,6 +190,13 @@ available_notification_agents = sorted(notifiers.available_notification_agents()

Group successive play history by the same user as a single entry in the tables and watch statistics.

+
+ +

Enable to mask passwords, access tokens, and public IP addresses with asterisks (*) in the logs.
+ Note: Only logs from the time this setting is enabled will be masked. Do not post your logs publically without masking sensitive information!

+

Directories

diff --git a/plexpy/config.py b/plexpy/config.py index 3419f58d..68ed0a58 100644 --- a/plexpy/config.py +++ b/plexpy/config.py @@ -169,6 +169,7 @@ _CONFIG_DEFINITIONS = { 'IFTTT_ON_PMSUPDATE': (int, 'IFTTT', 0), 'JOURNAL_MODE': (str, 'Advanced', 'wal'), 'LAUNCH_BROWSER': (int, 'General', 1), + 'LOG_BLACKLIST': (int, 'General', 1), 'LOG_DIR': (str, 'General', ''), 'LOGGING_IGNORE_INTERVAL': (int, 'Monitoring', 120), 'MOVIE_LOGGING_ENABLE': (int, 'Monitoring', 1), @@ -449,9 +450,7 @@ class Config(object): for key in _CONFIG_DEFINITIONS.keys(): self.check_setting(key) self._upgrade() - - if not plexpy.DEV: - self._blacklist() + self._blacklist() def _blacklist(self): """ Add tokens and passwords to blacklisted words in logger """ @@ -522,8 +521,7 @@ class Config(object): except IOError as e: plexpy.logger.error("Error writing configuration file: %s", e) - if not plexpy.DEV: - self._blacklist() + self._blacklist() def __getattr__(self, name): """ diff --git a/plexpy/logger.py b/plexpy/logger.py index 8eee7c0c..b8e4085f 100644 --- a/plexpy/logger.py +++ b/plexpy/logger.py @@ -27,6 +27,7 @@ import logging import errno import sys import os +import re # These settings are for file logging only FILENAME = "plexpy.log" @@ -73,17 +74,53 @@ class BlacklistFilter(logging.Filter): pass def filter(self, record): + if not plexpy.CONFIG.LOG_BLACKLIST: + return True + for item in _BLACKLIST_WORDS: try: if item in record.msg: record.msg = record.msg.replace(item, 8 * '*' + item[-2:]) if any(item in str(arg) for arg in record.args): - record.args = tuple(arg.replace(item, 8 * '*' + item[-2:]) for arg in record.args) + record.args = tuple(arg.replace(item, 8 * '*' + item[-2:]) if isinstance(arg, basestring) else arg + for arg in record.args) except: pass return True +class PublicIPFilter(logging.Filter): + """ + Log filter for public IP addresses + """ + def __init__(self): + pass + + def filter(self, record): + if not plexpy.CONFIG.LOG_BLACKLIST: + return True + + try: + # Currently only checking for ipv4 addresses + ipv4 = re.findall(r'[0-9]+(?:\.[0-9]+){3}', record.msg) + for ip in ipv4: + if helpers.is_ip_public(ip): + record.msg = record.msg.replace(ip, ip.partition('.')[0] + '.***.***.***') + + args = [] + for arg in record.args: + ipv4 = re.findall(r'[0-9]+(?:\.[0-9]+){3}', arg) if isinstance(arg, basestring) else [] + for ip in ipv4: + if helpers.is_ip_public(ip): + arg = arg.replace(ip, ip.partition('.')[0] + '.***.***.***') + args.append(arg) + record.args = tuple(args) + except: + pass + + return True + + @contextlib.contextmanager def listener(): """ @@ -175,7 +212,6 @@ def initLogger(console=False, log_dir=False, verbose=False): # Add list logger loglist_handler = LogListHandler() loglist_handler.setLevel(logging.DEBUG) - loglist_handler.addFilter(BlacklistFilter()) logger.addHandler(loglist_handler) @@ -187,7 +223,6 @@ def initLogger(console=False, log_dir=False, verbose=False): file_handler = handlers.RotatingFileHandler(filename, maxBytes=MAX_SIZE, backupCount=MAX_FILES) file_handler.setLevel(logging.DEBUG) file_handler.setFormatter(file_formatter) - file_handler.addFilter(BlacklistFilter()) logger.addHandler(file_handler) @@ -197,10 +232,17 @@ def initLogger(console=False, log_dir=False, verbose=False): console_handler = logging.StreamHandler() console_handler.setFormatter(console_formatter) console_handler.setLevel(logging.DEBUG) - console_handler.addFilter(BlacklistFilter()) logger.addHandler(console_handler) + # Add filters to log handlers + # Only add filters after the config file has been initialized + # Nothing prior to initialization should contain sensitive information + if not plexpy.DEV and plexpy.CONFIG: + for handler in logger.handlers: + handler.addFilter(BlacklistFilter()) + handler.addFilter(PublicIPFilter()) + # Install exception hooks initHooks() diff --git a/plexpy/webserve.py b/plexpy/webserve.py index 548eb555..784e48ae 100644 --- a/plexpy/webserve.py +++ b/plexpy/webserve.py @@ -1180,6 +1180,7 @@ class WebInterface(object): "backup_dir": plexpy.CONFIG.BACKUP_DIR, "cache_dir": plexpy.CONFIG.CACHE_DIR, "log_dir": plexpy.CONFIG.LOG_DIR, + "log_blacklist": checked(plexpy.CONFIG.LOG_BLACKLIST), "check_github": checked(plexpy.CONFIG.CHECK_GITHUB), "interface_list": interface_list, "cache_sizemb": plexpy.CONFIG.CACHE_SIZEMB, @@ -1282,7 +1283,7 @@ class WebInterface(object): "ip_logging_enable", "movie_logging_enable", "tv_logging_enable", "music_logging_enable", "pms_is_remote", "home_stats_type", "group_history_tables", "notify_consecutive", "notify_upload_posters", "notify_recently_added", "notify_recently_added_grandparent", - "monitor_pms_updates", "monitor_remote_access", "get_file_sizes" + "monitor_pms_updates", "monitor_remote_access", "get_file_sizes", "log_blacklist" ] for checked_config in checked_configs: if checked_config not in kwargs: From 2a764cf1909ec87672374527c73c938a8174066e Mon Sep 17 00:00:00 2001 From: JonnyWong16 Date: Sun, 27 Mar 2016 15:32:03 -0700 Subject: [PATCH 27/30] Add "First" and "Last" page buttons to datatables --- data/interfaces/default/js/tables/history_table.js | 2 +- data/interfaces/default/js/tables/history_table_modal.js | 2 +- data/interfaces/default/js/tables/libraries.js | 2 +- data/interfaces/default/js/tables/logs.js | 2 +- data/interfaces/default/js/tables/media_info_table.js | 2 +- data/interfaces/default/js/tables/notification_logs.js | 2 +- data/interfaces/default/js/tables/plex_logs.js | 2 +- data/interfaces/default/js/tables/sync_table.js | 2 +- data/interfaces/default/js/tables/user_ips.js | 2 +- data/interfaces/default/js/tables/users.js | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/data/interfaces/default/js/tables/history_table.js b/data/interfaces/default/js/tables/history_table.js index 3b176385..7749ef4e 100644 --- a/data/interfaces/default/js/tables/history_table.js +++ b/data/interfaces/default/js/tables/history_table.js @@ -21,7 +21,7 @@ history_table_options = { "infoFiltered":"", "emptyTable": "No data in table" }, - "pagingType": "bootstrap", + "pagingType": "full_numbers", "stateSave": true, "processing": false, "serverSide": true, diff --git a/data/interfaces/default/js/tables/history_table_modal.js b/data/interfaces/default/js/tables/history_table_modal.js index a58ca2f7..268f1dc1 100644 --- a/data/interfaces/default/js/tables/history_table_modal.js +++ b/data/interfaces/default/js/tables/history_table_modal.js @@ -19,7 +19,7 @@ history_table_modal_options = { "infoFiltered":"", "emptyTable": "No data in table", }, - "pagingType": "bootstrap", + "pagingType": "simple_numbers", "stateSave": false, "processing": false, "serverSide": true, diff --git a/data/interfaces/default/js/tables/libraries.js b/data/interfaces/default/js/tables/libraries.js index ec1767bc..437e2899 100644 --- a/data/interfaces/default/js/tables/libraries.js +++ b/data/interfaces/default/js/tables/libraries.js @@ -17,7 +17,7 @@ libraries_list_table_options = { "order": [ 2, 'asc'], "autoWidth": true, "stateSave": true, - "pagingType": "bootstrap", + "pagingType": "full_numbers", "columnDefs": [ { "targets": [0], diff --git a/data/interfaces/default/js/tables/logs.js b/data/interfaces/default/js/tables/logs.js index b8a21d39..532176b9 100644 --- a/data/interfaces/default/js/tables/logs.js +++ b/data/interfaces/default/js/tables/logs.js @@ -2,7 +2,7 @@ var log_table_options = { "destroy": true, "serverSide": true, "processing": false, - "pagingType": "bootstrap", + "pagingType": "full_numbers", "order": [ 0, 'desc'], "pageLength": 50, "stateSave": true, diff --git a/data/interfaces/default/js/tables/media_info_table.js b/data/interfaces/default/js/tables/media_info_table.js index 6bcdd202..d32aa656 100644 --- a/data/interfaces/default/js/tables/media_info_table.js +++ b/data/interfaces/default/js/tables/media_info_table.js @@ -22,7 +22,7 @@ media_info_table_options = { "infoFiltered":"", "emptyTable": "No data in table" }, - "pagingType": "bootstrap", + "pagingType": "full_numbers", "stateSave": true, "processing": false, "serverSide": true, diff --git a/data/interfaces/default/js/tables/notification_logs.js b/data/interfaces/default/js/tables/notification_logs.js index 283bd966..86c7b3bd 100644 --- a/data/interfaces/default/js/tables/notification_logs.js +++ b/data/interfaces/default/js/tables/notification_logs.js @@ -2,7 +2,7 @@ notification_log_table_options = { "destroy": true, "serverSide": true, "processing": false, - "pagingType": "bootstrap", + "pagingType": "full_numbers", "order": [ 0, 'desc'], "pageLength": 50, "stateSave": true, diff --git a/data/interfaces/default/js/tables/plex_logs.js b/data/interfaces/default/js/tables/plex_logs.js index 8a1109ba..4181e532 100644 --- a/data/interfaces/default/js/tables/plex_logs.js +++ b/data/interfaces/default/js/tables/plex_logs.js @@ -2,7 +2,7 @@ var plex_log_table_options = { "destroy": true, "processing": false, "serverSide": false, - "pagingType": "bootstrap", + "pagingType": "full_numbers", "order": [ 0, 'desc'], "pageLength": 50, "stateSave": true, diff --git a/data/interfaces/default/js/tables/sync_table.js b/data/interfaces/default/js/tables/sync_table.js index 94f4e289..5c348d52 100644 --- a/data/interfaces/default/js/tables/sync_table.js +++ b/data/interfaces/default/js/tables/sync_table.js @@ -1,7 +1,7 @@ sync_table_options = { "processing": false, "serverSide": false, - "pagingType": "bootstrap", + "pagingType": "full_numbers", "order": [ [ 0, 'desc'], [ 1, 'asc'], [2, 'asc'] ], "pageLength": 25, "stateSave": true, diff --git a/data/interfaces/default/js/tables/user_ips.js b/data/interfaces/default/js/tables/user_ips.js index b97a4407..f0a2a16c 100644 --- a/data/interfaces/default/js/tables/user_ips.js +++ b/data/interfaces/default/js/tables/user_ips.js @@ -9,7 +9,7 @@ user_ip_table_options = { "emptyTable": "No data in table", }, "stateSave": true, - "pagingType": "bootstrap", + "pagingType": "full_numbers", "processing": false, "serverSide": true, "pageLength": 10, diff --git a/data/interfaces/default/js/tables/users.js b/data/interfaces/default/js/tables/users.js index cc6ea22c..5f6d936d 100644 --- a/data/interfaces/default/js/tables/users.js +++ b/data/interfaces/default/js/tables/users.js @@ -17,7 +17,7 @@ users_list_table_options = { "order": [ 2, 'asc'], "autoWidth": true, "stateSave": true, - "pagingType": "bootstrap", + "pagingType": "full_numbers", "columnDefs": [ { "targets": [0], From c8f7f40b46e603ba8c7618b848b41ba63c35c8db Mon Sep 17 00:00:00 2001 From: JonnyWong16 Date: Sun, 27 Mar 2016 16:10:02 -0700 Subject: [PATCH 28/30] ISO date format for logs --- plexpy/logger.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plexpy/logger.py b/plexpy/logger.py index b8e4085f..75e84c67 100644 --- a/plexpy/logger.py +++ b/plexpy/logger.py @@ -219,7 +219,7 @@ def initLogger(console=False, log_dir=False, verbose=False): if log_dir: filename = os.path.join(log_dir, FILENAME) - file_formatter = logging.Formatter('%(asctime)s - %(levelname)-7s :: %(threadName)s : %(message)s', '%d-%m-%Y %H:%M:%S') + file_formatter = logging.Formatter('%(asctime)s - %(levelname)-7s :: %(threadName)s : %(message)s', '%Y-%m-%d %H:%M:%S') file_handler = handlers.RotatingFileHandler(filename, maxBytes=MAX_SIZE, backupCount=MAX_FILES) file_handler.setLevel(logging.DEBUG) file_handler.setFormatter(file_formatter) @@ -228,7 +228,7 @@ def initLogger(console=False, log_dir=False, verbose=False): # Setup console logger if console: - console_formatter = logging.Formatter('%(asctime)s - %(levelname)s :: %(threadName)s : %(message)s', '%d-%m-%Y %H:%M:%S') + console_formatter = logging.Formatter('%(asctime)s - %(levelname)s :: %(threadName)s : %(message)s', '%Y-%m-%d %H:%M:%S') console_handler = logging.StreamHandler() console_handler.setFormatter(console_formatter) console_handler.setLevel(logging.DEBUG) From 3c7b9558fe946d7cc31a59f467712e8eefc37869 Mon Sep 17 00:00:00 2001 From: JonnyWong16 Date: Sun, 27 Mar 2016 16:41:57 -0700 Subject: [PATCH 29/30] Access log file from the Help & Info page --- data/interfaces/default/settings.html | 2 +- plexpy/webserve.py | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/data/interfaces/default/settings.html b/data/interfaces/default/settings.html index 53295722..c09f9d88 100644 --- a/data/interfaces/default/settings.html +++ b/data/interfaces/default/settings.html @@ -83,7 +83,7 @@ available_notification_agents = sorted(notifiers.available_notification_agents() Log File: - ${os.path.join(config['log_dir'],'plexpy.log')} + ${os.path.join(config['log_dir'],'plexpy.log')} Backup Directory: diff --git a/plexpy/webserve.py b/plexpy/webserve.py index 784e48ae..697f85ad 100644 --- a/plexpy/webserve.py +++ b/plexpy/webserve.py @@ -1145,6 +1145,15 @@ class WebInterface(object): line)) return True + @cherrypy.expose + def logFile(self): + try: + with open(os.path.join(plexpy.CONFIG.LOG_DIR, 'plexpy.log'), 'r') as f: + return '
%s
' % f.read() + except IOError as e: + return "Log file not found." + + ##### Settings ##### @cherrypy.expose From 39034e38f6aa3c4ef985dafed7cf3d41fdbdcbce Mon Sep 17 00:00:00 2001 From: JonnyWong16 Date: Sun, 27 Mar 2016 16:43:06 -0700 Subject: [PATCH 30/30] v1.3.12 --- CHANGELOG.md | 21 +++++++++++++++++++++ plexpy/version.py | 2 +- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b9dd08b..13932ded 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,26 @@ # Changelog +## v1.3.12 (2016-03-27) + +* Fix: "Check GitHub for updates" not rescheduling when toggling setting. +* Fix: Bug where notifications would fail if metadata is not found. +* Fix: Bug where notifications would fail if unable to upload poster to Imgur. +* Fix: PlexPy will now start properly for different Python environment variables. +* New: Feature requests moved to FeatHub. +* New: Ability to specify a GitHub API token for updates (optional). +* New: Mask out sensitive information from the logs. +* New: New and updated Arnold quotes. (Thanks @Vilsol & @Chrisophogus) +* New: "First" and "Last" page buttons to datatables. +* New: Access log file from the "Help & Info" page. +* New: CherryPy environment options (for development). (Thanks @codedecay) +* New: PlexPy development environment (for development only). +* Change: Facebook posts with a posters now include a summary. +* Change: Facebook posts now use a default poster if the poster is not found or unable to upload to Imgur. +* Change: IFTTT events can be fromatted with the {action} name. +* Change: Logs now use ISO date format to avoid locale encoding errors. (Thanks @alshain) +* Remove: Non-functioning Plex notification agent. + + ## v1.3.11 (2016-03-15) * Fix: Typo preventing history logging for websockets. diff --git a/plexpy/version.py b/plexpy/version.py index 683d9b58..586b2a29 100644 --- a/plexpy/version.py +++ b/plexpy/version.py @@ -1,2 +1,2 @@ PLEXPY_VERSION = "master" -PLEXPY_RELEASE_VERSION = "1.3.11" +PLEXPY_RELEASE_VERSION = "1.3.12"