diff --git a/README.md b/README.md index baad255..4ef8297 100644 --- a/README.md +++ b/README.md @@ -130,9 +130,17 @@ The config file is in the scripts folder. Before first run of the script, pleas #####Filtering * filter_include_plex_web_link - True to add hyperlinks to the images and titles to go to Plex Web for the specific title * filter_show_movies - True to show recently added movies +* filter_movies_include - List of movies to include (Anything that does not match perfectly will not be included) +* filter_movies_excluse - List of movies to exclude (Only titles that match perfectly will be excluded) * filter_show_shows - True to show recently added TV shows +* filter_shows_include - List of shows to include (Anything that does not match perfectly will not be included) +* filter_shows_excluse - List of shows to exclude (Only titles that match perfectly will be excluded) * filter_show_seasons - True to show recently added TV seasons +* filter_seasons_include - List of seasons to include (Anything that does not match perfectly will not be included) +* filter_seasons_excluse - List of seasons to exclude (Only titles that match perfectly will be excluded) * filter_show_episodes - True to show recently added TV episodes +* filter_episodes_include - List of episodes to include (Anything that does not match perfectly will not be included) +* filter_episodes_excluse - List of episodes to exclude (Only titles that match perfectly will be excluded) * filter_show_email_images - True to show images in the email * filter_libraries - A list of library names to filter out - ['Home Videos', 'Private'] * filter_sections_movies - Movie specific filters @@ -144,6 +152,7 @@ The config file is in the scripts folder. Before first run of the script, pleas * postText - The text that should be added after this field for each title * include - A list of values that are each title must match at least one to be shown * exclude - A list of values that if the title matches any of, will not be shown + * format - Date format to be applied (Only use this for air_date) #####Messages * msg_notice - Used for special notices to the users. This can also be done through the command line using the -n flag. diff --git a/scripts/config.conf b/scripts/config.conf index d3736ff..a37c83c 100644 --- a/scripts/config.conf +++ b/scripts/config.conf @@ -57,10 +57,20 @@ email_skip_if_no_additions = False ##Filtering filter_include_plex_web_link = True filter_show_movies = True +filter_movies_include = [] +filter_movies_exclude = [] filter_show_shows = True +filter_shows_include = [] +filter_shows_exclude = [] filter_show_seasons = True +filter_seasons_include = [] +filter_seasons_exclude = [] filter_show_episodes = True +filter_episodes_include = [] +filter_episodes_exclude = [] filter_show_email_images = True +#Type of image to show for new TV Episodes - "episode", "season" or "show" (Defaults to episode) +filter_episode_thumbnail_type = 'episode' #Name of libraries to filter out - ['Home Videos', 'Private'] filter_libraries = [] #The sections to include and ordering - tagline, summary, content_rating, duration, year, rating, studio, tags_genre, tags_director, tags_star @@ -144,6 +154,15 @@ filter_sections_movies = { 'postText':'%', 'include':[], 'exclude':[] + }, + 'air_date':{ + 'order':11, + 'show': False, + 'preText':'Release Date: ', + 'postText':'', + 'include':[], + 'exclude':[], + 'format': '%B %d, %Y' } } filter_sections_TV = { @@ -226,6 +245,15 @@ filter_sections_TV = { 'postText':'%', 'include':[], 'exclude':[] + }, + 'air_date':{ + 'order':11, + 'show': True, + 'preText':'Air Date: ', + 'postText':'', + 'include':[], + 'exclude':[], + 'format': '%B %d, %Y' } } diff --git a/scripts/plexEmail.py b/scripts/plexEmail.py index 4c9ba46..aa7d5d4 100644 --- a/scripts/plexEmail.py +++ b/scripts/plexEmail.py @@ -12,6 +12,7 @@ import cloudinary.uploader import cloudinary.api import imghdr +import time from base64 import b64encode from collections import OrderedDict from datetime import date, timedelta @@ -24,6 +25,33 @@ def replaceConfigTokens(): ## The below code is for backwards compatibility + if ('filter_movies_include' not in config): + config['filter_movies_include'] = [] + + if ('filter_movies_exclude' not in config): + config['filter_movies_exclude'] = [] + + if ('filter_shows_include' not in config): + config['filter_movies_include'] = [] + + if ('filter_shows_exclude' not in config): + config['filter_movies_exclude'] = [] + + if ('filter_seasons_include' not in config): + config['filter_movies_include'] = [] + + if ('filter_seasons_exclude' not in config): + config['filter_movies_exclude'] = [] + + if ('filter_episodes_include' not in config): + config['filter_movies_include'] = [] + + if ('filter_episodes_exclude' not in config): + config['filter_movies_exclude'] = [] + + if ('filter_episode_thumbnail_type' not in config): + config['filter_episode_thumbnail_type'] = 'episode' + if ('email_unsubscribe' not in config): config['email_unsubscribe'] = [] @@ -357,7 +385,7 @@ def sendMail(email): #Create image headers for image in imgNames: fp = open(imgNames[image], 'rb') - msgImage = MIMEImage(fp.read()) + msgImage = MIMEImage(fp.read(), _subtype="jpg") fp.close() msgImage.add_header('Content-ID', '<' + image + '>') msg.attach(msgImage) @@ -697,11 +725,11 @@ def createWebHTML(): dateSearch = 'datetime(\'now\', \'localtime\', \'-' + str(config['date_days_back_to_search']) + ' days\', \'-' + str(config['date_hours_back_to_search']) + ' hours\', \'-' + str(config['date_minutes_back_to_search']) + ' minutes\')' cur = con.cursor() - cur.execute("SELECT MD.id, MD.parent_id, MD.metadata_type, MD.title, MD.title_sort, MD.original_title, MD.rating, MD.tagline, MD.summary, MD.content_rating, MD.duration, MD.user_thumb_url, MD.tags_genre, MD.tags_director, MD.tags_star, MD.year, MD.hash, MD.[index], MD.studio, ME.duration FROM metadata_items MD LEFT OUTER JOIN media_items ME ON MD.id = ME.metadata_item_id WHERE added_at >= " + dateSearch + " AND metadata_type >= 1 AND metadata_type <= 4 " + libraryFilter + " ORDER BY title_sort;") + cur.execute("SELECT MD.id, MD.parent_id, MD.metadata_type, MD.title, MD.title_sort, MD.original_title, MD.rating, MD.tagline, MD.summary, MD.content_rating, MD.duration, MD.user_thumb_url, MD.tags_genre, MD.tags_director, MD.tags_star, MD.year, MD.hash, MD.[index], MD.studio, ME.duration, MD.originally_available_at FROM metadata_items MD LEFT OUTER JOIN media_items ME ON MD.id = ME.metadata_item_id WHERE added_at >= " + dateSearch + " AND metadata_type >= 1 AND metadata_type <= 4 " + libraryFilter + " ORDER BY title_sort;") response = {}; for row in cur: - response[row[0]] = {'id': row[0], 'parent_id': row[1], 'metadata_type': row[2], 'title': row[3], 'title_sort': row[4], 'original_title': row[5], 'rating': row[6], 'tagline': row[7], 'summary': row[8], 'content_rating': row[9], 'duration': row[10], 'user_thumb_url': row[11], 'tags_genre': row[12], 'tags_director': row[13], 'tags_star': row[14], 'year': row[15], 'hash': row[16], 'index': row[17], 'studio': row[18], 'real_duration': row[19]} + response[row[0]] = {'id': row[0], 'parent_id': row[1], 'metadata_type': row[2], 'title': row[3], 'title_sort': row[4], 'original_title': row[5], 'rating': row[6], 'tagline': row[7], 'summary': row[8], 'content_rating': row[9], 'duration': row[10], 'user_thumb_url': row[11], 'tags_genre': row[12], 'tags_director': row[13], 'tags_star': row[14], 'year': row[15], 'hash': row[16], 'index': row[17], 'studio': row[18], 'real_duration': row[19], 'air_date': row[20]} emailNotice = '' htmlNotice = '' @@ -802,12 +830,20 @@ def createWebHTML(): if (movies[movie][section[0]] in sections[section[0]]['exclude'] or len(set(movies[movie][section[0] + '_filter']).intersection(sections[section[0]]['exclude'])) > 0 or (sections[section[0]]['include'] and movies[movie][section[0]] not in sections[section[0]]['include'] and len(set(movies[movie][section[0] + '_filter']).intersection(sections[section[0]]['include'])) == 0)): skipItem = True if (sections[section[0]]['show'] and movies[movie][section[0]] and movies[movie][section[0]] != ''): - emailText += '

' + sections[section[0]]['preText'].decode('utf-8') + str(movies[movie][section[0]]).decode('utf-8') + sections[section[0]]['postText'].decode('utf-8') + '

' - htmlText += '

' + sections[section[0]]['preText'].decode('utf-8') + str(movies[movie][section[0]]).decode('utf-8') + sections[section[0]]['postText'].decode('utf-8') + '

' + displayText = str(movies[movie][section[0]]) + if ('format' in sections[section[0]] and sections[section[0]]['format'] != ''): + displayText = time.strftime(sections[section[0]]['format'], time.strptime(displayText, '%Y-%m-%d %H:%M:%S')) + emailText += '

' + sections[section[0]]['preText'].decode('utf-8') + displayText.decode('utf-8') + sections[section[0]]['postText'].decode('utf-8') + '

' + htmlText += '

' + sections[section[0]]['preText'].decode('utf-8') + displayText.decode('utf-8') + sections[section[0]]['postText'].decode('utf-8') + '

' emailText += '
 
 ' htmlText += '
 
 ' + titleFilter = [] + + if (movies[movie]['title'] in config['filter_movies_exclude'] or len(set(titleFilter).intersection(config['filter_movies_exclude'])) > 0 or (config['filter_movies_include'] and movies[movie]['title'] not in config['filter_movies_include'] and len(set(titleFilter).intersection(config['filter_movies_include'])) == 0)): + skipItem = True + if (not skipItem): movieCount += 1 emailMovies += emailText @@ -852,12 +888,20 @@ def createWebHTML(): if (tvShows[show][section[0]] in sections[section[0]]['exclude'] or len(set(tvShows[show][section[0] + '_filter']).intersection(sections[section[0]]['exclude'])) > 0 or (sections[section[0]]['include'] and tvShows[show][section[0]] not in sections[section[0]]['include'] and len(set(tvShows[show][section[0] + '_filter']).intersection(sections[section[0]]['include'])) == 0)): skipItem = True if (sections[section[0]]['show'] and tvShows[show][section[0]] and tvShows[show][section[0]] != ''): - emailText += '

' + sections[section[0]]['preText'].decode('utf-8') + str(tvShows[show][section[0]]).decode('utf-8') + sections[section[0]]['postText'].decode('utf-8') + '

' - htmlText += '

' + sections[section[0]]['preText'].decode('utf-8') + str(tvShows[show][section[0]]).decode('utf-8') + sections[section[0]]['postText'].decode('utf-8') + '

' + displayText = str(tvShows[show][section[0]]) + if ('format' in sections[section[0]] and sections[section[0]]['format'] != ''): + displayText = time.strftime(sections[section[0]]['format'], time.strptime(displayText, '%Y-%m-%d %H:%M:%S')) + emailText += '

' + sections[section[0]]['preText'].decode('utf-8') + displayText.decode('utf-8') + sections[section[0]]['postText'].decode('utf-8') + '

' + htmlText += '

' + sections[section[0]]['preText'].decode('utf-8') + displayText.decode('utf-8') + sections[section[0]]['postText'].decode('utf-8') + '

' emailText += '
 
 ' htmlText += '
 
 ' + titleFilter = [] + + if (tvShows[show]['title'] in config['filter_shows_exclude'] or len(set(titleFilter).intersection(config['filter_shows_exclude'])) > 0 or (config['filter_shows_include'] and tvShows[show]['title'] not in config['filter_shows_include'] and len(set(titleFilter).intersection(config['filter_shows_include'])) == 0)): + skipItem = True + if (not skipItem): showCount += 1 emailTVShows += emailText @@ -935,6 +979,11 @@ def createWebHTML(): emailText += '
 
 ' htmlText += '
 
 ' + titleFilter = [] + + if (tvSeasons[season]['title'] in config['filter_seasons_exclude'] or len(set(titleFilter).intersection(config['filter_seasons_exclude'])) > 0 or (config['filter_seasons_include'] and tvSeasons[season]['title'] not in config['filter_seasons_include'] and len(set(titleFilter).intersection(config['filter_seasons_include'])) == 0)): + skipItem = True + if (not skipItem): seasonCount += 1 emailTVSeasons += emailText @@ -984,13 +1033,14 @@ def createWebHTML(): title += tvEpisodes[episode]['title'] hash = str(tvEpisodes[episode]['hash']) imageInfo = {} - if (tvEpisodes[episode]['user_thumb_url'] != ''): + imageTypeToUse = 'show' if (tvEpisodes[episode]['show_thumb_url'] != '' and config['filter_episode_thumbnail_type'] == 'show') else 'season' if (tvEpisodes[episode]['season_thumb_url'] != '' and config['filter_episode_thumbnail_type'] == 'season') else 'episode' if (tvEpisodes[episode]['user_thumb_url'] != '') else '' + if (imageTypeToUse == 'episode'): imageInfo['thumb'] = tvEpisodes[episode]['user_thumb_url'] imageInfo = processImage(hash, imageInfo['thumb'], 'episode', tvEpisodes[episode]['season_index'], tvEpisodes[episode]['index']) - elif (tvEpisodes[episode]['season_thumb_url'] != ''): + elif (imageTypeToUse == 'season'): imageInfo['thumb'] = tvEpisodes[episode]['season_thumb_url'] imageInfo = processImage(hash, imageInfo['thumb'], 'season', tvEpisodes[episode]['season_index'], 0) - elif (tvEpisodes[episode]['show_thumb_url'] != ''): + elif (imageTypeToUse == 'show'): imageInfo['thumb'] = tvEpisodes[episode]['show_thumb_url'] imageInfo = processImage(hash, imageInfo['thumb'], 'show', 0, 0) @@ -1017,12 +1067,20 @@ def createWebHTML(): if (tvEpisodes[episode][section[0]] in sections[section[0]]['exclude'] or len(set(tvEpisodes[episode][section[0] + '_filter']).intersection(sections[section[0]]['exclude'])) > 0 or (sections[section[0]]['include'] and tvEpisodes[episode][section[0]] not in sections[section[0]]['include'] and len(set(tvEpisodes[episode][section[0] + '_filter']).intersection(sections[section[0]]['include'])) == 0)): skipItem = True if (sections[section[0]]['show'] and tvEpisodes[episode][section[0]] and tvEpisodes[episode][section[0]] != ''): - emailText += '

