def get_current_activity(self, session_key=None, **kwargs): current_activity = { 'server_id': self.CONFIG.ID, 'pms_name': self.CONFIG.PMS_NAME, 'sessions': [], 'stream_count': 0, 'stream_count_direct_play': 0, 'stream_count_direct_stream': 0, 'stream_count_transcode': 0, 'total_bandwidth': 0, 'wan_bandwidth': 0, 'lan_bandwidth': 0, } if self.WS and self.WS.WS_CONNECTION and self.WS.WS_CONNECTION.connected: activity = self.PMSCONNECTION.get_current_activity() if activity: current_activity.update(activity) counts = { 'stream_count_direct_play': 0, 'stream_count_direct_stream': 0, 'stream_count_transcode': 0, 'total_bandwidth': 0, 'lan_bandwidth': 0, 'wan_bandwidth': 0 } for s in current_activity['sessions']: if s['transcode_decision'] == 'transcode': counts['stream_count_transcode'] += 1 elif s['transcode_decision'] == 'copy': counts['stream_count_direct_stream'] += 1 else: counts['stream_count_direct_play'] += 1 counts['total_bandwidth'] += helpers.cast_to_int( s['bandwidth']) if s['location'] == 'lan': counts['lan_bandwidth'] += helpers.cast_to_int( s['bandwidth']) else: counts['wan_bandwidth'] += helpers.cast_to_int( s['bandwidth']) current_activity.update(counts) return current_activity
def build_server_notify_text(state=None): # Get time formats date_format = plexpy.CONFIG.DATE_FORMAT.replace('Do','').replace('zz','') time_format = plexpy.CONFIG.TIME_FORMAT.replace('Do','').replace('zz','') # Get the server name server_name = plexpy.CONFIG.PMS_NAME # Get the server uptime plex_tv = plextv.PlexTV() server_times = plex_tv.get_server_times() if server_times: updated_at = server_times[0]['updated_at'] server_uptime = helpers.human_duration(int(time.time() - helpers.cast_to_int(updated_at))) else: logger.error(u"PlexPy NotificationHandler :: Unable to retrieve server uptime.") server_uptime = 'N/A' on_extdown_subject = plexpy.CONFIG.NOTIFY_ON_EXTDOWN_SUBJECT_TEXT on_extdown_body = plexpy.CONFIG.NOTIFY_ON_EXTDOWN_BODY_TEXT on_intdown_subject = plexpy.CONFIG.NOTIFY_ON_INTDOWN_SUBJECT_TEXT on_intdown_body = plexpy.CONFIG.NOTIFY_ON_INTDOWN_BODY_TEXT on_extup_subject = plexpy.CONFIG.NOTIFY_ON_EXTUP_SUBJECT_TEXT on_extup_body = plexpy.CONFIG.NOTIFY_ON_EXTUP_BODY_TEXT on_intup_subject = plexpy.CONFIG.NOTIFY_ON_INTUP_SUBJECT_TEXT on_intup_body = plexpy.CONFIG.NOTIFY_ON_INTUP_BODY_TEXT script_args_text = plexpy.CONFIG.NOTIFY_SCRIPTS_ARGS_TEXT available_params = {# Global paramaters 'server_name': server_name, 'server_uptime': server_uptime, 'action': state.title(), 'datestamp': arrow.now().format(date_format), 'timestamp': arrow.now().format(time_format)} # Default text subject_text = 'PlexPy (%s)' % server_name # Default scripts args script_args = [] if script_args_text: try: script_args = [unicode(arg).format(**available_params) for arg in script_args_text.split()] except LookupError as e: logger.error(u"PlexPy Notifier :: Unable to parse field %s in script argument. Using fallback." % e) except Exception as e: logger.error(u"PlexPy Notifier :: Unable to parse custom script arguments %s. Using fallback." % e) if state == 'extdown': # Default body text body_text = 'The Plex Media Server remote access is down.' if on_extdown_subject and on_extdown_body: try: subject_text = unicode(on_extdown_subject).format(**available_params) except LookupError, e: logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification subject. Using fallback." % e) except:
def _validate_config(self, config=None, default=None): if config is None: return default new_config = {} for k, v in default.items(): if isinstance(v, int): new_config[k] = helpers.cast_to_int(config.get(k, v)) elif isinstance(v, list): c = config.get(k, v) if not isinstance(c, list): new_config[k] = [c] else: new_config[k] = c else: new_config[k] = config.get(k, v) return new_config
def get_media_info_file_sizes(self, section_id=None, rating_key=None): from plexpy import pmsconnect import json, os if section_id and not str(section_id).isdigit(): logger.warn(u"PlexPy Libraries :: Datatable media info file size called by invalid section_id provided.") return False elif rating_key and not str(rating_key).isdigit(): logger.warn(u"PlexPy Libraries :: Datatable media info file size called by invalid rating_key provided.") return False # Get the library details library_details = self.get_details(section_id=section_id) if library_details['section_id'] == None: logger.debug(u"PlexPy Libraries :: Library section_id %s not found." % section_id) return False if library_details['section_type'] == 'photo': return False rows = [] # Import media info cache from json file if rating_key: #logger.debug(u"PlexPy Libraries :: Getting file sizes for rating_key %s." % rating_key) try: inFilePath = os.path.join(plexpy.CONFIG.CACHE_DIR,'media_info_%s-%s.json' % (section_id, rating_key)) with open(inFilePath, 'r') as inFile: rows = json.load(inFile) except IOError as e: #logger.debug(u"PlexPy Libraries :: No JSON file for rating_key %s." % rating_key) #logger.debug(u"PlexPy Libraries :: Refreshing data and creating new JSON file for rating_key %s." % rating_key) pass elif section_id: logger.debug(u"PlexPy Libraries :: Getting file sizes for section_id %s." % section_id) try: inFilePath = os.path.join(plexpy.CONFIG.CACHE_DIR,'media_info_%s.json' % section_id) with open(inFilePath, 'r') as inFile: rows = json.load(inFile) except IOError as e: #logger.debug(u"PlexPy Libraries :: No JSON file for library section_id %s." % section_id) #logger.debug(u"PlexPy Libraries :: Refreshing data and creating new JSON file for section_id %s." % section_id) pass # Get the total file size for each item pms_connect = pmsconnect.PmsConnect() for item in rows: if item['rating_key'] and not item['file_size']: file_size = 0 child_metadata = pms_connect.get_metadata_children_details(rating_key=item['rating_key'], get_children=True, get_media_info=True) metadata_list = child_metadata['metadata'] for child_metadata in metadata_list: file_size += helpers.cast_to_int(child_metadata.get('file_size', 0)) item['file_size'] = file_size # Cache the media info to a json file if rating_key: try: outFilePath = os.path.join(plexpy.CONFIG.CACHE_DIR,'media_info_%s-%s.json' % (section_id, rating_key)) with open(outFilePath, 'w') as outFile: json.dump(rows, outFile) except IOError as e: logger.debug(u"PlexPy Libraries :: Unable to create cache file with file sizes for rating_key %s." % rating_key) elif section_id: try: outFilePath = os.path.join(plexpy.CONFIG.CACHE_DIR,'media_info_%s.json' % section_id) with open(outFilePath, 'w') as outFile: json.dump(rows, outFile) except IOError as e: logger.debug(u"PlexPy Libraries :: Unable to create cache file with file sizes for section_id %s." % section_id) if rating_key: #logger.debug(u"PlexPy Libraries :: File sizes updated for rating_key %s." % rating_key) pass elif section_id: logger.debug(u"PlexPy Libraries :: File sizes updated for section_id %s." % section_id) return True
def get_datatables_media_info(self, section_id=None, section_type=None, rating_key=None, refresh=False, kwargs=None): from plexpy import pmsconnect import json, os default_return = {'recordsFiltered': 0, 'recordsTotal': 0, 'draw': 0, 'data': None, 'error': 'Unable to execute database query.'} if section_id and not str(section_id).isdigit(): logger.warn(u"PlexPy Libraries :: Datatable media info called by invalid section_id provided.") return default_return elif rating_key and not str(rating_key).isdigit(): logger.warn(u"PlexPy Libraries :: Datatable media info called by invalid rating_key provided.") return default_return # Get the library details library_details = self.get_details(section_id=section_id) if library_details['section_id'] == None: logger.debug(u"PlexPy Libraries :: Library section_id %s not found." % section_id) return default_return if not section_type: section_type = library_details['section_type'] # Get play counts from the database monitor_db = database.MonitorDatabase() if plexpy.CONFIG.GROUP_HISTORY_TABLES: count_by = 'reference_id' else: count_by = 'id' if section_type == 'show' or section_type == 'artist': group_by = 'grandparent_rating_key' elif section_type == 'season' or section_type == 'album': group_by = 'parent_rating_key' else: group_by = 'rating_key' try: query = 'SELECT MAX(session_history.started) AS last_played, COUNT(DISTINCT session_history.%s) AS play_count, ' \ 'session_history.rating_key, session_history.parent_rating_key, session_history.grandparent_rating_key ' \ 'FROM session_history ' \ 'JOIN session_history_metadata ON session_history.id = session_history_metadata.id ' \ 'WHERE session_history_metadata.section_id = ? ' \ 'GROUP BY session_history.%s ' % (count_by, group_by) result = monitor_db.select(query, args=[section_id]) except Exception as e: logger.warn(u"PlexPy Libraries :: Unable to execute database query for get_datatables_media_info2: %s." % e) return default_return watched_list = {} for item in result: watched_list[str(item[group_by])] = {'last_played': item['last_played'], 'play_count': item['play_count']} rows = [] # Import media info cache from json file if rating_key: try: inFilePath = os.path.join(plexpy.CONFIG.CACHE_DIR,'media_info_%s-%s.json' % (section_id, rating_key)) with open(inFilePath, 'r') as inFile: rows = json.load(inFile) library_count = len(rows) except IOError as e: #logger.debug(u"PlexPy Libraries :: No JSON file for rating_key %s." % rating_key) #logger.debug(u"PlexPy Libraries :: Refreshing data and creating new JSON file for rating_key %s." % rating_key) pass elif section_id: try: inFilePath = os.path.join(plexpy.CONFIG.CACHE_DIR,'media_info_%s.json' % section_id) with open(inFilePath, 'r') as inFile: rows = json.load(inFile) library_count = len(rows) except IOError as e: #logger.debug(u"PlexPy Libraries :: No JSON file for library section_id %s." % section_id) #logger.debug(u"PlexPy Libraries :: Refreshing data and creating new JSON file for section_id %s." % section_id) pass # If no cache was imported, get all library children items cached_items = {d['rating_key']: d['file_size'] for d in rows} if refresh or not rows: pms_connect = pmsconnect.PmsConnect() if rating_key: library_children = pms_connect.get_library_children_details(rating_key=rating_key, get_media_info=True) elif section_id: library_children = pms_connect.get_library_children_details(section_id=section_id, section_type=section_type, get_media_info=True) if library_children: library_count = library_children['library_count'] children_list = library_children['childern_list'] else: logger.warn(u"PlexPy Libraries :: Unable to get a list of library items.") return default_return new_rows = [] for item in children_list: cached_file_size = cached_items.get(item['rating_key'], None) file_size = cached_file_size if cached_file_size else item.get('file_size', '') row = {'section_id': library_details['section_id'], 'section_type': library_details['section_type'], 'added_at': item['added_at'], 'media_type': item['media_type'], 'rating_key': item['rating_key'], 'parent_rating_key': item['parent_rating_key'], 'grandparent_rating_key': item['grandparent_rating_key'], 'title': item['title'], 'year': item['year'], 'media_index': item['media_index'], 'parent_media_index': item['parent_media_index'], 'thumb': item['thumb'], 'container': item.get('container', ''), 'bitrate': item.get('bitrate', ''), 'video_codec': item.get('video_codec', ''), 'video_resolution': item.get('video_resolution', ''), 'video_framerate': item.get('video_framerate', ''), 'audio_codec': item.get('audio_codec', ''), 'audio_channels': item.get('audio_channels', ''), 'file_size': file_size } new_rows.append(row) rows = new_rows if not rows: return default_return # Cache the media info to a json file if rating_key: try: outFilePath = os.path.join(plexpy.CONFIG.CACHE_DIR,'media_info_%s-%s.json' % (section_id, rating_key)) with open(outFilePath, 'w') as outFile: json.dump(rows, outFile) except IOError as e: logger.debug(u"PlexPy Libraries :: Unable to create cache file for rating_key %s." % rating_key) elif section_id: try: outFilePath = os.path.join(plexpy.CONFIG.CACHE_DIR,'media_info_%s.json' % section_id) with open(outFilePath, 'w') as outFile: json.dump(rows, outFile) except IOError as e: logger.debug(u"PlexPy Libraries :: Unable to create cache file for section_id %s." % section_id) # Update the last_played and play_count for item in rows: watched_item = watched_list.get(item['rating_key'], None) if watched_item: item['last_played'] = watched_item['last_played'] item['play_count'] = watched_item['play_count'] else: item['last_played'] = None item['play_count'] = None results = [] # Get datatables JSON data if kwargs.get('json_data'): json_data = helpers.process_json_kwargs(json_kwargs=kwargs.get('json_data')) #print json_data # Search results search_value = json_data['search']['value'].lower() if search_value: searchable_columns = [d['data'] for d in json_data['columns'] if d['searchable']] for row in rows: for k,v in row.iteritems(): if k in searchable_columns and search_value in v.lower(): results.append(row) break else: results = rows filtered_count = len(results) # Sort results results = sorted(results, key=lambda k: k['title']) sort_order = json_data['order'] for order in reversed(sort_order): sort_key = json_data['columns'][int(order['column'])]['data'] reverse = True if order['dir'] == 'desc' else False if rating_key and sort_key == 'title': results = sorted(results, key=lambda k: helpers.cast_to_int(k['media_index']), reverse=reverse) elif sort_key == 'file_size' or sort_key == 'bitrate': results = sorted(results, key=lambda k: helpers.cast_to_int(k[sort_key]), reverse=reverse) else: results = sorted(results, key=lambda k: k[sort_key], reverse=reverse) total_file_size = sum([helpers.cast_to_int(d['file_size']) for d in results]) # Paginate results results = results[json_data['start']:(json_data['start'] + json_data['length'])] filtered_file_size = sum([helpers.cast_to_int(d['file_size']) for d in results]) dict = {'recordsFiltered': filtered_count, 'recordsTotal': library_count, 'data': results, 'draw': int(json_data['draw']), 'filtered_file_size': filtered_file_size, 'total_file_size': total_file_size } return dict
def _get_recently_added(self, media_type=None): from plexpy.notification_handler import format_group_index recently_added = [] done = False start = 0 while not done: for server_id in self.config['incl_servers']: server = plexpy.PMS_SERVERS.get_server_by_id(server_id) recent_items = server.PMSCONNECTION.get_recently_added_details( start=str(start), count='10', media_type=media_type) filtered_items = [ i for i in recent_items['recently_added'] if self.start_time < helpers.cast_to_int(i['added_at']) < self.end_time ] if len(filtered_items) < 10: done = True else: start += 10 recently_added.extend(filtered_items) if media_type in ('movie', 'other_video'): movie_list = [] for item in recently_added: # Filter included libraries if str(item['library_id'] ) not in self.config['incl_libraries']: continue movie_list.append(item) recently_added = movie_list if media_type == 'show': shows_list = [] show_rating_keys = [] for item in recently_added: # Filter included libraries if str(item['library_id'] ) not in self.config['incl_libraries']: continue if item['media_type'] == 'show': show_rating_key = item['rating_key'] elif item['media_type'] == 'season': show_rating_key = item['parent_rating_key'] elif item['media_type'] == 'episode': show_rating_key = item['grandparent_rating_key'] if show_rating_key in show_rating_keys: continue server = plexpy.PMS_SERVERS.get_server_by_id(item['server_id']) show_metadata = server.PMSCONNECTION.get_metadata_details( show_rating_key, media_info=False) show_metadata['pms_web_url'] = item['pms_web_url'] show_metadata['pms_identifier'] = item['pms_identifier'] children = server.PMSCONNECTION.get_item_children( show_rating_key, get_grandchildren=True) filtered_children = [ i for i in children['children_list'] if self.start_time < helpers.cast_to_int(i['added_at']) < self.end_time ] filtered_children.sort( key=lambda x: int(x['parent_media_index'])) seasons = [] for k, v in groupby(filtered_children, key=lambda x: x['parent_media_index']): episodes = list(v) num, num00 = format_group_index([ helpers.cast_to_int(d['media_index']) for d in episodes ]) seasons.append({ 'media_index': k, 'episode_range': num00, 'episode_count': len(episodes), 'episode': episodes }) num, num00 = format_group_index( [helpers.cast_to_int(d['media_index']) for d in seasons]) show_metadata['season_range'] = num00 show_metadata['season_count'] = len(seasons) show_metadata['season'] = seasons shows_list.append(show_metadata) show_rating_keys.append(show_rating_key) recently_added = shows_list if media_type == 'artist': artists_list = [] artist_rating_keys = [] for item in recently_added: # Filter included libraries if str(item['library_id'] ) not in self.config['incl_libraries']: continue if item['media_type'] == 'artist': artist_rating_key = item['rating_key'] elif item['media_type'] == 'album': artist_rating_key = item['parent_rating_key'] elif item['media_type'] == 'track': artist_rating_key = item['grandparent_rating_key'] if artist_rating_key in artist_rating_keys: continue server = plexpy.PMS_SERVERS.get_server_by_id(item['server_id']) artist_metadata = server.PMSCONNECTION.get_metadata_details( artist_rating_key, media_info=False) artist_metadata['pms_web_url'] = item['pms_web_url'] artist_metadata['pms_identifier'] = item['pms_identifier'] children = server.PMSCONNECTION.get_item_children( artist_rating_key) filtered_children = [ i for i in children['children_list'] if self.start_time < helpers.cast_to_int(i['added_at']) < self.end_time ] filtered_children.sort(key=lambda x: x['added_at']) albums = [] for a in filtered_children: album_metadata = server.PMSCONNECTION.get_metadata_details( a['rating_key'], media_info=False) album_metadata['pms_web_url'] = item['pms_web_url'] album_metadata['pms_identifier'] = item['pms_identifier'] album_metadata['track_count'] = helpers.cast_to_int( album_metadata['children_count']) albums.append(album_metadata) artist_metadata['album_count'] = len(albums) artist_metadata['album'] = albums artists_list.append(artist_metadata) artist_rating_keys.append(artist_rating_key) recently_added = artists_list return recently_added
def get_media_info_file_sizes(self, section_id=None, rating_key=None): from plexpy import pmsconnect import json, os if section_id and not str(section_id).isdigit(): logger.warn( u"PlexPy Libraries :: Datatable media info file size called by invalid section_id provided." ) return False elif rating_key and not str(rating_key).isdigit(): logger.warn( u"PlexPy Libraries :: Datatable media info file size called by invalid rating_key provided." ) return False # Get the library details library_details = self.get_details(section_id=section_id) if library_details['section_id'] == None: logger.debug( u"PlexPy Libraries :: Library section_id %s not found." % section_id) return False if library_details['section_type'] == 'photo': return False rows = [] # Import media info cache from json file if rating_key: #logger.debug(u"PlexPy Libraries :: Getting file sizes for rating_key %s." % rating_key) try: inFilePath = os.path.join( plexpy.CONFIG.CACHE_DIR, 'media_info_%s-%s.json' % (section_id, rating_key)) with open(inFilePath, 'r') as inFile: rows = json.load(inFile) except IOError as e: #logger.debug(u"PlexPy Libraries :: No JSON file for rating_key %s." % rating_key) #logger.debug(u"PlexPy Libraries :: Refreshing data and creating new JSON file for rating_key %s." % rating_key) pass elif section_id: logger.debug( u"PlexPy Libraries :: Getting file sizes for section_id %s." % section_id) try: inFilePath = os.path.join(plexpy.CONFIG.CACHE_DIR, 'media_info_%s.json' % section_id) with open(inFilePath, 'r') as inFile: rows = json.load(inFile) except IOError as e: #logger.debug(u"PlexPy Libraries :: No JSON file for library section_id %s." % section_id) #logger.debug(u"PlexPy Libraries :: Refreshing data and creating new JSON file for section_id %s." % section_id) pass # Get the total file size for each item pms_connect = pmsconnect.PmsConnect() for item in rows: if item['rating_key'] and not item['file_size']: file_size = 0 child_metadata = pms_connect.get_metadata_children_details( rating_key=item['rating_key'], get_children=True, get_media_info=True) metadata_list = child_metadata['metadata'] for child_metadata in metadata_list: file_size += helpers.cast_to_int( child_metadata.get('file_size', 0)) item['file_size'] = file_size # Cache the media info to a json file if rating_key: try: outFilePath = os.path.join( plexpy.CONFIG.CACHE_DIR, 'media_info_%s-%s.json' % (section_id, rating_key)) with open(outFilePath, 'w') as outFile: json.dump(rows, outFile) except IOError as e: logger.debug( u"PlexPy Libraries :: Unable to create cache file with file sizes for rating_key %s." % rating_key) elif section_id: try: outFilePath = os.path.join(plexpy.CONFIG.CACHE_DIR, 'media_info_%s.json' % section_id) with open(outFilePath, 'w') as outFile: json.dump(rows, outFile) except IOError as e: logger.debug( u"PlexPy Libraries :: Unable to create cache file with file sizes for section_id %s." % section_id) if rating_key: #logger.debug(u"PlexPy Libraries :: File sizes updated for rating_key %s." % rating_key) pass elif section_id: logger.debug( u"PlexPy Libraries :: File sizes updated for section_id %s." % section_id) return True
def get_datatables_media_info(self, section_id=None, section_type=None, rating_key=None, refresh=False, kwargs=None): from plexpy import pmsconnect import json, os default_return = { 'recordsFiltered': 0, 'recordsTotal': 0, 'draw': 0, 'data': None, 'error': 'Unable to execute database query.' } if section_id and not str(section_id).isdigit(): logger.warn( u"PlexPy Libraries :: Datatable media info called by invalid section_id provided." ) return default_return elif rating_key and not str(rating_key).isdigit(): logger.warn( u"PlexPy Libraries :: Datatable media info called by invalid rating_key provided." ) return default_return # Get the library details library_details = self.get_details(section_id=section_id) if library_details['section_id'] == None: logger.debug( u"PlexPy Libraries :: Library section_id %s not found." % section_id) return default_return if not section_type: section_type = library_details['section_type'] # Get play counts from the database monitor_db = database.MonitorDatabase() if plexpy.CONFIG.GROUP_HISTORY_TABLES: count_by = 'reference_id' else: count_by = 'id' if section_type == 'show' or section_type == 'artist': group_by = 'grandparent_rating_key' elif section_type == 'season' or section_type == 'album': group_by = 'parent_rating_key' else: group_by = 'rating_key' try: query = 'SELECT MAX(session_history.started) AS last_played, COUNT(DISTINCT session_history.%s) AS play_count, ' \ 'session_history.rating_key, session_history.parent_rating_key, session_history.grandparent_rating_key ' \ 'FROM session_history ' \ 'JOIN session_history_metadata ON session_history.id = session_history_metadata.id ' \ 'WHERE session_history_metadata.section_id = ? ' \ 'GROUP BY session_history.%s ' % (count_by, group_by) result = monitor_db.select(query, args=[section_id]) except Exception as e: logger.warn( u"PlexPy Libraries :: Unable to execute database query for get_datatables_media_info2: %s." % e) return default_return watched_list = {} for item in result: watched_list[str(item[group_by])] = { 'last_played': item['last_played'], 'play_count': item['play_count'] } rows = [] # Import media info cache from json file if rating_key: try: inFilePath = os.path.join( plexpy.CONFIG.CACHE_DIR, 'media_info_%s-%s.json' % (section_id, rating_key)) with open(inFilePath, 'r') as inFile: rows = json.load(inFile) library_count = len(rows) except IOError as e: #logger.debug(u"PlexPy Libraries :: No JSON file for rating_key %s." % rating_key) #logger.debug(u"PlexPy Libraries :: Refreshing data and creating new JSON file for rating_key %s." % rating_key) pass elif section_id: try: inFilePath = os.path.join(plexpy.CONFIG.CACHE_DIR, 'media_info_%s.json' % section_id) with open(inFilePath, 'r') as inFile: rows = json.load(inFile) library_count = len(rows) except IOError as e: #logger.debug(u"PlexPy Libraries :: No JSON file for library section_id %s." % section_id) #logger.debug(u"PlexPy Libraries :: Refreshing data and creating new JSON file for section_id %s." % section_id) pass # If no cache was imported, get all library children items cached_items = {d['rating_key']: d['file_size'] for d in rows} if refresh or not rows: pms_connect = pmsconnect.PmsConnect() if rating_key: library_children = pms_connect.get_library_children_details( rating_key=rating_key, get_media_info=True) elif section_id: library_children = pms_connect.get_library_children_details( section_id=section_id, section_type=section_type, get_media_info=True) if library_children: library_count = library_children['library_count'] children_list = library_children['childern_list'] else: logger.warn( u"PlexPy Libraries :: Unable to get a list of library items." ) return default_return new_rows = [] for item in children_list: cached_file_size = cached_items.get(item['rating_key'], None) file_size = cached_file_size if cached_file_size else item.get( 'file_size', '') row = { 'section_id': library_details['section_id'], 'section_type': library_details['section_type'], 'added_at': item['added_at'], 'media_type': item['media_type'], 'rating_key': item['rating_key'], 'parent_rating_key': item['parent_rating_key'], 'grandparent_rating_key': item['grandparent_rating_key'], 'title': item['title'], 'year': item['year'], 'media_index': item['media_index'], 'parent_media_index': item['parent_media_index'], 'thumb': item['thumb'], 'container': item.get('container', ''), 'bitrate': item.get('bitrate', ''), 'video_codec': item.get('video_codec', ''), 'video_resolution': item.get('video_resolution', ''), 'video_framerate': item.get('video_framerate', ''), 'audio_codec': item.get('audio_codec', ''), 'audio_channels': item.get('audio_channels', ''), 'file_size': file_size } new_rows.append(row) rows = new_rows if not rows: return default_return # Cache the media info to a json file if rating_key: try: outFilePath = os.path.join( plexpy.CONFIG.CACHE_DIR, 'media_info_%s-%s.json' % (section_id, rating_key)) with open(outFilePath, 'w') as outFile: json.dump(rows, outFile) except IOError as e: logger.debug( u"PlexPy Libraries :: Unable to create cache file for rating_key %s." % rating_key) elif section_id: try: outFilePath = os.path.join( plexpy.CONFIG.CACHE_DIR, 'media_info_%s.json' % section_id) with open(outFilePath, 'w') as outFile: json.dump(rows, outFile) except IOError as e: logger.debug( u"PlexPy Libraries :: Unable to create cache file for section_id %s." % section_id) # Update the last_played and play_count for item in rows: watched_item = watched_list.get(item['rating_key'], None) if watched_item: item['last_played'] = watched_item['last_played'] item['play_count'] = watched_item['play_count'] else: item['last_played'] = None item['play_count'] = None results = [] # Get datatables JSON data if kwargs.get('json_data'): json_data = helpers.process_json_kwargs( json_kwargs=kwargs.get('json_data')) #print json_data # Search results search_value = json_data['search']['value'].lower() if search_value: searchable_columns = [ d['data'] for d in json_data['columns'] if d['searchable'] ] for row in rows: for k, v in row.iteritems(): if k in searchable_columns and search_value in v.lower(): results.append(row) break else: results = rows filtered_count = len(results) # Sort results results = sorted(results, key=lambda k: k['title']) sort_order = json_data['order'] for order in reversed(sort_order): sort_key = json_data['columns'][int(order['column'])]['data'] reverse = True if order['dir'] == 'desc' else False if rating_key and sort_key == 'title': results = sorted( results, key=lambda k: helpers.cast_to_int(k['media_index']), reverse=reverse) elif sort_key == 'file_size' or sort_key == 'bitrate': results = sorted( results, key=lambda k: helpers.cast_to_int(k[sort_key]), reverse=reverse) else: results = sorted(results, key=lambda k: k[sort_key], reverse=reverse) total_file_size = sum( [helpers.cast_to_int(d['file_size']) for d in results]) # Paginate results results = results[json_data['start']:(json_data['start'] + json_data['length'])] filtered_file_size = sum( [helpers.cast_to_int(d['file_size']) for d in results]) dict = { 'recordsFiltered': filtered_count, 'recordsTotal': library_count, 'data': results, 'draw': int(json_data['draw']), 'filtered_file_size': filtered_file_size, 'total_file_size': total_file_size } return dict
def build_notify_text(session=None, timeline=None, state=None): # Get time formats date_format = plexpy.CONFIG.DATE_FORMAT.replace('Do','').replace('zz','') time_format = plexpy.CONFIG.TIME_FORMAT.replace('Do','').replace('zz','') duration_format = plexpy.CONFIG.TIME_FORMAT.replace('Do','').replace('zz','').replace('a','').replace('A','') # Get the server name server_name = plexpy.CONFIG.PMS_NAME # Get the server uptime plex_tv = plextv.PlexTV() server_times = plex_tv.get_server_times() if server_times: updated_at = server_times[0]['updated_at'] server_uptime = helpers.human_duration(int(time.time() - helpers.cast_to_int(updated_at))) else: logger.error(u"PlexPy NotificationHandler :: Unable to retrieve server uptime.") server_uptime = 'N/A' # Get metadata feed for item if session: rating_key = session['rating_key'] elif timeline: rating_key = timeline['rating_key'] pms_connect = pmsconnect.PmsConnect() metadata_list = pms_connect.get_metadata_details(rating_key=rating_key) stream_count = pms_connect.get_current_activity().get('stream_count', '') if metadata_list: metadata = metadata_list['metadata'] else: logger.error(u"PlexPy NotificationHandler :: Unable to retrieve metadata for rating_key %s" % str(rating_key)) return [] # Check for exclusion tags if metadata['media_type'] == 'movie': # Regex pattern to remove the text in the tags we don't want pattern = re.compile('\n*<tv>[^>]+.</tv>\n*|\n*<music>[^>]+.</music>\n*', re.IGNORECASE | re.DOTALL) elif metadata['media_type'] == 'show' or metadata['media_type'] == 'episode': # Regex pattern to remove the text in the tags we don't want pattern = re.compile('\n*<movie>[^>]+.</movie>\n*|\n*?<music>[^>]+.</music>\n*', re.IGNORECASE | re.DOTALL) elif metadata['media_type'] == 'artist' or metadata['media_type'] == 'track': # Regex pattern to remove the text in the tags we don't want pattern = re.compile('\n*<tv>[^>]+.</tv>\n*|\n*<movie>[^>]+.</movie>\n*', re.IGNORECASE | re.DOTALL) else: pattern = None if metadata['media_type'] == 'movie' \ or metadata['media_type'] == 'show' or metadata['media_type'] == 'episode' \ or metadata['media_type'] == 'artist' or metadata['media_type'] == 'track' \ and pattern: # Remove the unwanted tags and strip any unmatch tags too. on_start_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_START_SUBJECT_TEXT)) on_start_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_START_BODY_TEXT)) on_stop_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_STOP_SUBJECT_TEXT)) on_stop_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_STOP_BODY_TEXT)) on_pause_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_PAUSE_SUBJECT_TEXT)) on_pause_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_PAUSE_BODY_TEXT)) on_resume_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_RESUME_SUBJECT_TEXT)) on_resume_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_RESUME_BODY_TEXT)) on_buffer_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_BUFFER_SUBJECT_TEXT)) on_buffer_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_BUFFER_BODY_TEXT)) on_watched_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_WATCHED_SUBJECT_TEXT)) on_watched_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_WATCHED_BODY_TEXT)) on_created_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_CREATED_SUBJECT_TEXT)) on_created_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_CREATED_BODY_TEXT)) script_args_text = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_SCRIPTS_ARGS_TEXT)) else: on_start_subject = plexpy.CONFIG.NOTIFY_ON_START_SUBJECT_TEXT on_start_body = plexpy.CONFIG.NOTIFY_ON_START_BODY_TEXT on_stop_subject = plexpy.CONFIG.NOTIFY_ON_STOP_SUBJECT_TEXT on_stop_body = plexpy.CONFIG.NOTIFY_ON_STOP_BODY_TEXT on_pause_subject = plexpy.CONFIG.NOTIFY_ON_PAUSE_SUBJECT_TEXT on_pause_body = plexpy.CONFIG.NOTIFY_ON_PAUSE_BODY_TEXT on_resume_subject = plexpy.CONFIG.NOTIFY_ON_RESUME_SUBJECT_TEXT on_resume_body = plexpy.CONFIG.NOTIFY_ON_RESUME_BODY_TEXT on_buffer_subject = plexpy.CONFIG.NOTIFY_ON_BUFFER_SUBJECT_TEXT on_buffer_body = plexpy.CONFIG.NOTIFY_ON_BUFFER_BODY_TEXT on_watched_subject = plexpy.CONFIG.NOTIFY_ON_WATCHED_SUBJECT_TEXT on_watched_body = plexpy.CONFIG.NOTIFY_ON_WATCHED_BODY_TEXT on_created_subject = plexpy.CONFIG.NOTIFY_ON_CREATED_SUBJECT_TEXT on_created_body = plexpy.CONFIG.NOTIFY_ON_CREATED_BODY_TEXT script_args_text = plexpy.CONFIG.NOTIFY_SCRIPTS_ARGS_TEXT # Create a title if metadata['media_type'] == 'episode' or metadata['media_type'] == 'track': full_title = '%s - %s' % (metadata['grandparent_title'], metadata['title']) else: full_title = metadata['title'] # Session values if session is None: session = {} # Generate a combined transcode decision value if session.get('video_decision','') == 'transcode' or session.get('audio_decision','') == 'transcode': transcode_decision = 'Transcode' elif session.get('video_decision','') == 'copy' or session.get('audio_decision','') == 'copy': transcode_decision = 'Direct Stream' else: transcode_decision = 'Direct Play' if state != 'play': stream_duration = int((time.time() - helpers.cast_to_int(session.get('started', 0)) - helpers.cast_to_int(session.get('paused_counter', 0))) / 60) else: stream_duration = 0 view_offset = helpers.convert_milliseconds_to_minutes(session.get('view_offset', 0)) duration = helpers.convert_milliseconds_to_minutes(metadata['duration']) progress_percent = helpers.get_percent(view_offset, duration) remaining_duration = duration - view_offset # Get media IDs from guid and build URLs if 'imdb://' in metadata['guid']: metadata['imdb_id'] = metadata['guid'].split('imdb://')[1].split('?')[0] metadata['imdb_url'] = 'https://www.imdb.com/title/' + metadata['imdb_id'] metadata['trakt_url'] = 'https://trakt.tv/search/imdb/' + metadata['imdb_id'] if 'thetvdb://' in metadata['guid']: metadata['thetvdb_id'] = metadata['guid'].split('thetvdb://')[1].split('/')[0] metadata['thetvdb_url'] = 'https://thetvdb.com/?tab=series&id=' + metadata['thetvdb_id'] metadata['trakt_url'] = 'https://trakt.tv/search/tvdb/' + metadata['thetvdb_id'] + '?id_type=show' elif 'thetvdbdvdorder://' in metadata['guid']: metadata['thetvdb_id'] = metadata['guid'].split('thetvdbdvdorder://')[1].split('/')[0] metadata['thetvdb_url'] = 'https://thetvdb.com/?tab=series&id=' + metadata['thetvdb_id'] metadata['trakt_url'] = 'https://trakt.tv/search/tvdb/' + metadata['thetvdb_id'] + '?id_type=show' if 'themoviedb://' in metadata['guid']: if metadata['media_type'] == 'movie': metadata['themoviedb_id'] = metadata['guid'].split('themoviedb://')[1].split('?')[0] metadata['themoviedb_url'] = 'https://www.themoviedb.org/movie/' + metadata['themoviedb_id'] metadata['trakt_url'] = 'https://trakt.tv/search/tmdb/' + metadata['themoviedb_id'] + '?id_type=movie' elif metadata['media_type'] == 'show' or metadata['media_type'] == 'episode': metadata['themoviedb_id'] = metadata['guid'].split('themoviedb://')[1].split('/')[0] metadata['themoviedb_url'] = 'https://www.themoviedb.org/tv/' + metadata['themoviedb_id'] metadata['trakt_url'] = 'https://trakt.tv/search/tmdb/' + metadata['themoviedb_id'] + '?id_type=show' if 'lastfm://' in metadata['guid']: metadata['lastfm_id'] = metadata['guid'].split('lastfm://')[1].rsplit('/', 1)[0] metadata['lastfm_url'] = 'https://www.last.fm/music/' + metadata['lastfm_id'] if metadata['media_type'] == 'movie' or metadata['media_type'] == 'show' or metadata['media_type'] == 'artist': thumb = metadata['thumb'] elif metadata['media_type'] == 'episode': thumb = metadata['grandparent_thumb'] elif metadata['media_type'] == 'track': thumb = metadata['parent_thumb'] else: thumb = None if thumb: # 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 metadata['poster_url'] = helpers.uploadToImgur(os.path.join(plexpy.CONFIG.CACHE_DIR, 'cache-poster.jpg'), full_title) # Fix metadata params for notify recently added grandparent if state == 'created' and plexpy.CONFIG.NOTIFY_RECENTLY_ADDED_GRANDPARENT: show_name = metadata['title'] episode_name = '' artist_name = metadata['title'] album_name = '' track_name = '' else: show_name = metadata['grandparent_title'] episode_name = metadata['title'] artist_name = metadata['grandparent_title'] album_name = metadata['parent_title'] track_name = metadata['title'] available_params = {# Global paramaters 'server_name': server_name, 'server_uptime': server_uptime, 'action': state.title(), 'datestamp': arrow.now().format(date_format), 'timestamp': arrow.now().format(time_format), # Stream parameters 'streams': stream_count, 'user': session.get('friendly_name',''), 'platform': session.get('platform',''), 'player': session.get('player',''), 'ip_address': session.get('ip_address','N/A'), 'stream_duration': stream_duration, 'stream_time': arrow.get(stream_duration * 60).format(duration_format), 'remaining_duration': remaining_duration, 'remaining_time': arrow.get(remaining_duration * 60).format(duration_format), 'progress_duration': view_offset, 'progress_time': arrow.get(view_offset * 60).format(duration_format), 'progress_percent': progress_percent, 'container': session.get('container',''), 'video_codec': session.get('video_codec',''), 'video_bitrate': session.get('bitrate',''), 'video_width': session.get('width',''), 'video_height': session.get('height',''), 'video_resolution': session.get('video_resolution',''), 'video_framerate': session.get('video_framerate',''), 'aspect_ratio': session.get('aspect_ratio',''), 'audio_codec': session.get('audio_codec',''), 'audio_channels': session.get('audio_channels',''), 'transcode_decision': transcode_decision, 'video_decision': session.get('video_decision','').title(), 'audio_decision': session.get('audio_decision','').title(), 'transcode_container': session.get('transcode_container',''), 'transcode_video_codec': session.get('transcode_video_codec',''), 'transcode_video_width': session.get('transcode_width',''), 'transcode_video_height': session.get('transcode_height',''), 'transcode_audio_codec': session.get('transcode_audio_codec',''), 'transcode_audio_channels': session.get('transcode_audio_channels',''), 'session_key': session.get('session_key',''), 'user_id': session.get('user_id',''), 'machine_id': session.get('machine_id',''), # Metadata parameters 'media_type': metadata['media_type'], 'title': full_title, 'library_name': metadata['library_name'], 'show_name': show_name, 'episode_name': episode_name, 'artist_name': artist_name, 'album_name': album_name, 'track_name': track_name, 'season_num': metadata['parent_media_index'].zfill(1), 'season_num00': metadata['parent_media_index'].zfill(2), 'episode_num': metadata['media_index'].zfill(1), 'episode_num00': metadata['media_index'].zfill(2), 'track_num': metadata['media_index'].zfill(1), 'track_num00': metadata['media_index'].zfill(2), 'year': metadata['year'], 'studio': metadata['studio'], 'content_rating': metadata['content_rating'], 'directors': ', '.join(metadata['directors']), 'writers': ', '.join(metadata['writers']), 'actors': ', '.join(metadata['actors']), 'genres': ', '.join(metadata['genres']), 'summary': metadata['summary'], 'tagline': metadata['tagline'], 'rating': metadata['rating'], 'duration': duration, 'poster_url': metadata.get('poster_url',''), 'imdb_id': metadata.get('imdb_id',''), 'imdb_url': metadata.get('imdb_url',''), 'thetvdb_id': metadata.get('thetvdb_id',''), 'thetvdb_url': metadata.get('thetvdb_url',''), 'themoviedb_id': metadata.get('themoviedb_id',''), 'themoviedb_url': metadata.get('themoviedb_url',''), 'lastfm_url': metadata.get('lastfm_url',''), 'trakt_url': metadata.get('trakt_url',''), '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 subject_text = 'PlexPy (%s)' % server_name # Default scripts args script_args = [] if script_args_text: try: script_args = [unicode(arg).format(**available_params) for arg in script_args_text.split()] except LookupError as e: logger.error(u"PlexPy Notifier :: Unable to parse field %s in script argument. Using fallback." % e) except Exception as e: logger.error(u"PlexPy Notifier :: Unable to parse custom script arguments %s. Using fallback." % e) if state == 'play': # Default body text body_text = '%s (%s) started playing %s' % (session['friendly_name'], session['player'], full_title) if on_start_subject and on_start_body: try: subject_text = unicode(on_start_subject).format(**available_params) except LookupError, e: logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification subject. Using fallback." % e) except:
def build_notify_text(session=None, timeline=None, state=None): # Get time formats date_format = plexpy.CONFIG.DATE_FORMAT.replace("Do", "").replace("zz", "") time_format = plexpy.CONFIG.TIME_FORMAT.replace("Do", "").replace("zz", "") duration_format = plexpy.CONFIG.TIME_FORMAT.replace("Do", "").replace("zz", "").replace("a", "").replace("A", "") # Get the server name server_name = plexpy.CONFIG.PMS_NAME # Get the server uptime plex_tv = plextv.PlexTV() server_times = plex_tv.get_server_times() if server_times: updated_at = server_times[0]["updated_at"] server_uptime = helpers.human_duration(int(time.time() - helpers.cast_to_int(updated_at))) else: logger.error(u"PlexPy NotificationHandler :: Unable to retrieve server uptime.") server_uptime = "N/A" # Get metadata feed for item if session: rating_key = session["rating_key"] elif timeline: rating_key = timeline["rating_key"] pms_connect = pmsconnect.PmsConnect() metadata_list = pms_connect.get_metadata_details(rating_key=rating_key) stream_count = pms_connect.get_current_activity().get("stream_count", "") if metadata_list: metadata = metadata_list["metadata"] else: logger.error(u"PlexPy NotificationHandler :: Unable to retrieve metadata for rating_key %s" % str(rating_key)) return [] # Check for exclusion tags if metadata["media_type"] == "movie": # Regex pattern to remove the text in the tags we don't want pattern = re.compile("\n*<tv>[^>]+.</tv>\n*|\n*<music>[^>]+.</music>\n*", re.IGNORECASE | re.DOTALL) elif metadata["media_type"] == "show" or metadata["media_type"] == "episode": # Regex pattern to remove the text in the tags we don't want pattern = re.compile("\n*<movie>[^>]+.</movie>\n*|\n*?<music>[^>]+.</music>\n*", re.IGNORECASE | re.DOTALL) elif metadata["media_type"] == "artist" or metadata["media_type"] == "track": # Regex pattern to remove the text in the tags we don't want pattern = re.compile("\n*<tv>[^>]+.</tv>\n*|\n*<movie>[^>]+.</movie>\n*", re.IGNORECASE | re.DOTALL) else: pattern = None if ( metadata["media_type"] == "movie" or metadata["media_type"] == "show" or metadata["media_type"] == "episode" or metadata["media_type"] == "artist" or metadata["media_type"] == "track" and pattern ): # Remove the unwanted tags and strip any unmatch tags too. on_start_subject = strip_tag(re.sub(pattern, "", plexpy.CONFIG.NOTIFY_ON_START_SUBJECT_TEXT)) on_start_body = strip_tag(re.sub(pattern, "", plexpy.CONFIG.NOTIFY_ON_START_BODY_TEXT)) on_stop_subject = strip_tag(re.sub(pattern, "", plexpy.CONFIG.NOTIFY_ON_STOP_SUBJECT_TEXT)) on_stop_body = strip_tag(re.sub(pattern, "", plexpy.CONFIG.NOTIFY_ON_STOP_BODY_TEXT)) on_pause_subject = strip_tag(re.sub(pattern, "", plexpy.CONFIG.NOTIFY_ON_PAUSE_SUBJECT_TEXT)) on_pause_body = strip_tag(re.sub(pattern, "", plexpy.CONFIG.NOTIFY_ON_PAUSE_BODY_TEXT)) on_resume_subject = strip_tag(re.sub(pattern, "", plexpy.CONFIG.NOTIFY_ON_RESUME_SUBJECT_TEXT)) on_resume_body = strip_tag(re.sub(pattern, "", plexpy.CONFIG.NOTIFY_ON_RESUME_BODY_TEXT)) on_buffer_subject = strip_tag(re.sub(pattern, "", plexpy.CONFIG.NOTIFY_ON_BUFFER_SUBJECT_TEXT)) on_buffer_body = strip_tag(re.sub(pattern, "", plexpy.CONFIG.NOTIFY_ON_BUFFER_BODY_TEXT)) on_watched_subject = strip_tag(re.sub(pattern, "", plexpy.CONFIG.NOTIFY_ON_WATCHED_SUBJECT_TEXT)) on_watched_body = strip_tag(re.sub(pattern, "", plexpy.CONFIG.NOTIFY_ON_WATCHED_BODY_TEXT)) on_created_subject = strip_tag(re.sub(pattern, "", plexpy.CONFIG.NOTIFY_ON_CREATED_SUBJECT_TEXT)) on_created_body = strip_tag(re.sub(pattern, "", plexpy.CONFIG.NOTIFY_ON_CREATED_BODY_TEXT)) script_args_text = strip_tag(re.sub(pattern, "", plexpy.CONFIG.NOTIFY_SCRIPTS_ARGS_TEXT)) else: on_start_subject = plexpy.CONFIG.NOTIFY_ON_START_SUBJECT_TEXT on_start_body = plexpy.CONFIG.NOTIFY_ON_START_BODY_TEXT on_stop_subject = plexpy.CONFIG.NOTIFY_ON_STOP_SUBJECT_TEXT on_stop_body = plexpy.CONFIG.NOTIFY_ON_STOP_BODY_TEXT on_pause_subject = plexpy.CONFIG.NOTIFY_ON_PAUSE_SUBJECT_TEXT on_pause_body = plexpy.CONFIG.NOTIFY_ON_PAUSE_BODY_TEXT on_resume_subject = plexpy.CONFIG.NOTIFY_ON_RESUME_SUBJECT_TEXT on_resume_body = plexpy.CONFIG.NOTIFY_ON_RESUME_BODY_TEXT on_buffer_subject = plexpy.CONFIG.NOTIFY_ON_BUFFER_SUBJECT_TEXT on_buffer_body = plexpy.CONFIG.NOTIFY_ON_BUFFER_BODY_TEXT on_watched_subject = plexpy.CONFIG.NOTIFY_ON_WATCHED_SUBJECT_TEXT on_watched_body = plexpy.CONFIG.NOTIFY_ON_WATCHED_BODY_TEXT on_created_subject = plexpy.CONFIG.NOTIFY_ON_CREATED_SUBJECT_TEXT on_created_body = plexpy.CONFIG.NOTIFY_ON_CREATED_BODY_TEXT script_args_text = plexpy.CONFIG.NOTIFY_SCRIPTS_ARGS_TEXT # Create a title if metadata["media_type"] == "episode" or metadata["media_type"] == "track": full_title = "%s - %s" % (metadata["grandparent_title"], metadata["title"]) else: full_title = metadata["title"] # Session values if session is None: session = {} # Generate a combined transcode decision value if session.get("video_decision", "") == "transcode" or session.get("audio_decision", "") == "transcode": transcode_decision = "Transcode" elif session.get("video_decision", "") == "copy" or session.get("audio_decision", "") == "copy": transcode_decision = "Direct Stream" else: transcode_decision = "Direct Play" if state != "play": stream_duration = helpers.convert_seconds_to_minutes( time.time() - helpers.cast_to_int(session.get("started", 0)) - helpers.cast_to_int(session.get("paused_counter", 0)) ) else: stream_duration = 0 view_offset = helpers.convert_milliseconds_to_minutes(session.get("view_offset", 0)) duration = helpers.convert_milliseconds_to_minutes(metadata["duration"]) progress_percent = helpers.get_percent(view_offset, duration) remaining_duration = duration - view_offset # Fix metadata params for notify recently added grandparent if state == "created" and plexpy.CONFIG.NOTIFY_RECENTLY_ADDED_GRANDPARENT: show_name = metadata["title"] episode_name = "" artist_name = metadata["title"] album_name = "" track_name = "" else: show_name = metadata["grandparent_title"] episode_name = metadata["title"] artist_name = metadata["grandparent_title"] album_name = metadata["parent_title"] track_name = metadata["title"] available_params = { # Global paramaters "server_name": server_name, "server_uptime": server_uptime, "action": state.title(), "datestamp": arrow.now().format(date_format), "timestamp": arrow.now().format(time_format), # Stream parameters "streams": stream_count, "user": session.get("friendly_name", ""), "platform": session.get("platform", ""), "player": session.get("player", ""), "ip_address": session.get("ip_address", "N/A"), "stream_duration": stream_duration, "stream_time": arrow.get(stream_duration * 60).format(duration_format), "remaining_duration": remaining_duration, "remaining_time": arrow.get(remaining_duration * 60).format(duration_format), "progress_duration": view_offset, "progress_time": arrow.get(view_offset * 60).format(duration_format), "progress_percent": progress_percent, "container": session.get("container", ""), "video_codec": session.get("video_codec", ""), "video_bitrate": session.get("bitrate", ""), "video_width": session.get("width", ""), "video_height": session.get("height", ""), "video_resolution": session.get("video_resolution", ""), "video_framerate": session.get("video_framerate", ""), "aspect_ratio": session.get("aspect_ratio", ""), "audio_codec": session.get("audio_codec", ""), "audio_channels": session.get("audio_channels", ""), "transcode_decision": transcode_decision, "video_decision": session.get("video_decision", "").title(), "audio_decision": session.get("audio_decision", "").title(), "transcode_container": session.get("transcode_container", ""), "transcode_video_codec": session.get("transcode_video_codec", ""), "transcode_video_width": session.get("transcode_width", ""), "transcode_video_height": session.get("transcode_height", ""), "transcode_audio_codec": session.get("transcode_audio_codec", ""), "transcode_audio_channels": session.get("transcode_audio_channels", ""), "session_key": session.get("session_key", ""), "user_id": session.get("user_id", ""), # Metadata parameters "media_type": metadata["media_type"], "title": full_title, "library_name": metadata["library_name"], "show_name": show_name, "episode_name": episode_name, "artist_name": artist_name, "album_name": album_name, "track_name": track_name, "season_num": metadata["parent_media_index"].zfill(1), "season_num00": metadata["parent_media_index"].zfill(2), "episode_num": metadata["media_index"].zfill(1), "episode_num00": metadata["media_index"].zfill(2), "track_num": metadata["media_index"].zfill(1), "track_num00": metadata["media_index"].zfill(2), "year": metadata["year"], "studio": metadata["studio"], "content_rating": metadata["content_rating"], "directors": ", ".join(metadata["directors"]), "writers": ", ".join(metadata["writers"]), "actors": ", ".join(metadata["actors"]), "genres": ", ".join(metadata["genres"]), "summary": metadata["summary"], "tagline": metadata["tagline"], "rating": metadata["rating"], "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 subject_text = "PlexPy (%s)" % server_name # Default scripts args script_args = [] if script_args_text: try: script_args = [unicode(arg).format(**available_params) for arg in script_args_text.split()] except LookupError as e: logger.error(u"PlexPy Notifier :: Unable to parse field %s in script argument. Using fallback." % e) except Exception as e: logger.error(u"PlexPy Notifier :: Unable to parse custom script arguments %s. Using fallback." % e) if state == "play": # Default body text body_text = "%s (%s) started playing %s" % (session["friendly_name"], session["player"], full_title) if on_start_subject and on_start_body: try: subject_text = unicode(on_start_subject).format(**available_params) except LookupError, e: logger.error( u"PlexPy NotificationHandler :: Unable to parse field %s in notification subject. Using fallback." % e ) except: