diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f58c273..8d5e5552 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## v1.3.3 (2016-01-26) + +* Fix: Plays by Month graph not loading. +* Change: Disable caching for datatables. +* Change: Improved updating library data in the database again. + + +## v1.3.2 (2016-01-24) + +* Fix: 'datestamp' and 'timestamp' for server notifications. +* Change: New method for updating library data in database. + + ## v1.3.1 (2016-01-23) * Fix: Notifiers authorization popups for reverse proxies. @@ -7,8 +20,8 @@ * Fix: Star rating overlapping text. * Fix: Unable to startup when library refresh fails. * Fix: Unable to parse 'datestamp' and 'timestamp' format. -* Change: Rename "Last Watched" to "Last Played" -* Change: More descriptive libraries updating message +* Change: Rename "Last Watched" to "Last Played". +* Change: More descriptive libraries updating message. ## v1.3.0 (2016-01-23) diff --git a/data/interfaces/default/js/tables/history_table.js b/data/interfaces/default/js/tables/history_table.js index 2f337189..2ecde57a 100644 --- a/data/interfaces/default/js/tables/history_table.js +++ b/data/interfaces/default/js/tables/history_table.js @@ -22,7 +22,7 @@ history_table_options = { "emptyTable": "No data in table" }, "pagingType": "bootstrap", - "stateSave": true, + "stateSave": false, "processing": false, "serverSide": true, "pageLength": 25, diff --git a/data/interfaces/default/js/tables/libraries.js b/data/interfaces/default/js/tables/libraries.js index 2fcb3346..377295ae 100644 --- a/data/interfaces/default/js/tables/libraries.js +++ b/data/interfaces/default/js/tables/libraries.js @@ -16,7 +16,7 @@ libraries_list_table_options = { "pageLength": 10, "order": [ 2, 'asc'], "autoWidth": true, - "stateSave": true, + "stateSave": false, "pagingType": "bootstrap", "columnDefs": [ { diff --git a/data/interfaces/default/js/tables/logs.js b/data/interfaces/default/js/tables/logs.js index b8a21d39..4d26d2cd 100644 --- a/data/interfaces/default/js/tables/logs.js +++ b/data/interfaces/default/js/tables/logs.js @@ -5,7 +5,7 @@ var log_table_options = { "pagingType": "bootstrap", "order": [ 0, 'desc'], "pageLength": 50, - "stateSave": true, + "stateSave": false, "language": { "search":"Search: ", "lengthMenu":"Show _MENU_ lines per page", diff --git a/data/interfaces/default/js/tables/plex_logs.js b/data/interfaces/default/js/tables/plex_logs.js index 8a1109ba..520eae42 100644 --- a/data/interfaces/default/js/tables/plex_logs.js +++ b/data/interfaces/default/js/tables/plex_logs.js @@ -5,7 +5,7 @@ var plex_log_table_options = { "pagingType": "bootstrap", "order": [ 0, 'desc'], "pageLength": 50, - "stateSave": true, + "stateSave": false, "language": { "search":"Search: ", "lengthMenu":"Show _MENU_ lines per page", diff --git a/data/interfaces/default/js/tables/sync_table.js b/data/interfaces/default/js/tables/sync_table.js index 94f4e289..a46c67d2 100644 --- a/data/interfaces/default/js/tables/sync_table.js +++ b/data/interfaces/default/js/tables/sync_table.js @@ -4,7 +4,7 @@ sync_table_options = { "pagingType": "bootstrap", "order": [ [ 0, 'desc'], [ 1, 'asc'], [2, 'asc'] ], "pageLength": 25, - "stateSave": true, + "stateSave": false, "language": { "search":"Search: ", "lengthMenu":"Show _MENU_ lines per page", diff --git a/data/interfaces/default/js/tables/user_ips.js b/data/interfaces/default/js/tables/user_ips.js index d025d7d6..16c3b9df 100644 --- a/data/interfaces/default/js/tables/user_ips.js +++ b/data/interfaces/default/js/tables/user_ips.js @@ -8,7 +8,7 @@ user_ip_table_options = { "infoFiltered":"(filtered from _MAX_ total entries)", "emptyTable": "No data in table", }, - "stateSave": true, + "stateSave": false, "pagingType": "bootstrap", "processing": false, "serverSide": true, diff --git a/data/interfaces/default/js/tables/users.js b/data/interfaces/default/js/tables/users.js index aeda3df1..f7147a17 100644 --- a/data/interfaces/default/js/tables/users.js +++ b/data/interfaces/default/js/tables/users.js @@ -16,7 +16,7 @@ users_list_table_options = { "pageLength": 10, "order": [ 2, 'asc'], "autoWidth": true, - "stateSave": true, + "stateSave": false, "pagingType": "bootstrap", "columnDefs": [ { diff --git a/data/interfaces/default/libraries.html b/data/interfaces/default/libraries.html index a2d1a7bb..1e99697c 100644 --- a/data/interfaces/default/libraries.html +++ b/data/interfaces/default/libraries.html @@ -15,7 +15,7 @@
PlexPy is updating library IDs in the database. This could take a few minutes to hours depending on the size of your database.
- You may leave this page and come back later. Note: All monitoring has been disabled while this update is in progress. + You may leave this page and come back later.
% endif
@@ -177,7 +177,7 @@ $("#refresh-libraries-list").click(function () { if ("${config['update_section_ids']}" == "1") { $('#update_section_ids_message').html( - ' PlexPy is updating library IDs in the database. This could take a few minutes depending on the size of your database.' + + ' PlexPy is updating library IDs in the database. This could take a few minutes to hours depending on the size of your database.' + '
' + 'You may leave this page and come back later.'); $(this).prop('disabled', true); diff --git a/data/interfaces/default/settings.html b/data/interfaces/default/settings.html index 466d516f..f796549c 100644 --- a/data/interfaces/default/settings.html +++ b/data/interfaces/default/settings.html @@ -1228,6 +1228,10 @@ available_notification_agents = sorted(notifiers.available_notification_agents() {transcode_audio_channels} The audio channels of the transcoded media. + + {user_id} + The unique identifier for the user. + @@ -1327,6 +1331,22 @@ available_notification_agents = sorted(notifiers.available_notification_agents() + + + + + + + + + + + + + + + +
{duration} The duration (in minutes) for the item.
{section_id}The unique identifier for the library.
{rating_key}The unique identifier for the item.
{parent_rating_key}The unique identifier for the item parent (season or album).
{grandparent_rating_key}The unique identifier for the item grandparent (TV show or artist).
diff --git a/plexpy/__init__.py b/plexpy/__init__.py index 03b393f1..c59ee7a2 100644 --- a/plexpy/__init__.py +++ b/plexpy/__init__.py @@ -739,7 +739,7 @@ def dbcheck(): 'ALTER TABLE library_sections_temp RENAME TO library_sections' ) except sqlite3.OperationalError: - logger.debug(u"Unable to remove section_id unique constraint from library_sections.") + logger.warn(u"Unable to remove section_id unique constraint from library_sections.") try: c_db.execute( 'DROP TABLE library_sections_temp' @@ -747,6 +747,17 @@ def dbcheck(): except: pass + # Upgrade library_sections table from earlier versions (remove duplicated libraries) + try: + result = c_db.execute('SELECT * FROM library_sections WHERE server_id = ""') + if result.rowcount > 0: + logger.debug(u"Altering database. Removing duplicate libraries from library_sections table.") + c_db.execute( + 'DELETE FROM library_sections WHERE server_id = ""' + ) + except sqlite3.OperationalError: + logger.warn(u"Unable to remove duplicate libraries from library_sections table.") + # Upgrade users table from earlier versions (remove UNIQUE constraint on username) try: result = c_db.execute('PRAGMA index_xinfo("sqlite_autoindex_users_2")') @@ -773,7 +784,7 @@ def dbcheck(): 'ALTER TABLE users_temp RENAME TO users' ) except sqlite3.OperationalError: - logger.debug(u"Unable to remove username unique constraint from users.") + logger.warn(u"Unable to remove username unique constraint from users.") try: c_db.execute( 'DROP TABLE users_temp' diff --git a/plexpy/activity_handler.py b/plexpy/activity_handler.py index 956cee73..fe6de42f 100644 --- a/plexpy/activity_handler.py +++ b/plexpy/activity_handler.py @@ -156,8 +156,8 @@ class ActivityHandler(object): (self.get_session_key(), buffer_last_triggered)) time_since_last_trigger = int(time.time()) - int(buffer_last_triggered) - if current_buffer_count >= plexpy.CONFIG.BUFFER_THRESHOLD and time_since_last_trigger == 0 or \ - time_since_last_trigger >= plexpy.CONFIG.BUFFER_WAIT: + if plexpy.CONFIG.BUFFER_THRESHOLD > 0 and (current_buffer_count >= plexpy.CONFIG.BUFFER_THRESHOLD and \ + time_since_last_trigger == 0 or time_since_last_trigger >= plexpy.CONFIG.BUFFER_WAIT): ap.set_session_buffer_trigger_time(session_key=self.get_session_key()) threading.Thread(target=notification_handler.notify, kwargs=dict(stream_data=db_stream, notify_action='buffer')).start() diff --git a/plexpy/config.py b/plexpy/config.py index afe81bf8..9cc23068 100644 --- a/plexpy/config.py +++ b/plexpy/config.py @@ -360,9 +360,10 @@ _CONFIG_DEFINITIONS = { 'TV_NOTIFY_ON_STOP': (int, 'Monitoring', 0), 'TV_NOTIFY_ON_PAUSE': (int, 'Monitoring', 0), 'TWITTER_ENABLED': (int, 'Twitter', 0), - 'TWITTER_PASSWORD': (str, 'Twitter', ''), - 'TWITTER_PREFIX': (str, 'Twitter', 'PlexPy'), - 'TWITTER_USERNAME': (str, 'Twitter', ''), + 'TWITTER_ACCESS_TOKEN': (str, 'Twitter', ''), + 'TWITTER_ACCESS_TOKEN_SECRET': (str, 'Twitter', ''), + 'TWITTER_CONSUMER_KEY': (str, 'Twitter', ''), + 'TWITTER_CONSUMER_SECRET': (str, 'Twitter', ''), 'TWITTER_ON_PLAY': (int, 'Twitter', 0), 'TWITTER_ON_STOP': (int, 'Twitter', 0), 'TWITTER_ON_PAUSE': (int, 'Twitter', 0), diff --git a/plexpy/graphs.py b/plexpy/graphs.py index bcede4d5..e5d93720 100644 --- a/plexpy/graphs.py +++ b/plexpy/graphs.py @@ -14,9 +14,9 @@ # along with PlexPy. If not, see . from plexpy import logger, database, helpers, common +import plexpy import datetime -import locale class Graphs(object): @@ -321,7 +321,7 @@ class Graphs(object): dt = datetime.datetime(*month_item[:6]) date_string = dt.strftime('%Y-%m') - categories.append(dt.strftime('%b %Y').decode(locale.getlocale()[1])) + categories.append(dt.strftime('%b %Y').decode(plexpy.SYS_ENCODING, 'replace')) series_1_value = 0 series_2_value = 0 series_3_value = 0 diff --git a/plexpy/libraries.py b/plexpy/libraries.py index d61be644..61a2f621 100644 --- a/plexpy/libraries.py +++ b/plexpy/libraries.py @@ -18,25 +18,28 @@ import plexpy def update_section_ids(): from plexpy import pmsconnect, activity_pinger - import threading + #import threading plexpy.CONFIG.UPDATE_SECTION_IDS = -1 logger.info(u"PlexPy Libraries :: Updating section_id's in database.") - logger.debug(u"PlexPy Libraries :: Disabling monitoring while update in progress.") - plexpy.schedule_job(activity_pinger.check_active_sessions, 'Check for active sessions', - hours=0, minutes=0, seconds=0) - plexpy.schedule_job(activity_pinger.check_recently_added, 'Check for recently added items', - hours=0, minutes=0, seconds=0) - plexpy.schedule_job(activity_pinger.check_server_response, 'Check for server response', - hours=0, minutes=0, seconds=0) + #logger.debug(u"PlexPy Libraries :: Disabling monitoring while update in progress.") + #plexpy.schedule_job(activity_pinger.check_active_sessions, 'Check for active sessions', + # hours=0, minutes=0, seconds=0) + #plexpy.schedule_job(activity_pinger.check_recently_added, 'Check for recently added items', + # hours=0, minutes=0, seconds=0) + #plexpy.schedule_job(activity_pinger.check_server_response, 'Check for server response', + # hours=0, minutes=0, seconds=0) monitor_db = database.MonitorDatabase() try: - query = 'SELECT id, rating_key FROM session_history_metadata WHERE section_id IS NULL' - result = monitor_db.select(query=query) + query = 'SELECT id, rating_key, grandparent_rating_key, media_type ' \ + 'FROM session_history_metadata WHERE section_id IS NULL' + history_results = monitor_db.select(query=query) + query = 'SELECT section_id, section_type FROM library_sections' + library_results = monitor_db.select(query=query) except Exception as e: logger.warn(u"PlexPy Libraries :: Unable to execute database query for update_section_ids: %s." % e) @@ -44,36 +47,52 @@ def update_section_ids(): plexpy.CONFIG.__setattr__('UPDATE_SECTION_IDS', 1) plexpy.CONFIG.write() - logger.debug(u"PlexPy Libraries :: Re-enabling monitoring.") - plexpy.initialize_scheduler() + #logger.debug(u"PlexPy Libraries :: Re-enabling monitoring.") + #plexpy.initialize_scheduler() return None # Add thread filter to the logger - logger.debug(u"PlexPy Libraries :: Disabling logging in the current thread while update in progress.") - thread_filter = logger.NoThreadFilter(threading.current_thread().name) - for handler in logger.logger.handlers: - handler.addFilter(thread_filter) + #logger.debug(u"PlexPy Libraries :: Disabling logging in the current thread while update in progress.") + #thread_filter = logger.NoThreadFilter(threading.current_thread().name) + #for handler in logger.logger.handlers: + # handler.addFilter(thread_filter) + + # Get rating_key: section_id mapping pairs + key_mappings = {} pms_connect = pmsconnect.PmsConnect() + for library in library_results: + section_id = library['section_id'] + section_type = library['section_type'] + + if section_type != 'photo': + library_children = pms_connect.get_library_children_details(section_id=section_id, + section_type=section_type) + if library_children: + children_list = library_children['childern_list'] + key_mappings.update({child['rating_key']:child['section_id'] for child in children_list}) + else: + logger.warn(u"PlexPy Libraries :: Unable to get a list of library items for section_id %s." % section_id) error_keys = set() - for item in result: - id = item['id'] - rating_key = item['rating_key'] - metadata = pms_connect.get_metadata_details(rating_key=rating_key) - - if metadata: - metadata = metadata['metadata'] - section_keys = {'id': id} - section_values = {'section_id': metadata['section_id']} - monitor_db.upsert('session_history_metadata', key_dict=section_keys, value_dict=section_values) + for item in history_results: + rating_key = item['grandparent_rating_key'] if item['media_type'] != 'movie' else item['rating_key'] + section_id = key_mappings.get(str(rating_key), None) + + if section_id: + try: + section_keys = {'id': item['id']} + section_values = {'section_id': section_id} + monitor_db.upsert('session_history_metadata', key_dict=section_keys, value_dict=section_values) + except: + error_keys.add(item['rating_key']) else: - error_keys.add(rating_key) + error_keys.add(item['rating_key']) # Remove thread filter from the logger - for handler in logger.logger.handlers: - handler.removeFilter(thread_filter) - logger.debug(u"PlexPy Libraries :: Re-enabling logging in the current thread.") + #for handler in logger.logger.handlers: + # handler.removeFilter(thread_filter) + #logger.debug(u"PlexPy Libraries :: Re-enabling logging in the current thread.") if error_keys: logger.info(u"PlexPy Libraries :: Updated all section_id's in database except for rating_keys: %s." % @@ -84,8 +103,8 @@ def update_section_ids(): plexpy.CONFIG.__setattr__('UPDATE_SECTION_IDS', 0) plexpy.CONFIG.write() - logger.debug(u"PlexPy Libraries :: Re-enabling monitoring.") - plexpy.initialize_scheduler() + #logger.debug(u"PlexPy Libraries :: Re-enabling monitoring.") + #plexpy.initialize_scheduler() return True diff --git a/plexpy/notification_handler.py b/plexpy/notification_handler.py index 8120f4e2..ece8ea5c 100644 --- a/plexpy/notification_handler.py +++ b/plexpy/notification_handler.py @@ -211,23 +211,17 @@ def notify(stream_data=None, notify_action=None): def notify_timeline(timeline_data=None, notify_action=None): if timeline_data and notify_action: - if (timeline_data['media_type'] == 'movie' and plexpy.CONFIG.MOVIE_NOTIFY_ENABLE) \ - or ((timeline_data['media_type'] == 'show' or timeline_data['media_type'] == 'episode') \ - and plexpy.CONFIG.TV_NOTIFY_ENABLE) \ - or ((timeline_data['media_type'] == 'artist' or timeline_data['media_type'] == 'track') \ - and plexpy.CONFIG.MUSIC_NOTIFY_ENABLE): - - for agent in notifiers.available_notification_agents(): - if agent['on_created'] and notify_action == 'created': - # Build and send notification - notify_strings = build_notify_text(timeline=timeline_data, state=notify_action) - notifiers.send_notification(config_id=agent['id'], - subject=notify_strings[0], - body=notify_strings[1], - notify_action=notify_action, - script_args=notify_strings[2]) - # Set the notification state in the db - set_notify_state(session=timeline_data, state=notify_action, agent_info=agent) + for agent in notifiers.available_notification_agents(): + if agent['on_created'] and notify_action == 'created': + # Build and send notification + notify_strings = build_notify_text(timeline=timeline_data, state=notify_action) + notifiers.send_notification(config_id=agent['id'], + subject=notify_strings[0], + body=notify_strings[1], + notify_action=notify_action, + script_args=notify_strings[2]) + # Set the notification state in the db + set_notify_state(session=timeline_data, state=notify_action, agent_info=agent) elif not timeline_data and notify_action: for agent in notifiers.available_notification_agents(): @@ -462,6 +456,7 @@ def build_notify_text(session=None, timeline=None, state=None): transcode_video_height = '' transcode_audio_codec = '' transcode_audio_channels = '' + user_id = '' progress_time = '' # Session values @@ -485,7 +480,6 @@ def build_notify_text(session=None, timeline=None, state=None): stream_duration = int((time.time() - helpers.cast_to_float(session['started'])) / 60) view_offset = helpers.convert_milliseconds_to_minutes(session['view_offset']) - progress_time = arrow.get(helpers.cast_to_int(session['view_offset'])/1000).format(plexpy.CONFIG.TIME_FORMAT.replace('zz','').replace('a','').replace('A','').replace('h','')) user = session['friendly_name'] platform = session['platform'] player = session['player'] @@ -506,6 +500,8 @@ def build_notify_text(session=None, timeline=None, state=None): transcode_video_height = session['transcode_height'] transcode_audio_codec = session['transcode_audio_codec'] transcode_audio_channels = session['transcode_audio_channels'] + user_id = session['user_id'] + progress_time = arrow.get(helpers.cast_to_int(session['view_offset'])/1000).format(plexpy.CONFIG.TIME_FORMAT.replace('zz','').replace('a','').replace('A','').replace('h','')) progress_percent = helpers.get_percent(view_offset, duration) @@ -558,6 +554,7 @@ def build_notify_text(session=None, timeline=None, state=None): 'transcode_video_height': transcode_video_height, 'transcode_audio_codec': transcode_audio_codec, 'transcode_audio_channels': transcode_audio_channels, + 'user_id': user_id, 'title': full_title, 'library_name': metadata['library_name'], 'show_name': show_name, @@ -579,7 +576,11 @@ def build_notify_text(session=None, timeline=None, state=None): 'summary': metadata['summary'], 'tagline': metadata['tagline'], 'rating': metadata['rating'], - 'duration': duration + 'duration': duration, + 'section_id': metadata['section_id'], + 'rating_key': metadata['rating_key'], + 'parent_rating_key': metadata['parent_rating_key'], + 'grandparent_rating_key': metadata['grandparent_rating_key'] } # Default subject text @@ -798,8 +799,8 @@ def build_server_notify_text(state=None): available_params = {'server_name': server_name, 'server_uptime': server_uptime, 'action': state, - 'datestamp': time.strftime(helpers.parse_js_date(plexpy.CONFIG.DATE_FORMAT)), - 'timestamp': time.strftime(helpers.parse_js_date(plexpy.CONFIG.TIME_FORMAT))} + 'datestamp': arrow.now().format(plexpy.CONFIG.DATE_FORMAT.replace('Do','').replace('zz','')), + 'timestamp': arrow.now().format(plexpy.CONFIG.TIME_FORMAT.replace('Do','').replace('zz',''))} # Default text subject_text = 'PlexPy (%s)' % server_name diff --git a/plexpy/notifiers.py b/plexpy/notifiers.py index a23f8b58..1623cd8d 100644 --- a/plexpy/notifiers.py +++ b/plexpy/notifiers.py @@ -1165,8 +1165,10 @@ class TwitterNotifier(object): SIGNIN_URL = 'https://api.twitter.com/oauth/authenticate' def __init__(self): - self.consumer_key = "2LdJKXHDUwJtjYBsdwJisIOsh" - self.consumer_secret = "QWbUcZzAIiL4zbDCIhy2EdUkV8yEEav3qMdo5y3FugxCFelWrA" + self.access_token = plexpy.CONFIG.TWITTER_ACCESS_TOKEN + self.access_token_secret = plexpy.CONFIG.TWITTER_ACCESS_TOKEN_SECRET + self.consumer_key = plexpy.CONFIG.TWITTER_CONSUMER_KEY + self.consumer_secret = plexpy.CONFIG.TWITTER_CONSUMER_SECRET def notify(self, subject, message): if not subject or not message: @@ -1191,16 +1193,16 @@ class TwitterNotifier(object): else: request_token = dict(parse_qsl(content)) - plexpy.CONFIG.TWITTER_USERNAME = request_token['oauth_token'] - plexpy.CONFIG.TWITTER_PASSWORD = request_token['oauth_token_secret'] + plexpy.CONFIG.TWITTER_ACCESS_TOKEN = request_token['oauth_token'] + plexpy.CONFIG.TWITTER_ACCESS_TOKEN_SECRET = request_token['oauth_token_secret'] return self.AUTHORIZATION_URL + "?oauth_token=" + request_token['oauth_token'] def _get_credentials(self, key): request_token = {} - request_token['oauth_token'] = plexpy.CONFIG.TWITTER_USERNAME - request_token['oauth_token_secret'] = plexpy.CONFIG.TWITTER_PASSWORD + request_token['oauth_token'] = plexpy.CONFIG.TWITTER_ACCESS_TOKEN + request_token['oauth_token_secret'] = plexpy.CONFIG.TWITTER_ACCESS_TOKEN_SECRET request_token['oauth_callback_confirmed'] = 'true' token = oauth.Token(request_token['oauth_token'], request_token['oauth_token_secret']) @@ -1225,20 +1227,20 @@ class TwitterNotifier(object): else: # logger.info(u"PlexPy Notifiers :: Your Twitter Access Token key: %s" % access_token['oauth_token']) # logger.info(u"PlexPy Notifiers :: Access Token secret: %s" % access_token['oauth_token_secret']) - plexpy.CONFIG.TWITTER_USERNAME = access_token['oauth_token'] - plexpy.CONFIG.TWITTER_PASSWORD = access_token['oauth_token_secret'] + plexpy.CONFIG.TWITTER_ACCESS_TOKEN = access_token['oauth_token'] + plexpy.CONFIG.TWITTER_ACCESS_TOKEN_SECRET = access_token['oauth_token_secret'] plexpy.CONFIG.write() return True def _send_tweet(self, message=None): - username = self.consumer_key - password = self.consumer_secret - access_token_key = plexpy.CONFIG.TWITTER_USERNAME - access_token_secret = plexpy.CONFIG.TWITTER_PASSWORD + consumer_key = self.consumer_key + consumer_secret = self.consumer_secret + access_token = self.access_token + access_token_secret = self.access_token_secret # logger.info(u"PlexPy Notifiers :: Sending tweet: " + message) - api = twitter.Api(username, password, access_token_key, access_token_secret) + api = twitter.Api(consumer_key, consumer_secret, access_token, access_token_secret) try: api.PostUpdate(message) @@ -1251,30 +1253,37 @@ class TwitterNotifier(object): def return_config_options(self): config_option = [{'label': 'Instructions', - 'description': 'Step 1: Click the Request Authorization button below.
\ - Step 2: Input the Authorization Key you received from Step 1 below.
\ - Step 3: Click the Verify Key button below.', + 'description': 'Step 1: Visit \ + Twitter Apps to Create New App. A vaild "Website" is not required.
\ + Step 2: Go to Keys and Access Tokens and click \ + Create my access token.
\ + Step 3: Fill in the Consumer Key, Consumer Secret, \ + Access Token, and Access Token Secret below.', 'input_type': 'help' }, - {'label': 'Request Authorization', - 'value': 'Request Authorization', - 'name': 'twitterStep1', - 'description': 'Request Twitter authorization. (Ensure you allow the browser pop-up).', - 'input_type': 'button' - }, - {'label': 'Authorization Key', - 'value': '', - 'name': 'twitter_key', - 'description': 'Your Twitter authorization key.', + {'label': 'Twitter Consumer Key', + 'value': self.consumer_key, + 'name': 'twitter_consumer_key', + 'description': 'Your Twitter consumer key.', 'input_type': 'text' }, - {'label': 'Verify Key', - 'value': 'Verify Key', - 'name': 'twitterStep2', - 'description': 'Verify your Twitter authorization key.', - 'input_type': 'button' + {'label': 'Twitter Consumer Secret', + 'value': self.consumer_secret, + 'name': 'twitter_consumer_secret', + 'description': 'Your Twitter consumer secret.', + 'input_type': 'text' }, - {'input_type': 'nosave' + {'label': 'Twitter Access Token', + 'value': self.access_token, + 'name': 'twitter_access_token', + 'description': 'Your Twitter access token.', + 'input_type': 'text' + }, + {'label': 'Twitter Access Token Secret', + 'value': self.access_token_secret, + 'name': 'twitter_access_token_secret', + 'description': 'Your Twitter access token secret.', + 'input_type': 'text' } ] @@ -1668,10 +1677,10 @@ class TELEGRAM(object): 'description': 'Your Telegram bot token. Contact @BotFather on Telegram to get one.', 'input_type': 'text' }, - {'label': 'Telegram Chat ID', + {'label': 'Telegram Chat ID, Group ID, or Channel Username', 'value': self.chat_id, 'name': 'telegram_chat_id', - 'description': 'Your Telegram Chat ID, Group ID, or channel username. Contact @myidbot on Telegram to get an ID.', + 'description': 'Your Telegram Chat ID, Group ID, or @channelusername. Contact @myidbot on Telegram to get an ID.', 'input_type': 'text' } ] @@ -2088,12 +2097,16 @@ class FacebookNotifier(object): config_option = [{'label': 'Instructions', 'description': 'Facebook notifications are currently experimental!

\ Step 1: Visit \ - Facebook Developers to create a new app using advanced setup.
\ - Step 2: Go to Settings > Advanced and fill in \ + 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).
\ - Step 3: Fill in the PlexPy URL below with the exact same URL from Step 2.
\ - Step 4: Fill in the App ID and App Secret below.
\ - Step 5: Click the Request Authorization button below.', + 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.
\ + Step 7: Click the Request Authorization button below.
\ + Step 8: Fill in the Group ID below.', 'input_type': 'help' }, {'label': 'PlexPy URL', diff --git a/plexpy/pmsconnect.py b/plexpy/pmsconnect.py index bcbd61db..2a1a76b0 100644 --- a/plexpy/pmsconnect.py +++ b/plexpy/pmsconnect.py @@ -40,15 +40,19 @@ def get_server_friendly_name(): def refresh_libraries(): logger.info(u"PlexPy Pmsconnect :: Requesting libraries list refresh...") - library_sections = PmsConnect().get_library_details() server_id = plexpy.CONFIG.PMS_IDENTIFIER + if not server_id: + logger.error(u"PlexPy Pmsconnect :: No PMS identifier, cannot refresh libraries. Verify server in settings.") + return - library_keys = [] + library_sections = PmsConnect().get_library_details() if library_sections: monitor_db = database.MonitorDatabase() + library_keys = [] + for section in library_sections: section_keys = {'server_id': server_id, 'section_id': section['section_id']} @@ -72,10 +76,11 @@ def refresh_libraries(): plexpy.CONFIG.__setattr__('HOME_LIBRARY_CARDS', library_keys) plexpy.CONFIG.write() - if plexpy.CONFIG.UPDATE_SECTION_IDS == 1: + if plexpy.CONFIG.UPDATE_SECTION_IDS == 1 or plexpy.CONFIG.UPDATE_SECTION_IDS == -1: from plexpy import libraries import threading + # Start library section_id update on it's own thread threading.Thread(target=libraries.update_section_ids).start() logger.info(u"PlexPy Pmsconnect :: Libraries list refreshed.") @@ -1588,9 +1593,9 @@ class PmsConnect(object): sort_type = '' if str(section_id).isdigit(): - library_data = self.get_library_list(section_id, list_type, count, sort_type, output_format='xml') + library_data = self.get_library_list(str(section_id), list_type, count, sort_type, output_format='xml') elif str(rating_key).isdigit(): - library_data = self.get_children_list(rating_key, output_format='xml') + library_data = self.get_children_list(str(rating_key), output_format='xml') else: logger.warn(u"PlexPy Pmsconnect :: get_library_children called by invalid section_id or rating_key provided.") return [] diff --git a/plexpy/version.py b/plexpy/version.py index 423b493f..9dd70962 100644 --- a/plexpy/version.py +++ b/plexpy/version.py @@ -1,2 +1,2 @@ PLEXPY_VERSION = "master" -PLEXPY_RELEASE_VERSION = "1.3.1" +PLEXPY_RELEASE_VERSION = "1.3.3"