' + sections[section[0]]['preText'].decode('utf-8') + str(tvEpisodes[episode][section[0]]).decode('utf-8') + sections[section[0]]['postText'].decode('utf-8') + '

' - htmlText += '

' + sections[section[0]]['preText'].decode('utf-8') + str(tvEpisodes[episode][section[0]]).decode('utf-8') + sections[section[0]]['postText'].decode('utf-8') + '

' + displayText = str(tvEpisodes[episode][section[0]]) + if ('format' in sections[section[0]] and sections[section[0]]['format'] != ''): + displayText = time.strftime(sections[section[0]]['format'], time.strptime(displayText, '%Y-%m-%d %H:%M:%S')) + emailText += '

' + sections[section[0]]['preText'].decode('utf-8') + displayText.decode('utf-8') + sections[section[0]]['postText'].decode('utf-8') + '

' + htmlText += '

' + sections[section[0]]['preText'].decode('utf-8') + displayText.decode('utf-8') + sections[section[0]]['postText'].decode('utf-8') + '

' emailText += '
 
 ' htmlText += '
 
 ' + titleFilter = [] + + if (tvEpisodes[episode]['show_title'] in config['filter_episodes_exclude'] or len(set(titleFilter).intersection(config['filter_episodes_exclude'])) > 0 or (config['filter_episodes_include'] and tvEpisodes[episode]['show_title'] not in config['filter_episodes_include'] and len(set(titleFilter).intersection(config['filter_episodes_include'])) == 0)): + skipItem = True + if (not skipItem): episodeCount += 1 emailTVEpisodes += emailText