2021-05-19 20:42:05 +00:00
import logging , os , re
2021-02-20 05:41:45 +00:00
from datetime import datetime , timedelta
2021-11-27 00:30:41 +00:00
from modules import anidb , anilist , flixpatrol , icheckmovies , imdb , letterboxd , mal , plex , radarr , sonarr , stevenlu , tautulli , tmdb , trakt , tvdb , util
2021-10-21 14:00:16 +00:00
from modules . util import Failed , ImageData , NotScheduled
2021-07-14 14:47:20 +00:00
from PIL import Image
2021-03-01 20:59:10 +00:00
from plexapi . exceptions import BadRequest , NotFound
2021-08-22 15:54:33 +00:00
from plexapi . video import Movie , Show , Season , Episode
2021-05-05 18:01:41 +00:00
from urllib . parse import quote
2021-02-20 05:41:45 +00:00
logger = logging . getLogger ( " Plex Meta Manager " )
2021-05-05 18:01:41 +00:00
string_filters = [ " title " , " episode_title " , " studio " ]
2021-04-21 12:49:27 +00:00
advance_new_agent = [ " item_metadata_language " , " item_use_original_title " ]
advance_show = [ " item_episode_sorting " , " item_keep_episodes " , " item_delete_episodes " , " item_season_display " , " item_episode_sorting " ]
2021-03-30 05:50:53 +00:00
method_alias = {
" actors " : " actor " , " role " : " actor " , " roles " : " actor " ,
2021-05-27 17:40:35 +00:00
" show_actor " : " actor " , " show_actors " : " actor " , " show_role " : " actor " , " show_roles " : " actor " ,
" collections " : " collection " , " plex_collection " : " collection " ,
" show_collections " : " collection " , " show_collection " : " collection " ,
2021-03-30 05:50:53 +00:00
" content_ratings " : " content_rating " , " contentRating " : " content_rating " , " contentRatings " : " content_rating " ,
" countries " : " country " ,
" decades " : " decade " ,
" directors " : " director " ,
" genres " : " genre " ,
" labels " : " label " ,
2021-04-01 16:32:41 +00:00
" rating " : " critic_rating " ,
2021-05-27 17:40:35 +00:00
" show_user_rating " : " user_rating " ,
2021-05-28 23:18:28 +00:00
" video_resolution " : " resolution " ,
2021-08-14 03:32:26 +00:00
" tmdb_trending " : " tmdb_trending_daily " ,
2021-05-27 17:40:35 +00:00
" play " : " plays " , " show_plays " : " plays " , " show_play " : " plays " , " episode_play " : " episode_plays " ,
" originally_available " : " release " , " episode_originally_available " : " episode_air_date " ,
" episode_release " : " episode_air_date " , " episode_released " : " episode_air_date " ,
" show_originally_available " : " release " , " show_release " : " release " , " show_air_date " : " release " ,
2021-05-28 23:18:28 +00:00
" released " : " release " , " show_released " : " release " , " max_age " : " release " ,
2021-04-01 15:34:02 +00:00
" studios " : " studio " ,
" networks " : " network " ,
2021-03-30 05:50:53 +00:00
" producers " : " producer " ,
" writers " : " writer " ,
2021-05-27 17:40:35 +00:00
" years " : " year " , " show_year " : " year " , " show_years " : " year " ,
2021-12-07 19:21:07 +00:00
" show_title " : " title " , " filter " : " filters " ,
2021-08-14 22:59:35 +00:00
" seasonyear " : " year " , " isadult " : " adult " , " startdate " : " start " , " enddate " : " end " , " averagescore " : " score " ,
2021-08-16 05:41:04 +00:00
" minimum_tag_percentage " : " min_tag_percent " , " minimumtagrank " : " min_tag_percent " , " minimum_tag_rank " : " min_tag_percent " ,
2021-08-17 00:07:35 +00:00
" anilist_tag " : " anilist_search " , " anilist_genre " : " anilist_search " , " anilist_season " : " anilist_search " ,
2021-10-25 15:40:49 +00:00
" mal_producer " : " mal_studio " , " mal_licensor " : " mal_studio " ,
" trakt_recommended " : " trakt_recommended_weekly " , " trakt_watched " : " trakt_watched_weekly " , " trakt_collected " : " trakt_collected_weekly "
2021-03-30 05:50:53 +00:00
}
2021-05-26 04:35:54 +00:00
filter_translation = {
2021-05-12 14:25:48 +00:00
" actor " : " actors " ,
" audience_rating " : " audienceRating " ,
" collection " : " collections " ,
" content_rating " : " contentRating " ,
" country " : " countries " ,
" critic_rating " : " rating " ,
" director " : " directors " ,
" genre " : " genres " ,
2021-05-27 17:40:35 +00:00
" label " : " labels " ,
" producer " : " producers " ,
" release " : " originallyAvailableAt " ,
2021-05-28 23:18:28 +00:00
" added " : " addedAt " ,
" last_played " : " lastViewedAt " ,
" plays " : " viewCount " ,
2021-05-12 14:25:48 +00:00
" user_rating " : " userRating " ,
" writer " : " writers "
}
2021-05-05 18:01:41 +00:00
modifier_alias = { " .greater " : " .gt " , " .less " : " .lt " }
2021-11-27 00:30:41 +00:00
all_builders = anidb . builders + anilist . builders + flixpatrol . builders + icheckmovies . builders + imdb . builders + \
letterboxd . builders + mal . builders + plex . builders + stevenlu . builders + tautulli . builders + \
tmdb . builders + trakt . builders + tvdb . builders
2021-12-09 06:37:11 +00:00
show_only_builders = [ " tmdb_network " , " tmdb_show " , " tmdb_show_details " , " tvdb_show " , " tvdb_show_details " , " collection_level " , " item_tmdb_season_titles " ]
2021-03-30 05:50:53 +00:00
movie_only_builders = [
2021-08-01 01:23:17 +00:00
" letterboxd_list " , " letterboxd_list_details " , " icheckmovies_list " , " icheckmovies_list_details " , " stevenlu_popular " ,
2021-07-23 19:44:21 +00:00
" tmdb_collection " , " tmdb_collection_details " , " tmdb_movie " , " tmdb_movie_details " , " tmdb_now_playing " ,
2021-11-13 23:51:12 +00:00
" tvdb_movie " , " tvdb_movie_details " , " trakt_boxoffice "
2021-05-02 04:22:48 +00:00
]
2021-06-22 20:28:12 +00:00
summary_details = [
" summary " , " tmdb_summary " , " tmdb_description " , " tmdb_biography " , " tvdb_summary " ,
2021-07-03 19:17:05 +00:00
" tvdb_description " , " trakt_description " , " letterboxd_description " , " icheckmovies_description "
2021-06-22 20:28:12 +00:00
]
2021-07-23 19:44:21 +00:00
poster_details = [ " url_poster " , " tmdb_poster " , " tmdb_profile " , " tvdb_poster " , " file_poster " ]
background_details = [ " url_background " , " tmdb_background " , " tvdb_background " , " file_background " ]
2021-10-04 17:51:32 +00:00
boolean_details = [
2021-11-03 14:36:11 +00:00
" visible_library " , " visible_home " , " visible_shared " , " show_filtered " , " show_missing " , " save_missing " ,
2021-12-01 16:59:49 +00:00
" missing_only_released " , " only_filter_missing " , " delete_below_minimum "
2021-10-04 17:51:32 +00:00
]
2021-07-23 19:44:21 +00:00
string_details = [ " sort_title " , " content_rating " , " name_mapping " ]
2021-08-22 15:54:33 +00:00
ignored_details = [
2021-12-07 16:23:20 +00:00
" smart_filter " , " smart_label " , " smart_url " , " run_again " , " schedule " , " sync_mode " , " template " , " test " , " delete_not_scheduled " ,
2021-12-17 14:24:46 +00:00
" tmdb_person " , " build_collection " , " collection_order " , " collection_level " , " validate_builders " , " collection_name " , " sort_by " , " libraries "
2021-08-22 15:54:33 +00:00
]
2021-12-13 22:51:31 +00:00
details = [ " ignore_ids " , " ignore_imdb_ids " , " server_preroll " , " collection_changes_webhooks " , " collection_mode " ,
" collection_minimum " , " label " ] + boolean_details + string_details
2021-07-23 19:44:21 +00:00
collectionless_details = [ " collection_order " , " plex_collectionless " , " label " , " label_sync_mode " , " test " ] + \
poster_details + background_details + summary_details + string_details
2021-12-09 06:37:11 +00:00
item_bool_details = [ " item_tmdb_season_titles " , " item_assets " , " revert_overlay " , " item_lock_background " , " item_lock_poster " , " item_lock_title " , " item_refresh " ]
2021-11-24 13:22:17 +00:00
item_details = [ " item_label " , " item_radarr_tag " , " item_sonarr_tag " , " item_overlay " ] + item_bool_details + list ( plex . item_advance_keys . keys ( ) )
2021-12-03 04:23:22 +00:00
none_details = [ " label.sync " , " item_label.sync " ]
2021-08-16 05:41:04 +00:00
radarr_details = [ " radarr_add " , " radarr_add_existing " , " radarr_folder " , " radarr_monitor " , " radarr_search " , " radarr_availability " , " radarr_quality " , " radarr_tag " ]
2021-08-22 15:54:33 +00:00
sonarr_details = [
" sonarr_add " , " sonarr_add_existing " , " sonarr_folder " , " sonarr_monitor " , " sonarr_language " , " sonarr_series " ,
" sonarr_quality " , " sonarr_season " , " sonarr_search " , " sonarr_cutoff_search " , " sonarr_tag "
]
2021-12-09 05:40:49 +00:00
parts_collection_valid = [
" plex_search " , " trakt_list " , " trakt_list_details " , " collection_mode " , " label " , " visible_library " , " collection_changes_webhooks "
" visible_home " , " visible_shared " , " show_missing " , " save_missing " , " missing_only_released " , " server_preroll " ,
2021-12-18 05:59:53 +00:00
" item_lock_background " , " item_lock_poster " , " item_lock_title " , " item_refresh " , " imdb_list "
2021-12-09 05:40:49 +00:00
] + summary_details + poster_details + background_details + string_details
2021-03-30 05:50:53 +00:00
all_filters = [
" actor " , " actor.not " ,
" audio_language " , " audio_language.not " ,
2021-09-13 02:42:33 +00:00
" audio_track_title " , " audio_track_title.not " , " audio_track_title.is " , " audio_track_title.isnot " , " audio_track_title.begins " , " audio_track_title.ends " , " audio_track_title.regex " ,
2021-03-30 05:50:53 +00:00
" collection " , " collection.not " ,
" content_rating " , " content_rating.not " ,
" country " , " country.not " ,
" director " , " director.not " ,
2021-09-13 02:42:33 +00:00
" filepath " , " filepath.not " , " filepath.is " , " filepath.isnot " , " filepath.begins " , " filepath.ends " , " filepath.regex " ,
2021-03-30 05:50:53 +00:00
" genre " , " genre.not " ,
2021-05-28 23:18:28 +00:00
" label " , " label.not " ,
" producer " , " producer.not " ,
2021-06-03 04:20:49 +00:00
" release " , " release.not " , " release.before " , " release.after " , " release.regex " , " history " ,
2021-06-02 22:36:24 +00:00
" added " , " added.not " , " added.before " , " added.after " , " added.regex " ,
" last_played " , " last_played.not " , " last_played.before " , " last_played.after " , " last_played.regex " ,
2021-08-06 23:17:19 +00:00
" first_episode_aired " , " first_episode_aired.not " , " first_episode_aired.before " , " first_episode_aired.after " , " first_episode_aired.regex " ,
2021-08-04 19:17:34 +00:00
" last_episode_aired " , " last_episode_aired.not " , " last_episode_aired.before " , " last_episode_aired.after " , " last_episode_aired.regex " ,
2021-09-13 02:42:33 +00:00
" title " , " title.not " , " title.is " , " title.isnot " , " title.begins " , " title.ends " , " title.regex " ,
2021-05-28 23:18:28 +00:00
" plays.gt " , " plays.gte " , " plays.lt " , " plays.lte " ,
" tmdb_vote_count.gt " , " tmdb_vote_count.gte " , " tmdb_vote_count.lt " , " tmdb_vote_count.lte " ,
" duration.gt " , " duration.gte " , " duration.lt " , " duration.lte " ,
2021-03-30 05:50:53 +00:00
" original_language " , " original_language.not " ,
2021-05-28 23:18:28 +00:00
" user_rating.gt " , " user_rating.gte " , " user_rating.lt " , " user_rating.lte " ,
" audience_rating.gt " , " audience_rating.gte " , " audience_rating.lt " , " audience_rating.lte " ,
" critic_rating.gt " , " critic_rating.gte " , " critic_rating.lt " , " critic_rating.lte " ,
2021-09-13 02:42:33 +00:00
" studio " , " studio.not " , " studio.is " , " studio.isnot " , " studio.begins " , " studio.ends " , " studio.regex " ,
2021-03-30 05:50:53 +00:00
" subtitle_language " , " subtitle_language.not " ,
2021-05-28 23:18:28 +00:00
" resolution " , " resolution.not " ,
2021-12-18 03:27:05 +00:00
" writer " , " writer.not " , " has_collection " , " has_overlay " ,
2021-05-28 23:18:28 +00:00
" year " , " year.gt " , " year.gte " , " year.lt " , " year.lte " , " year.not "
2021-08-09 15:40:44 +00:00
" tmdb_year " , " tmdb_year.gt " , " tmdb_year.gte " , " tmdb_year.lt " , " tmdb_year.lte " , " tmdb_year.not "
2021-03-30 05:50:53 +00:00
]
2021-08-09 15:40:44 +00:00
tmdb_filters = [ " original_language " , " tmdb_vote_count " , " tmdb_year " , " first_episode_aired " , " last_episode_aired " ]
2021-12-18 05:59:53 +00:00
boolean_filters = [ " has_collection " , " has_overlay " ]
2021-03-30 05:50:53 +00:00
movie_only_filters = [
" audio_language " , " audio_language.not " ,
2021-09-13 02:42:33 +00:00
" audio_track_title " , " audio_track_title.not " , " audio_track_title.is " , " audio_track_title.isnot " , " audio_track_title.begins " , " audio_track_title.ends " , " audio_track_title.regex " ,
2021-03-30 05:50:53 +00:00
" country " , " country.not " ,
" director " , " director.not " ,
2021-05-30 21:03:03 +00:00
" duration.gt " , " duration.gte " , " duration.lt " , " duration.lte " ,
2021-03-30 05:50:53 +00:00
" original_language " , " original_language.not " ,
" subtitle_language " , " subtitle_language.not " ,
2021-05-28 23:18:28 +00:00
" resolution " , " resolution.not " ,
2021-03-30 05:50:53 +00:00
" writer " , " writer.not "
]
2021-08-06 23:17:19 +00:00
show_only_filters = [ " first_episode_aired " , " last_episode_aired " , " network " ]
2021-08-22 15:54:33 +00:00
smart_invalid = [ " collection_order " , " collection_level " ]
2021-07-23 19:44:21 +00:00
smart_url_invalid = [ " filters " , " run_again " , " sync_mode " , " show_filtered " , " show_missing " , " save_missing " , " smart_label " ] + radarr_details + sonarr_details
2021-07-29 02:26:39 +00:00
custom_sort_builders = [
2021-12-03 04:23:22 +00:00
" plex_search " , " tmdb_list " , " tmdb_popular " , " tmdb_now_playing " , " tmdb_top_rated " ,
2021-07-29 21:36:26 +00:00
" tmdb_trending_daily " , " tmdb_trending_weekly " , " tmdb_discover " ,
2021-12-10 15:28:51 +00:00
" tvdb_list " , " imdb_chart " , " imdb_list " , " stevenlu_popular " , " anidb_popular " ,
2021-11-13 23:51:12 +00:00
" trakt_list " , " trakt_trending " , " trakt_popular " , " trakt_boxoffice " ,
2021-10-25 16:43:13 +00:00
" trakt_collected_daily " , " trakt_collected_weekly " , " trakt_collected_monthly " , " trakt_collected_yearly " , " trakt_collected_all " ,
2021-12-01 13:17:28 +00:00
" flixpatrol_url " , " flixpatrol_demographics " , " flixpatrol_popular " , " flixpatrol_top " ,
2021-10-25 16:43:13 +00:00
" trakt_recommended_daily " , " trakt_recommended_weekly " , " trakt_recommended_monthly " , " trakt_recommended_yearly " , " trakt_recommended_all " ,
" trakt_watched_daily " , " trakt_watched_weekly " , " trakt_watched_monthly " , " trakt_watched_yearly " , " trakt_watched_all " ,
2021-07-29 21:36:26 +00:00
" tautulli_popular " , " tautulli_watched " , " letterboxd_list " , " icheckmovies_list " ,
2021-08-16 05:41:04 +00:00
" anilist_top_rated " , " anilist_popular " , " anilist_season " , " anilist_studio " , " anilist_genre " , " anilist_tag " , " anilist_search " ,
2021-07-29 21:36:26 +00:00
" mal_all " , " mal_airing " , " mal_upcoming " , " mal_tv " , " mal_movie " , " mal_ova " , " mal_special " ,
2021-08-17 00:07:35 +00:00
" mal_popular " , " mal_favorite " , " mal_suggested " , " mal_userlist " , " mal_season " , " mal_genre " , " mal_studio "
2021-07-29 02:26:39 +00:00
]
2021-12-17 14:24:46 +00:00
playlist_attributes = [
" playlist_name " , " filters " , " name_mapping " , " show_filtered " , " show_missing " , " save_missing " ,
" missing_only_released " , " only_filter_missing " , " delete_below_minimum " , " ignore_ids " , " ignore_imdb_ids " ,
" server_preroll " , " collection_changes_webhooks " , " collection_minimum "
] + custom_sort_builders + summary_details + poster_details + radarr_details + sonarr_details
2021-03-30 05:50:53 +00:00
2021-02-20 05:41:45 +00:00
class CollectionBuilder :
2021-12-13 07:30:19 +00:00
def __init__ ( self , config , library , metadata , name , no_missing , data , playlist = False ) :
2021-02-20 05:41:45 +00:00
self . config = config
self . library = library
2021-05-07 15:29:29 +00:00
self . metadata = metadata
2021-09-13 00:05:38 +00:00
self . mapping_name = name
2021-08-16 05:41:04 +00:00
self . no_missing = no_missing
2021-02-20 05:41:45 +00:00
self . data = data
2021-12-13 07:30:19 +00:00
self . playlist = playlist
2021-07-21 20:59:27 +00:00
self . language = self . library . Plex . language
2021-02-20 06:41:40 +00:00
self . details = {
2021-05-26 14:45:33 +00:00
" show_filtered " : self . library . show_filtered ,
2021-12-17 00:16:08 +00:00
" show_options " : self . library . show_options ,
2021-05-26 14:45:33 +00:00
" show_missing " : self . library . show_missing ,
2021-06-30 22:26:53 +00:00
" save_missing " : self . library . save_missing ,
2021-08-16 05:41:04 +00:00
" missing_only_released " : self . library . missing_only_released ,
2021-12-01 16:59:49 +00:00
" only_filter_missing " : self . library . only_filter_missing ,
2021-08-02 19:00:15 +00:00
" create_asset_folders " : self . library . create_asset_folders ,
2021-10-04 17:51:32 +00:00
" delete_below_minimum " : self . library . delete_below_minimum ,
2021-12-06 22:30:38 +00:00
" delete_not_scheduled " : self . library . delete_not_scheduled ,
2021-12-07 06:29:41 +00:00
" collection_changes_webhooks " : self . library . collection_changes_webhooks
2021-02-20 06:41:40 +00:00
}
2021-04-21 12:49:27 +00:00
self . item_details = { }
2021-08-16 05:41:04 +00:00
self . radarr_details = { }
self . sonarr_details = { }
2021-03-01 20:59:10 +00:00
self . missing_movies = [ ]
self . missing_shows = [ ]
2021-08-22 15:54:33 +00:00
self . missing_parts = [ ]
2021-07-29 02:26:39 +00:00
self . builders = [ ]
2021-02-20 05:41:45 +00:00
self . filters = [ ]
2021-08-05 14:59:45 +00:00
self . tmdb_filters = [ ]
2021-12-17 14:24:46 +00:00
self . added_items = [ ]
2021-08-09 15:50:41 +00:00
self . filtered_keys = { }
2021-05-14 19:22:59 +00:00
self . run_again_movies = [ ]
self . run_again_shows = [ ]
2021-11-03 14:36:11 +00:00
self . notification_additions = [ ]
self . notification_removals = [ ]
2021-09-15 03:16:59 +00:00
self . items = [ ]
2021-02-28 23:06:04 +00:00
self . posters = { }
self . backgrounds = { }
self . summaries = { }
2021-02-26 18:15:05 +00:00
self . schedule = " "
2021-09-13 01:37:56 +00:00
self . minimum = self . library . collection_minimum
2021-12-08 05:17:35 +00:00
self . ignore_ids = [ i for i in self . library . ignore_ids ]
self . ignore_imdb_ids = [ i for i in self . library . ignore_imdb_ids ]
2021-12-08 03:31:20 +00:00
self . server_preroll = None
2021-05-27 17:40:35 +00:00
self . current_time = datetime . now ( )
self . current_year = self . current_time . year
2021-12-13 19:43:36 +00:00
self . collection_poster = None
self . collection_background = None
2021-10-04 17:51:32 +00:00
self . exists = False
self . created = False
2021-12-09 04:57:00 +00:00
self . deleted = False
2021-12-13 07:30:19 +00:00
self . type = " playlist " if self . playlist else " collection "
self . Type = self . type . capitalize ( )
2021-02-20 05:41:45 +00:00
2021-03-21 23:00:10 +00:00
methods = { m . lower ( ) : m for m in self . data }
2021-12-13 07:30:19 +00:00
if f " { self . type } _name " in methods :
2021-09-13 00:05:38 +00:00
logger . debug ( " " )
2021-12-13 07:30:19 +00:00
logger . debug ( f " Validating Method: { self . type } _name " )
if not self . data [ methods [ f " { self . type } _name " ] ] :
raise Failed ( f " { self . Type } Error: { self . type } _name attribute is blank " )
logger . debug ( f " Value: { self . data [ methods [ ' {} _name ' . format ( self . type ) ] ] } " )
self . name = self . data [ methods [ f " { self . type } _name " ] ]
2021-09-13 00:05:38 +00:00
else :
self . name = self . mapping_name
2021-03-21 23:00:10 +00:00
if " template " in methods :
2021-08-05 14:59:45 +00:00
logger . debug ( " " )
logger . debug ( " Validating Method: template " )
2021-05-07 15:29:29 +00:00
if not self . metadata . templates :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: No templates found " )
2021-03-21 23:00:10 +00:00
elif not self . data [ methods [ " template " ] ] :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: template attribute is blank " )
2021-02-20 05:41:45 +00:00
else :
2021-05-24 15:23:21 +00:00
logger . debug ( f " Value: { self . data [ methods [ ' template ' ] ] } " )
2021-05-09 20:35:38 +00:00
for variables in util . get_list ( self . data [ methods [ " template " ] ] , split = False ) :
if not isinstance ( variables , dict ) :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: template attribute is not a dictionary " )
2021-05-09 20:35:38 +00:00
elif " name " not in variables :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: template sub-attribute name is required " )
2021-05-09 20:35:38 +00:00
elif not variables [ " name " ] :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: template sub-attribute name is blank " )
2021-05-09 20:35:38 +00:00
elif variables [ " name " ] not in self . metadata . templates :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: template { variables [ ' name ' ] } not found " )
2021-05-09 20:35:38 +00:00
elif not isinstance ( self . metadata . templates [ variables [ " name " ] ] , dict ) :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: template { variables [ ' name ' ] } is not a dictionary " )
2021-02-20 05:41:45 +00:00
else :
2021-05-09 20:35:38 +00:00
for tm in variables :
if not variables [ tm ] :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: template sub-attribute { tm } is blank " )
2021-05-09 20:35:38 +00:00
if " collection_name " not in variables :
variables [ " collection_name " ] = str ( self . name )
2021-02-20 05:41:45 +00:00
2021-05-09 20:35:38 +00:00
template_name = variables [ " name " ]
2021-05-07 15:29:29 +00:00
template = self . metadata . templates [ template_name ]
2021-03-02 00:30:33 +00:00
2021-02-20 05:41:45 +00:00
default = { }
if " default " in template :
if template [ " default " ] :
if isinstance ( template [ " default " ] , dict ) :
for dv in template [ " default " ] :
2021-03-02 00:30:33 +00:00
if template [ " default " ] [ dv ] :
default [ dv ] = template [ " default " ] [ dv ]
else :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: template default sub-attribute { dv } is blank " )
2021-02-20 05:41:45 +00:00
else :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: template sub-attribute default is not a dictionary " )
2021-02-20 05:41:45 +00:00
else :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: template sub-attribute default is blank " )
2021-02-20 05:41:45 +00:00
2021-03-02 00:30:33 +00:00
optional = [ ]
if " optional " in template :
if template [ " optional " ] :
2021-12-07 07:52:09 +00:00
for op in util . get_list ( template [ " optional " ] ) :
if op not in default :
optional . append ( str ( op ) )
else :
logger . warning ( f " Template Warning: variable { op } cannot be optional if it has a default " )
2021-03-02 00:30:33 +00:00
else :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: template sub-attribute optional is blank " )
2021-03-26 22:17:24 +00:00
2021-12-07 07:52:09 +00:00
if " move_collection_prefix " in template :
if template [ " move_collection_prefix " ] :
for op in util . get_list ( template [ " move_collection_prefix " ] ) :
variables [ " collection_name " ] = variables [ " collection_name " ] . replace ( f " { str ( op ) . strip ( ) } " , " " ) + f " , { str ( op ) . strip ( ) } "
else :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: template sub-attribute move_collection_prefix is blank " )
2021-12-07 07:52:09 +00:00
2021-05-09 20:35:38 +00:00
def check_data ( _data ) :
if isinstance ( _data , dict ) :
final_data = { }
for sm , sd in _data . items ( ) :
2021-02-28 18:18:21 +00:00
try :
2021-05-09 20:35:38 +00:00
final_data [ sm ] = check_data ( sd )
2021-02-28 18:18:21 +00:00
except Failed :
continue
2021-05-09 20:35:38 +00:00
elif isinstance ( _data , list ) :
final_data = [ ]
for li in _data :
try :
final_data . append ( check_data ( li ) )
except Failed :
continue
else :
txt = str ( _data )
2021-05-09 22:34:51 +00:00
def scan_text ( og_txt , var , var_value ) :
2021-05-09 20:35:38 +00:00
if og_txt == f " << { var } >> " :
2021-05-09 22:34:51 +00:00
return str ( var_value )
2021-05-09 20:35:38 +00:00
elif f " << { var } >> " in str ( og_txt ) :
return str ( og_txt ) . replace ( f " << { var } >> " , str ( var_value ) )
else :
return og_txt
for option in optional :
if option not in variables and f " << { option } >> " in txt :
raise Failed
for variable , variable_data in variables . items ( ) :
if variable != " name " :
2021-05-09 22:34:51 +00:00
txt = scan_text ( txt , variable , variable_data )
2021-05-09 20:35:38 +00:00
for dm , dd in default . items ( ) :
2021-05-09 22:34:51 +00:00
txt = scan_text ( txt , dm , dd )
if txt in [ " true " , " True " ] :
final_data = True
elif txt in [ " false " , " False " ] :
final_data = False
2021-02-20 05:41:45 +00:00
else :
2021-05-09 22:34:51 +00:00
try :
num_data = float ( txt )
final_data = int ( num_data ) if num_data . is_integer ( ) else num_data
except ( ValueError , TypeError ) :
final_data = txt
2021-05-09 20:35:38 +00:00
return final_data
for method_name , attr_data in template . items ( ) :
2021-12-07 07:52:09 +00:00
if method_name not in self . data and method_name not in [ " default " , " optional " , " move_collection_prefix " ] :
2021-05-09 20:35:38 +00:00
if attr_data is None :
logger . error ( f " Template Error: template attribute { method_name } is blank " )
continue
try :
self . data [ method_name ] = check_data ( attr_data )
methods [ method_name . lower ( ) ] = method_name
except Failed :
continue
2021-02-20 05:41:45 +00:00
2021-12-06 22:30:38 +00:00
if " delete_not_scheduled " in methods :
logger . debug ( " " )
logger . debug ( " Validating Method: delete_not_scheduled " )
logger . debug ( f " Value: { data [ methods [ ' delete_not_scheduled ' ] ] } " )
2021-12-13 07:30:19 +00:00
self . details [ " delete_not_scheduled " ] = self . _parse ( " delete_not_scheduled " , self . data , datatype = " bool " , methods = methods , default = False )
2021-12-06 22:30:38 +00:00
2021-12-12 07:38:59 +00:00
if " schedule " in methods and not config . requested_collections :
2021-08-05 14:59:45 +00:00
logger . debug ( " " )
logger . debug ( " Validating Method: schedule " )
2021-05-24 15:23:21 +00:00
if not self . data [ methods [ " schedule " ] ] :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: schedule attribute is blank " )
2021-05-24 15:23:21 +00:00
else :
logger . debug ( f " Value: { self . data [ methods [ ' schedule ' ] ] } " )
2021-12-18 03:02:24 +00:00
try :
util . schedule_check ( self . data [ methods [ ' schedule ' ] ] , self . current_time , self . config . run_hour )
except NotScheduled as e :
2021-12-06 22:30:38 +00:00
suffix = " "
if self . details [ " delete_not_scheduled " ] :
try :
self . obj = self . library . get_collection ( self . name )
self . delete_collection ( )
2021-12-09 04:57:00 +00:00
self . deleted = True
2021-12-06 22:30:38 +00:00
suffix = f " and was deleted "
except Failed :
suffix = f " and could not be found to delete "
2021-12-18 03:02:24 +00:00
raise NotScheduled ( f " { e } \n \n Collection { self . name } not scheduled to run { suffix } " )
2021-02-20 05:41:45 +00:00
2021-12-17 14:24:46 +00:00
self . collectionless = " plex_collectionless " in methods and not self . playlist
2021-05-02 04:22:48 +00:00
2021-07-30 19:19:43 +00:00
self . validate_builders = True
if " validate_builders " in methods :
2021-08-05 14:59:45 +00:00
logger . debug ( " " )
logger . debug ( " Validating Method: validate_builders " )
logger . debug ( f " Value: { data [ methods [ ' validate_builders ' ] ] } " )
2021-12-13 07:30:19 +00:00
self . validate_builders = self . _parse ( " validate_builders " , self . data , datatype = " bool " , methods = methods , default = True )
2021-07-30 19:19:43 +00:00
2021-05-24 15:23:21 +00:00
self . run_again = False
if " run_again " in methods :
2021-08-05 14:59:45 +00:00
logger . debug ( " " )
logger . debug ( " Validating Method: run_again " )
logger . debug ( f " Value: { data [ methods [ ' run_again ' ] ] } " )
2021-12-13 07:30:19 +00:00
self . run_again = self . _parse ( " run_again " , self . data , datatype = " bool " , methods = methods , default = False )
2021-07-30 19:19:43 +00:00
self . build_collection = True
2021-12-17 14:24:46 +00:00
if " build_collection " in methods and not self . playlist :
2021-08-05 14:59:45 +00:00
logger . debug ( " " )
logger . debug ( " Validating Method: build_collection " )
logger . debug ( f " Value: { data [ methods [ ' build_collection ' ] ] } " )
2021-12-13 07:30:19 +00:00
self . build_collection = self . _parse ( " build_collection " , self . data , datatype = " bool " , methods = methods , default = True )
2021-05-24 15:23:21 +00:00
self . sync = self . library . sync_mode == " sync "
if " sync_mode " in methods :
2021-08-05 14:59:45 +00:00
logger . debug ( " " )
logger . debug ( " Validating Method: sync_mode " )
2021-05-24 15:23:21 +00:00
if not self . data [ methods [ " sync_mode " ] ] :
logger . warning ( f " Collection Warning: sync_mode attribute is blank using general: { self . library . sync_mode } " )
else :
logger . debug ( f " Value: { self . data [ methods [ ' sync_mode ' ] ] } " )
if self . data [ methods [ " sync_mode " ] ] . lower ( ) not in [ " append " , " sync " ] :
logger . warning ( f " Collection Warning: { self . data [ methods [ ' sync_mode ' ] ] } sync_mode invalid using general: { self . library . sync_mode } " )
else :
self . sync = self . data [ methods [ " sync_mode " ] ] . lower ( ) == " sync "
2021-12-17 14:24:46 +00:00
self . custom_sort = self . playlist
if " collection_order " in methods and not self . playlist :
2021-08-05 14:59:45 +00:00
logger . debug ( " " )
logger . debug ( " Validating Method: collection_order " )
2021-07-29 02:26:39 +00:00
if self . data [ methods [ " collection_order " ] ] is None :
2021-12-14 05:51:36 +00:00
raise Failed ( f " { self . Type } Warning: collection_order attribute is blank " )
2021-07-29 02:26:39 +00:00
else :
2021-08-05 14:59:45 +00:00
logger . debug ( f " Value: { self . data [ methods [ ' collection_order ' ] ] } " )
if self . data [ methods [ " collection_order " ] ] . lower ( ) in plex . collection_order_options :
self . details [ " collection_order " ] = self . data [ methods [ " collection_order " ] ] . lower ( )
if self . data [ methods [ " collection_order " ] ] . lower ( ) == " custom " and self . build_collection :
self . custom_sort = True
else :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: { self . data [ methods [ ' collection_order ' ] ] } collection_order invalid \n \t release (Order Collection by release dates) \n \t alpha (Order Collection Alphabetically) \n \t custom (Custom Order Collection) " )
2021-07-29 02:26:39 +00:00
2021-12-13 22:51:31 +00:00
self . sort_by = None
2021-12-17 14:24:46 +00:00
if " sort_by " in methods and not self . playlist :
2021-12-13 22:51:31 +00:00
logger . debug ( " " )
logger . debug ( " Validating Method: sort_by " )
if self . data [ methods [ " sort_by " ] ] is None :
raise Failed ( f " { self . Type } Error: sort_by attribute is blank " )
else :
logger . debug ( f " Value: { self . data [ methods [ ' sort_by ' ] ] } " )
2021-12-17 23:18:34 +00:00
if ( self . library . is_movie and self . data [ methods [ " sort_by " ] ] not in plex . movie_sorts ) or ( self . library . is_show and self . data [ methods [ " sort_by " ] ] not in plex . show_sorts ) :
2021-12-13 22:51:31 +00:00
raise Failed ( f " { self . Type } Error: sort_by attribute { self . data [ methods [ ' sort_by ' ] ] } invalid " )
else :
self . sort_by = self . data [ methods [ " sort_by " ] ]
2021-08-22 15:54:33 +00:00
self . collection_level = " movie " if self . library . is_movie else " show "
2021-12-17 14:24:46 +00:00
if self . playlist :
self . collection_level = " item "
if " collection_level " in methods and not self . playlist :
2021-08-22 15:54:33 +00:00
logger . debug ( " " )
logger . debug ( " Validating Method: collection_level " )
2021-12-09 05:40:49 +00:00
if self . library . is_movie :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: collection_level attribute only works for show libraries " )
2021-12-09 05:40:49 +00:00
elif self . data [ methods [ " collection_level " ] ] is None :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: collection_level attribute is blank " )
2021-08-22 15:54:33 +00:00
else :
logger . debug ( f " Value: { self . data [ methods [ ' collection_level ' ] ] } " )
if self . data [ methods [ " collection_level " ] ] . lower ( ) in plex . collection_level_options :
self . collection_level = self . data [ methods [ " collection_level " ] ] . lower ( )
else :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: { self . data [ methods [ ' collection_level ' ] ] } collection_level invalid \n \t season (Collection at the Season Level) \n \t episode (Collection at the Episode Level) " )
2021-08-22 15:54:33 +00:00
self . parts_collection = self . collection_level in [ " season " , " episode " ]
2021-05-05 18:01:41 +00:00
if " tmdb_person " in methods :
2021-08-05 14:59:45 +00:00
logger . debug ( " " )
logger . debug ( " Validating Method: tmdb_person " )
2021-05-24 15:23:21 +00:00
if not self . data [ methods [ " tmdb_person " ] ] :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: tmdb_person attribute is blank " )
2021-05-24 15:23:21 +00:00
else :
logger . debug ( f " Value: { self . data [ methods [ ' tmdb_person ' ] ] } " )
2021-05-05 18:01:41 +00:00
valid_names = [ ]
for tmdb_id in util . get_int_list ( self . data [ methods [ " tmdb_person " ] ] , " TMDb Person ID " ) :
2021-07-21 20:59:27 +00:00
person = self . config . TMDb . get_person ( tmdb_id )
2021-05-05 18:01:41 +00:00
valid_names . append ( person . name )
if hasattr ( person , " biography " ) and person . biography :
self . summaries [ " tmdb_person " ] = person . biography
if hasattr ( person , " profile_path " ) and person . profile_path :
2021-07-21 20:59:27 +00:00
self . posters [ " tmdb_person " ] = f " { self . config . TMDb . image_url } { person . profile_path } "
2021-05-05 18:01:41 +00:00
if len ( valid_names ) > 0 :
self . details [ " tmdb_person " ] = valid_names
else :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: No valid TMDb Person IDs in { self . data [ methods [ ' tmdb_person ' ] ] } " )
2021-05-05 18:01:41 +00:00
self . smart_sort = " random "
2021-05-02 04:22:48 +00:00
self . smart_label_collection = False
2021-12-17 14:24:46 +00:00
if " smart_label " in methods and not self . playlist :
2021-08-05 14:59:45 +00:00
logger . debug ( " " )
logger . debug ( " Validating Method: smart_label " )
2021-05-02 04:22:48 +00:00
self . smart_label_collection = True
2021-05-24 15:23:21 +00:00
if not self . data [ methods [ " smart_label " ] ] :
2021-12-13 07:30:19 +00:00
logger . warning ( f " { self . Type } Error: smart_label attribute is blank defaulting to random " )
2021-05-24 15:23:21 +00:00
else :
logger . debug ( f " Value: { self . data [ methods [ ' smart_label ' ] ] } " )
2021-05-29 02:33:55 +00:00
if ( self . library . is_movie and str ( self . data [ methods [ " smart_label " ] ] ) . lower ( ) in plex . movie_sorts ) \
or ( self . library . is_show and str ( self . data [ methods [ " smart_label " ] ] ) . lower ( ) in plex . show_sorts ) :
2021-05-02 04:22:48 +00:00
self . smart_sort = str ( self . data [ methods [ " smart_label " ] ] ) . lower ( )
else :
2021-12-13 07:30:19 +00:00
logger . warning ( f " { self . Type } Error: smart_label attribute: { self . data [ methods [ ' smart_label ' ] ] } is invalid defaulting to random " )
2021-05-02 04:22:48 +00:00
self . smart_url = None
2021-05-05 18:01:41 +00:00
self . smart_type_key = None
2021-05-29 02:33:55 +00:00
self . smart_filter_details = " "
2021-12-17 14:24:46 +00:00
if " smart_url " in methods and not self . playlist :
2021-08-05 14:59:45 +00:00
logger . debug ( " " )
logger . debug ( " Validating Method: smart_url " )
2021-05-24 15:23:21 +00:00
if not self . data [ methods [ " smart_url " ] ] :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: smart_url attribute is blank " )
2021-05-24 15:23:21 +00:00
else :
logger . debug ( f " Value: { self . data [ methods [ ' smart_url ' ] ] } " )
2021-05-02 04:22:48 +00:00
try :
2021-05-26 14:45:33 +00:00
self . smart_url , self . smart_type_key = self . library . get_smart_filter_from_uri ( self . data [ methods [ " smart_url " ] ] )
2021-05-02 04:22:48 +00:00
except ValueError :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: smart_url is incorrectly formatted " )
2021-05-02 04:22:48 +00:00
2021-12-17 14:24:46 +00:00
if " smart_filter " in methods and not self . playlist :
2021-05-30 02:19:38 +00:00
self . smart_type_key , self . smart_filter_details , self . smart_url = self . build_filter ( " smart_filter " , self . data [ methods [ " smart_filter " ] ] , smart = True )
2021-05-05 18:01:41 +00:00
def cant_interact ( attr1 , attr2 , fail = False ) :
if getattr ( self , attr1 ) and getattr ( self , attr2 ) :
2021-12-13 07:30:19 +00:00
message = f " { self . Type } Error: { attr1 } & { attr2 } attributes cannot go together "
2021-05-05 18:01:41 +00:00
if fail :
raise Failed ( message )
2021-05-02 04:22:48 +00:00
else :
2021-05-05 18:01:41 +00:00
setattr ( self , attr2 , False )
logger . info ( " " )
logger . warning ( f " { message } removing { attr2 } " )
cant_interact ( " smart_label_collection " , " collectionless " )
cant_interact ( " smart_url " , " collectionless " )
cant_interact ( " smart_url " , " run_again " )
cant_interact ( " smart_label_collection " , " smart_url " , fail = True )
2021-08-22 15:54:33 +00:00
cant_interact ( " smart_label_collection " , " parts_collection " , fail = True )
cant_interact ( " smart_url " , " parts_collection " , fail = True )
2021-12-13 22:51:31 +00:00
cant_interact ( " smart_url " , " sort_by " )
cant_interact ( " smart_label_collection " , " sort_by " )
cant_interact ( " parts_collection " , " sort_by " )
2021-05-05 18:01:41 +00:00
self . smart = self . smart_url or self . smart_label_collection
2021-02-20 05:41:45 +00:00
2021-04-05 02:25:41 +00:00
for method_key , method_data in self . data . items ( ) :
2021-07-23 18:45:49 +00:00
method_name , method_mod , method_final = self . _split ( method_key )
if method_name in ignored_details :
2021-05-24 15:23:21 +00:00
continue
2021-07-23 18:45:49 +00:00
logger . debug ( " " )
logger . debug ( f " Validating Method: { method_key } " )
logger . debug ( f " Value: { method_data } " )
2021-07-30 19:19:43 +00:00
try :
2021-12-13 07:30:19 +00:00
if method_data is None and method_name in all_builders + plex . searches : raise Failed ( f " { self . Type } Error: { method_final } attribute is blank " )
2021-12-06 07:51:06 +00:00
elif method_data is None and method_final not in none_details : logger . warning ( f " Collection Warning: { method_final } attribute is blank " )
2021-12-17 14:24:46 +00:00
elif self . playlist and method_name not in playlist_attributes : raise Failed ( f " { self . Type } Error: { method_final } attribute not allowed when using playlists " )
2021-12-13 07:30:19 +00:00
elif not self . config . Trakt and " trakt " in method_name : raise Failed ( f " { self . Type } Error: { method_final } requires Trakt to be configured " )
elif not self . library . Radarr and " radarr " in method_name : raise Failed ( f " { self . Type } Error: { method_final } requires Radarr to be configured " )
elif not self . library . Sonarr and " sonarr " in method_name : raise Failed ( f " { self . Type } Error: { method_final } requires Sonarr to be configured " )
elif not self . library . Tautulli and " tautulli " in method_name : raise Failed ( f " { self . Type } Error: { method_final } requires Tautulli to be configured " )
elif not self . config . MyAnimeList and " mal " in method_name : raise Failed ( f " { self . Type } Error: { method_final } requires MyAnimeList to be configured " )
elif self . library . is_movie and method_name in show_only_builders : raise Failed ( f " { self . Type } Error: { method_final } attribute only works for show libraries " )
elif self . library . is_show and method_name in movie_only_builders : raise Failed ( f " { self . Type } Error: { method_final } attribute only works for movie libraries " )
elif self . library . is_show and method_name in plex . movie_only_searches : raise Failed ( f " { self . Type } Error: { method_final } plex search only works for movie libraries " )
elif self . library . is_movie and method_name in plex . show_only_searches : raise Failed ( f " { self . Type } Error: { method_final } plex search only works for show libraries " )
elif self . parts_collection and method_name not in parts_collection_valid : raise Failed ( f " { self . Type } Error: { method_final } attribute does not work with Collection Level: { self . collection_level . capitalize ( ) } " )
elif self . smart and method_name in smart_invalid : raise Failed ( f " { self . Type } Error: { method_final } attribute only works with normal collections " )
elif self . collectionless and method_name not in collectionless_details : raise Failed ( f " { self . Type } Error: { method_final } attribute does not work for Collectionless collection " )
elif self . smart_url and method_name in all_builders + smart_url_invalid : raise Failed ( f " { self . Type } Error: { method_final } builder not allowed when using smart_filter " )
2021-07-30 19:19:43 +00:00
elif method_name in summary_details : self . _summary ( method_name , method_data )
elif method_name in poster_details : self . _poster ( method_name , method_data )
elif method_name in background_details : self . _background ( method_name , method_data )
elif method_name in details : self . _details ( method_name , method_data , method_final , methods )
elif method_name in item_details : self . _item_details ( method_name , method_data , method_mod , method_final , methods )
elif method_name in radarr_details : self . _radarr ( method_name , method_data )
elif method_name in sonarr_details : self . _sonarr ( method_name , method_data )
elif method_name in anidb . builders : self . _anidb ( method_name , method_data )
elif method_name in anilist . builders : self . _anilist ( method_name , method_data )
2021-11-27 00:30:41 +00:00
elif method_name in flixpatrol . builders : self . _flixpatrol ( method_name , method_data )
2021-07-30 19:19:43 +00:00
elif method_name in icheckmovies . builders : self . _icheckmovies ( method_name , method_data )
elif method_name in letterboxd . builders : self . _letterboxd ( method_name , method_data )
elif method_name in imdb . builders : self . _imdb ( method_name , method_data )
elif method_name in mal . builders : self . _mal ( method_name , method_data )
elif method_name in plex . builders or method_final in plex . searches : self . _plex ( method_name , method_data )
2021-08-01 01:23:17 +00:00
elif method_name in stevenlu . builders : self . _stevenlu ( method_name , method_data )
2021-07-30 19:19:43 +00:00
elif method_name in tautulli . builders : self . _tautulli ( method_name , method_data )
elif method_name in tmdb . builders : self . _tmdb ( method_name , method_data )
elif method_name in trakt . builders : self . _trakt ( method_name , method_data )
elif method_name in tvdb . builders : self . _tvdb ( method_name , method_data )
elif method_name == " filters " : self . _filters ( method_name , method_data )
2021-12-13 07:30:19 +00:00
else : raise Failed ( f " { self . Type } Error: { method_final } attribute not supported " )
2021-07-30 19:19:43 +00:00
except Failed as e :
if self . validate_builders :
raise
else :
logger . error ( e )
2021-02-20 05:41:45 +00:00
2021-12-14 05:51:36 +00:00
if self . custom_sort and ( len ( self . builders ) > 1 or self . builders [ 0 ] [ 0 ] not in custom_sort_builders ) :
raise Failed ( f " { self . Type } Error: " + ( ' Playlists ' if playlist else ' collection_order: custom ' ) +
( f " can only be used with a single builder per { self . type } " if len ( self . builders ) > 1 else f " cannot be used with { self . builders [ 0 ] [ 0 ] } " ) )
2021-07-29 02:26:39 +00:00
2021-12-14 05:51:36 +00:00
if len ( self . builders ) == 0 :
raise Failed ( f " { self . Type } Error: No builders were found " )
2021-07-29 02:26:39 +00:00
2021-08-16 05:41:04 +00:00
if " add " not in self . radarr_details :
self . radarr_details [ " add " ] = self . library . Radarr . add if self . library . Radarr else False
if " add_existing " not in self . radarr_details :
self . radarr_details [ " add_existing " ] = self . library . Radarr . add_existing if self . library . Radarr else False
if " add " not in self . sonarr_details :
self . sonarr_details [ " add " ] = self . library . Sonarr . add if self . library . Sonarr else False
if " add_existing " not in self . sonarr_details :
self . sonarr_details [ " add_existing " ] = self . library . Sonarr . add_existing if self . library . Sonarr else False
2021-05-02 04:22:48 +00:00
2021-08-16 05:41:04 +00:00
if self . smart_url or self . collectionless :
self . radarr_details [ " add " ] = False
self . radarr_details [ " add_existing " ] = False
self . sonarr_details [ " add " ] = False
self . sonarr_details [ " add_existing " ] = False
2021-02-20 05:41:45 +00:00
2021-11-22 20:47:26 +00:00
if self . radarr_details [ " add_existing " ] or self . sonarr_details [ " add_existing " ] :
self . item_details [ " add_existing " ] = True
2021-03-16 15:49:05 +00:00
if self . collectionless :
self . details [ " collection_mode " ] = " hide "
self . sync = True
2021-08-16 05:41:04 +00:00
self . do_missing = not self . no_missing and ( self . details [ " show_missing " ] or self . details [ " save_missing " ]
or ( self . library . Radarr and self . radarr_details [ " add " ] )
or ( self . library . Sonarr and self . sonarr_details [ " add " ] ) )
2021-05-19 20:42:05 +00:00
if self . build_collection :
try :
2021-12-17 14:24:46 +00:00
self . obj = self . library . get_playlist ( self . name ) if self . playlist else self . library . get_collection ( self . name )
2021-06-16 18:20:48 +00:00
if ( self . smart and not self . obj . smart ) or ( not self . smart and self . obj . smart ) :
2021-05-19 20:42:05 +00:00
logger . info ( " " )
2021-12-13 07:30:19 +00:00
logger . error ( f " { self . Type } Error: Converting { self . obj . title } to a { ' smart ' if self . smart else ' normal ' } collection " )
2021-05-26 14:45:33 +00:00
self . library . query ( self . obj . delete )
2021-05-19 20:42:05 +00:00
self . obj = None
except Failed :
2021-05-12 14:25:48 +00:00
self . obj = None
2021-05-19 20:42:05 +00:00
self . plex_map = { }
if self . sync and self . obj :
2021-05-26 14:45:33 +00:00
for item in self . library . get_collection_items ( self . obj , self . smart_label_collection ) :
2021-05-19 20:42:05 +00:00
self . plex_map [ item . ratingKey ] = item
2021-10-04 17:51:32 +00:00
if self . obj :
self . exists = True
2021-05-19 20:42:05 +00:00
else :
2021-07-12 02:28:52 +00:00
self . obj = None
2021-05-19 20:42:05 +00:00
self . sync = False
self . run_again = False
2021-05-24 03:38:46 +00:00
logger . info ( " " )
logger . info ( " Validation Successful " )
2021-05-12 14:25:48 +00:00
2021-12-13 07:30:19 +00:00
def _parse ( self , attribute , data , datatype = None , methods = None , parent = None , default = None , options = None , translation = None , minimum = 1 , maximum = None , regex = None ) :
display = f " { parent + ' ' if parent else ' ' } { attribute } attribute "
if options is None and translation is not None :
options = [ o for o in translation ]
value = data [ methods [ attribute ] ] if methods and attribute in methods else data
if datatype == " list " :
if value :
return [ v for v in value if v ] if isinstance ( value , list ) else [ str ( value ) ]
return [ ]
elif datatype == " intlist " :
if value :
try :
return [ int ( v ) for v in value if v ] if isinstance ( value , list ) else [ int ( value ) ]
except ValueError :
pass
return [ ]
elif datatype == " dictlist " :
final_list = [ ]
for dict_data in util . get_list ( value ) :
if isinstance ( dict_data , dict ) :
final_list . append ( ( dict_data , { dm . lower ( ) : dm for dm in dict_data } ) )
else :
raise Failed ( f " { self . Type } Error: { display } { dict_data } is not a dictionary " )
return final_list
elif methods and attribute not in methods :
message = f " { display } not found "
elif value is None :
message = f " { display } is blank "
elif regex is not None :
regex_str , example = regex
if re . compile ( regex_str ) . match ( str ( value ) ) :
return str ( value )
else :
message = f " { display } : { value } must match pattern { regex_str } e.g. { example } "
elif datatype == " bool " :
if isinstance ( value , bool ) :
return value
elif isinstance ( value , int ) :
return value > 0
elif str ( value ) . lower ( ) in [ " t " , " true " ] :
return True
elif str ( value ) . lower ( ) in [ " f " , " false " ] :
return False
else :
message = f " { display } must be either true or false "
elif datatype in [ " int " , " float " ] :
try :
value = int ( str ( value ) ) if datatype == " int " else float ( str ( value ) )
if ( maximum is None and minimum < = value ) or ( maximum is not None and minimum < = value < = maximum ) :
return value
except ValueError :
pass
pre = f " { display } { value } must be { ' an integer ' if datatype == ' int ' else ' a number ' } "
if maximum is None :
message = f " { pre } { minimum } or greater "
else :
message = f " { pre } between { minimum } and { maximum } "
elif ( translation is not None and str ( value ) . lower ( ) not in translation ) or \
( options is not None and translation is None and str ( value ) . lower ( ) not in options ) :
message = f " { display } { value } must be in { ' , ' . join ( [ str ( o ) for o in options ] ) } "
else :
return translation [ value ] if translation is not None else value
if default is None :
raise Failed ( f " { self . Type } Error: { message } " )
else :
logger . warning ( f " { self . Type } Warning: { message } using { default } as default " )
return translation [ default ] if translation is not None else default
2021-07-21 20:59:27 +00:00
def _summary ( self , method_name , method_data ) :
if method_name == " summary " :
self . summaries [ method_name ] = method_data
elif method_name == " tmdb_summary " :
self . summaries [ method_name ] = self . config . TMDb . get_movie_show_or_collection ( util . regex_first_int ( method_data , " TMDb ID " ) , self . library . is_movie ) . overview
elif method_name == " tmdb_description " :
self . summaries [ method_name ] = self . config . TMDb . get_list ( util . regex_first_int ( method_data , " TMDb List ID " ) ) . description
elif method_name == " tmdb_biography " :
self . summaries [ method_name ] = self . config . TMDb . get_person ( util . regex_first_int ( method_data , " TMDb Person ID " ) ) . biography
elif method_name == " tvdb_summary " :
2021-10-26 15:01:08 +00:00
self . summaries [ method_name ] = self . config . TVDb . get_item ( method_data , self . library . is_movie ) . summary
2021-07-21 20:59:27 +00:00
elif method_name == " tvdb_description " :
2021-10-26 15:01:08 +00:00
self . summaries [ method_name ] = self . config . TVDb . get_list_description ( method_data )
2021-07-21 20:59:27 +00:00
elif method_name == " trakt_description " :
self . summaries [ method_name ] = self . config . Trakt . list_description ( self . config . Trakt . validate_trakt ( method_data , self . library . is_movie ) [ 0 ] )
elif method_name == " letterboxd_description " :
self . summaries [ method_name ] = self . config . Letterboxd . get_list_description ( method_data , self . language )
elif method_name == " icheckmovies_description " :
self . summaries [ method_name ] = self . config . ICheckMovies . get_list_description ( method_data , self . language )
def _poster ( self , method_name , method_data ) :
if method_name == " url_poster " :
self . posters [ method_name ] = method_data
elif method_name == " tmdb_poster " :
url_slug = self . config . TMDb . get_movie_show_or_collection ( util . regex_first_int ( method_data , ' TMDb ID ' ) , self . library . is_movie ) . poster_path
self . posters [ method_name ] = f " { self . config . TMDb . image_url } { url_slug } "
elif method_name == " tmdb_profile " :
url_slug = self . config . TMDb . get_person ( util . regex_first_int ( method_data , ' TMDb Person ID ' ) ) . profile_path
self . posters [ method_name ] = f " { self . config . TMDb . image_url } { url_slug } "
elif method_name == " tvdb_poster " :
2021-10-26 15:01:08 +00:00
self . posters [ method_name ] = f " { self . config . TVDb . get_item ( method_data , self . library . is_movie ) . poster_path } "
2021-07-21 20:59:27 +00:00
elif method_name == " file_poster " :
if os . path . exists ( method_data ) :
self . posters [ method_name ] = os . path . abspath ( method_data )
else :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: Poster Path Does Not Exist: { os . path . abspath ( method_data ) } " )
2021-07-21 20:59:27 +00:00
def _background ( self , method_name , method_data ) :
if method_name == " url_background " :
self . backgrounds [ method_name ] = method_data
elif method_name == " tmdb_background " :
url_slug = self . config . TMDb . get_movie_show_or_collection ( util . regex_first_int ( method_data , ' TMDb ID ' ) , self . library . is_movie ) . poster_path
self . backgrounds [ method_name ] = f " { self . config . TMDb . image_url } { url_slug } "
elif method_name == " tvdb_background " :
2021-10-26 15:01:08 +00:00
self . posters [ method_name ] = f " { self . config . TVDb . get_item ( method_data , self . library . is_movie ) . background_path } "
2021-07-21 20:59:27 +00:00
elif method_name == " file_background " :
if os . path . exists ( method_data ) :
self . backgrounds [ method_name ] = os . path . abspath ( method_data )
else :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: Background Path Does Not Exist: { os . path . abspath ( method_data ) } " )
2021-07-21 20:59:27 +00:00
def _details ( self , method_name , method_data , method_final , methods ) :
if method_name == " collection_mode " :
if str ( method_data ) . lower ( ) in plex . collection_mode_options :
self . details [ method_name ] = plex . collection_mode_options [ str ( method_data ) . lower ( ) ]
else :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: { method_data } collection_mode invalid \n \t default (Library default) \n \t hide (Hide Collection) \n \t hide_items (Hide Items in this Collection) \n \t show_items (Show this Collection and its Items) " )
2021-09-13 01:37:56 +00:00
elif method_name == " collection_minimum " :
2021-12-13 07:30:19 +00:00
self . minimum = self . _parse ( method_name , method_data , datatype = " int " , minimum = 1 )
2021-12-08 03:31:20 +00:00
elif method_name == " server_preroll " :
2021-12-13 07:30:19 +00:00
self . server_preroll = self . _parse ( method_name , method_data )
2021-12-08 04:00:17 +00:00
elif method_name == " ignore_ids " :
2021-12-13 07:30:19 +00:00
self . ignore_ids . extend ( self . _parse ( method_name , method_data , datatype = " intlist " ) )
2021-12-08 04:00:17 +00:00
elif method_name == " ignore_imdb_ids " :
2021-12-13 07:30:19 +00:00
self . ignore_imdb_ids . extend ( self . _parse ( method_name , method_data , datatype = " list " ) )
2021-07-21 20:59:27 +00:00
elif method_name == " label " :
if " label " in methods and " label.sync " in methods :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: Cannot use label and label.sync together " )
2021-07-21 20:59:27 +00:00
if " label.remove " in methods and " label.sync " in methods :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: Cannot use label.remove and label.sync together " )
2021-07-21 20:59:27 +00:00
if method_final == " label " and " label_sync_mode " in methods and self . data [ methods [ " label_sync_mode " ] ] == " sync " :
2021-12-03 04:23:22 +00:00
self . details [ " label.sync " ] = util . get_list ( method_data ) if method_data else [ ]
2021-07-21 20:59:27 +00:00
else :
2021-12-03 04:23:22 +00:00
self . details [ method_final ] = util . get_list ( method_data ) if method_data else [ ]
2021-12-07 06:29:41 +00:00
elif method_name == " collection_changes_webhooks " :
2021-12-13 07:30:19 +00:00
self . details [ method_name ] = self . _parse ( method_name , method_data , datatype = " list " )
2021-07-21 20:59:27 +00:00
elif method_name in boolean_details :
2021-08-05 15:56:27 +00:00
default = self . details [ method_name ] if method_name in self . details else None
2021-12-13 07:30:19 +00:00
self . details [ method_name ] = self . _parse ( method_name , method_data , datatype = " bool " , default = default )
2021-07-21 20:59:27 +00:00
elif method_name in string_details :
self . details [ method_name ] = str ( method_data )
def _item_details ( self , method_name , method_data , method_mod , method_final , methods ) :
if method_name == " item_label " :
if " item_label " in methods and " item_label.sync " in methods :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: Cannot use item_label and item_label.sync together " )
2021-07-21 20:59:27 +00:00
if " item_label.remove " in methods and " item_label.sync " in methods :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: Cannot use item_label.remove and item_label.sync together " )
2021-12-03 04:23:22 +00:00
self . item_details [ method_final ] = util . get_list ( method_data ) if method_data else [ ]
2021-07-21 20:59:27 +00:00
elif method_name in [ " item_radarr_tag " , " item_sonarr_tag " ] :
if method_name in methods and f " { method_name } .sync " in methods :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: Cannot use { method_name } and { method_name } .sync together " )
2021-07-21 20:59:27 +00:00
if f " { method_name } .remove " in methods and f " { method_name } .sync " in methods :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: Cannot use { method_name } .remove and { method_name } .sync together " )
2021-07-21 20:59:27 +00:00
if method_name in methods and f " { method_name } .remove " in methods :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: Cannot use { method_name } and { method_name } .remove together " )
2021-07-21 20:59:27 +00:00
self . item_details [ method_name ] = util . get_list ( method_data )
self . item_details [ " apply_tags " ] = method_mod [ 1 : ] if method_mod else " "
elif method_name == " item_overlay " :
overlay = os . path . join ( self . config . default_dir , " overlays " , method_data , " overlay.png " )
if not os . path . exists ( overlay ) :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: { method_data } overlay image not found at { overlay } " )
2021-07-21 20:59:27 +00:00
if method_data in self . library . overlays :
raise Failed ( " Each Overlay can only be used once per Library " )
self . library . overlays . append ( method_data )
self . item_details [ method_name ] = method_data
2021-11-24 13:22:17 +00:00
elif method_name in item_bool_details :
2021-12-13 07:30:19 +00:00
if self . _parse ( method_name , method_data , datatype = " bool " , default = False ) :
2021-09-15 03:16:59 +00:00
self . item_details [ method_name ] = True
2021-07-21 20:59:27 +00:00
elif method_name in plex . item_advance_keys :
key , options = plex . item_advance_keys [ method_name ]
if method_name in advance_new_agent and self . library . agent not in plex . new_plex_agents :
logger . error (
f " Metadata Error: { method_name } attribute only works for with the New Plex Movie Agent and New Plex TV Agent " )
elif method_name in advance_show and not self . library . is_show :
logger . error ( f " Metadata Error: { method_name } attribute only works for show libraries " )
elif str ( method_data ) . lower ( ) not in options :
logger . error ( f " Metadata Error: { method_data } { method_name } attribute invalid " )
else :
self . item_details [ method_name ] = str ( method_data ) . lower ( )
def _radarr ( self , method_name , method_data ) :
2021-08-16 05:41:04 +00:00
if method_name in [ " radarr_add " , " radarr_add_existing " , " radarr_monitor " , " radarr_search " ] :
2021-12-13 07:30:19 +00:00
self . radarr_details [ method_name [ 7 : ] ] = self . _parse ( method_name , method_data , datatype = " bool " )
2021-07-21 20:59:27 +00:00
elif method_name == " radarr_folder " :
2021-08-16 05:41:04 +00:00
self . radarr_details [ " folder " ] = method_data
2021-07-21 20:59:27 +00:00
elif method_name == " radarr_availability " :
if str ( method_data ) . lower ( ) in radarr . availability_translation :
2021-08-16 05:41:04 +00:00
self . radarr_details [ " availability " ] = str ( method_data ) . lower ( )
2021-07-21 20:59:27 +00:00
else :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: { method_name } attribute must be either announced, cinemas, released or db " )
2021-07-21 20:59:27 +00:00
elif method_name == " radarr_quality " :
2021-08-16 05:41:04 +00:00
self . radarr_details [ " quality " ] = method_data
2021-07-21 20:59:27 +00:00
elif method_name == " radarr_tag " :
2021-08-16 05:41:04 +00:00
self . radarr_details [ " tag " ] = util . get_list ( method_data )
2021-07-21 20:59:27 +00:00
def _sonarr ( self , method_name , method_data ) :
2021-08-16 05:41:04 +00:00
if method_name in [ " sonarr_add " , " sonarr_add_existing " , " sonarr_season " , " sonarr_search " , " sonarr_cutoff_search " ] :
2021-12-13 07:30:19 +00:00
self . sonarr_details [ method_name [ 7 : ] ] = self . _parse ( method_name , method_data , datatype = " bool " )
2021-10-19 04:23:52 +00:00
elif method_name in [ " sonarr_folder " , " sonarr_quality " , " sonarr_language " ] :
self . sonarr_details [ method_name [ 7 : ] ] = method_data
2021-07-21 20:59:27 +00:00
elif method_name == " sonarr_monitor " :
if str ( method_data ) . lower ( ) in sonarr . monitor_translation :
2021-08-16 05:41:04 +00:00
self . sonarr_details [ " monitor " ] = str ( method_data ) . lower ( )
2021-07-21 20:59:27 +00:00
else :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: { method_name } attribute must be either all, future, missing, existing, pilot, first, latest or none " )
2021-07-21 20:59:27 +00:00
elif method_name == " sonarr_series " :
2021-12-13 14:28:46 +00:00
if str ( method_data ) . lower ( ) in sonarr . series_types :
2021-08-16 05:41:04 +00:00
self . sonarr_details [ " series " ] = str ( method_data ) . lower ( )
2021-07-21 20:59:27 +00:00
else :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: { method_name } attribute must be either standard, daily, or anime " )
2021-07-21 20:59:27 +00:00
elif method_name == " sonarr_tag " :
2021-08-16 05:41:04 +00:00
self . sonarr_details [ " tag " ] = util . get_list ( method_data )
2021-07-21 20:59:27 +00:00
2021-07-22 21:00:45 +00:00
def _anidb ( self , method_name , method_data ) :
if method_name == " anidb_popular " :
2021-12-13 07:30:19 +00:00
self . builders . append ( ( method_name , self . _parse ( method_name , method_data , datatype = " int " , default = 30 , maximum = 30 ) ) )
2021-07-22 21:00:45 +00:00
elif method_name in [ " anidb_id " , " anidb_relation " ] :
for anidb_id in self . config . AniDB . validate_anidb_ids ( method_data , self . language ) :
2021-07-29 02:26:39 +00:00
self . builders . append ( ( method_name , anidb_id ) )
2021-07-22 21:00:45 +00:00
elif method_name == " anidb_tag " :
2021-12-13 07:30:19 +00:00
for dict_data , dict_methods in self . _parse ( method_name , method_data , datatype = " dictlist " ) :
2021-07-22 21:00:45 +00:00
new_dictionary = { }
if " tag " not in dict_methods :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: anidb_tag tag attribute is required " )
2021-07-22 21:00:45 +00:00
elif not dict_data [ dict_methods [ " tag " ] ] :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: anidb_tag tag attribute is blank " )
2021-07-22 21:00:45 +00:00
else :
2021-08-28 05:17:14 +00:00
new_dictionary [ " tag " ] = util . regex_first_int ( dict_data [ dict_methods [ " tag " ] ] , " AniDB Tag ID " )
2021-12-13 07:30:19 +00:00
new_dictionary [ " limit " ] = self . _parse ( " limit " , dict_data , datatype = " int " , methods = dict_methods , default = 0 , parent = method_name , minimum = 0 )
2021-07-29 02:26:39 +00:00
self . builders . append ( ( method_name , new_dictionary ) )
2021-07-22 21:00:45 +00:00
def _anilist ( self , method_name , method_data ) :
if method_name in [ " anilist_id " , " anilist_relations " , " anilist_studio " ] :
for anilist_id in self . config . AniList . validate_anilist_ids ( method_data , studio = method_name == " anilist_studio " ) :
2021-07-29 02:26:39 +00:00
self . builders . append ( ( method_name , anilist_id ) )
2021-08-26 18:24:30 +00:00
elif method_name in [ " anilist_popular " , " anilist_trending " , " anilist_top_rated " ] :
2021-12-13 07:30:19 +00:00
self . builders . append ( ( method_name , self . _parse ( method_name , method_data , datatype = " int " , default = 10 ) ) )
2021-08-16 05:41:04 +00:00
elif method_name == " anilist_search " :
if self . current_time . month in [ 12 , 1 , 2 ] : current_season = " winter "
elif self . current_time . month in [ 3 , 4 , 5 ] : current_season = " spring "
elif self . current_time . month in [ 6 , 7 , 8 ] : current_season = " summer "
else : current_season = " fall "
2021-12-01 15:17:19 +00:00
default_year = self . current_year + 1 if self . current_time . month == 12 else self . current_year
2021-12-13 07:30:19 +00:00
for dict_data , dict_methods in self . _parse ( method_name , method_data , datatype = " dictlist " ) :
2021-07-22 21:00:45 +00:00
new_dictionary = { }
2021-08-16 05:41:04 +00:00
for search_method , search_data in dict_data . items ( ) :
search_attr , modifier , search_final = self . _split ( search_method )
2021-08-17 00:07:35 +00:00
if search_final not in anilist . searches :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: { method_name } { search_final } attribute not supported " )
2021-08-16 05:41:04 +00:00
elif search_attr == " season " :
2021-12-13 07:30:19 +00:00
new_dictionary [ search_attr ] = self . _parse ( search_attr , search_data , parent = method_name , default = current_season , options = util . seasons )
2021-08-16 05:41:04 +00:00
if " year " not in dict_methods :
2021-12-01 15:17:19 +00:00
logger . warning ( f " Collection Warning: { method_name } year attribute not found using this year: { default_year } by default " )
new_dictionary [ " year " ] = default_year
2021-08-16 05:41:04 +00:00
elif search_attr == " year " :
2021-12-13 07:30:19 +00:00
new_dictionary [ search_attr ] = self . _parse ( search_attr , search_data , datatype = " int " , parent = method_name , default = default_year , minimum = 1917 , maximum = default_year + 1 )
2021-08-17 00:07:35 +00:00
elif search_data is None :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: { method_name } { search_final } attribute is blank " )
2021-08-16 05:41:04 +00:00
elif search_attr == " adult " :
2021-12-13 07:30:19 +00:00
new_dictionary [ search_attr ] = self . _parse ( search_attr , search_data , datatype = " bool " , parent = method_name )
2021-08-26 18:24:30 +00:00
elif search_attr == " country " :
2021-12-13 07:30:19 +00:00
new_dictionary [ search_attr ] = self . _parse ( search_attr , search_data , options = anilist . country_codes , parent = method_name )
2021-08-26 18:24:30 +00:00
elif search_attr == " source " :
2021-12-13 07:30:19 +00:00
new_dictionary [ search_attr ] = self . _parse ( search_attr , search_data , options = anilist . media_source , parent = method_name )
2021-08-16 05:41:04 +00:00
elif search_attr in [ " episodes " , " duration " , " score " , " popularity " ] :
2021-12-13 07:30:19 +00:00
new_dictionary [ search_final ] = self . _parse ( search_final , search_data , datatype = " int " , parent = method_name )
2021-08-16 05:41:04 +00:00
elif search_attr in [ " format " , " status " , " genre " , " tag " , " tag_category " ] :
2021-12-13 07:30:19 +00:00
new_dictionary [ search_final ] = self . config . AniList . validate ( search_attr . replace ( " _ " , " " ) . title ( ) , self . _parse ( search_final , search_data ) )
2021-08-16 05:41:04 +00:00
elif search_attr in [ " start " , " end " ] :
new_dictionary [ search_final ] = util . validate_date ( search_data , f " { method_name } { search_final } attribute " , return_as = " % m/ %d / % Y " )
elif search_attr == " min_tag_percent " :
2021-12-13 07:30:19 +00:00
new_dictionary [ search_attr ] = self . _parse ( search_attr , search_data , datatype = " int " , parent = method_name , minimum = 0 , maximum = 100 )
2021-08-16 05:41:04 +00:00
elif search_attr == " search " :
new_dictionary [ search_attr ] = str ( search_data )
elif search_final not in [ " sort_by " , " limit " ] :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: { method_name } { search_final } attribute not supported " )
2021-08-16 13:02:52 +00:00
if len ( new_dictionary ) == 0 :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: { method_name } must have at least one valid search option " )
new_dictionary [ " sort_by " ] = self . _parse ( " sort_by " , dict_data , methods = dict_methods , parent = method_name , default = " score " , options = anilist . sort_options )
new_dictionary [ " limit " ] = self . _parse ( " limit " , dict_data , datatype = " int " , methods = dict_methods , default = 0 , parent = method_name )
2021-07-29 02:26:39 +00:00
self . builders . append ( ( method_name , new_dictionary ) )
2021-07-22 21:00:45 +00:00
2021-11-27 00:30:41 +00:00
def _flixpatrol ( self , method_name , method_data ) :
if method_name . startswith ( " flixpatrol_url " ) :
flixpatrol_lists = self . config . FlixPatrol . validate_flixpatrol_lists ( method_data , self . language , self . library . is_movie )
for flixpatrol_list in flixpatrol_lists :
self . builders . append ( ( " flixpatrol_url " , flixpatrol_list ) )
elif method_name in flixpatrol . builders :
2021-12-13 07:30:19 +00:00
for dict_data , dict_methods in self . _parse ( method_name , method_data , datatype = " dictlist " ) :
2021-11-27 00:30:41 +00:00
if method_name == " flixpatrol_demographics " :
data = {
2021-12-13 07:30:19 +00:00
" generation " : self . _parse ( " generation " , dict_data , methods = dict_methods , parent = method_name , options = flixpatrol . generations ) ,
" gender " : self . _parse ( " gender " , dict_data , methods = dict_methods , parent = method_name , default = " all " , options = flixpatrol . gender ) ,
" location " : self . _parse ( " location " , dict_data , methods = dict_methods , parent = method_name , default = " world " , options = flixpatrol . demo_locations ) ,
" limit " : self . _parse ( " limit " , dict_data , datatype = " int " , methods = dict_methods , parent = method_name , default = 10 )
2021-11-27 00:30:41 +00:00
}
elif method_name == " flixpatrol_popular " :
data = {
2021-12-13 07:30:19 +00:00
" source " : self . _parse ( " source " , dict_data , methods = dict_methods , parent = method_name , options = flixpatrol . popular ) ,
" time_window " : self . _parse ( " time_window " , dict_data , methods = dict_methods , parent = method_name , default = " today " ) ,
" limit " : self . _parse ( " limit " , dict_data , datatype = " int " , methods = dict_methods , parent = method_name , default = 10 )
2021-11-27 00:30:41 +00:00
}
elif method_name == " flixpatrol_top " :
data = {
2021-12-13 07:30:19 +00:00
" platform " : self . _parse ( " platform " , dict_data , methods = dict_methods , parent = method_name , options = flixpatrol . platforms ) ,
" location " : self . _parse ( " location " , dict_data , methods = dict_methods , parent = method_name , default = " world " , options = flixpatrol . locations ) ,
" time_window " : self . _parse ( " time_window " , dict_data , methods = dict_methods , parent = method_name , default = " today " ) ,
" limit " : self . _parse ( " limit " , dict_data , datatype = " int " , methods = dict_methods , parent = method_name , default = 10 )
2021-11-27 00:30:41 +00:00
}
else :
continue
if self . config . FlixPatrol . validate_flixpatrol_dict ( method_name , data , self . language , self . library . is_movie ) :
self . builders . append ( ( method_name , data ) )
2021-07-22 21:00:45 +00:00
def _icheckmovies ( self , method_name , method_data ) :
if method_name . startswith ( " icheckmovies_list " ) :
icheckmovies_lists = self . config . ICheckMovies . validate_icheckmovies_lists ( method_data , self . language )
for icheckmovies_list in icheckmovies_lists :
2021-07-29 02:26:39 +00:00
self . builders . append ( ( " icheckmovies_list " , icheckmovies_list ) )
2021-07-22 21:00:45 +00:00
if method_name . endswith ( " _details " ) :
self . summaries [ method_name ] = self . config . ICheckMovies . get_list_description ( icheckmovies_lists [ 0 ] , self . language )
2021-07-23 18:45:49 +00:00
def _imdb ( self , method_name , method_data ) :
if method_name == " imdb_id " :
for value in util . get_list ( method_data ) :
if str ( value ) . startswith ( " tt " ) :
2021-07-29 02:26:39 +00:00
self . builders . append ( ( method_name , value ) )
2021-07-23 18:45:49 +00:00
else :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: imdb_id { value } must begin with tt " )
2021-07-23 18:45:49 +00:00
elif method_name == " imdb_list " :
for imdb_dict in self . config . IMDb . validate_imdb_lists ( method_data , self . language ) :
2021-07-29 02:26:39 +00:00
self . builders . append ( ( method_name , imdb_dict ) )
2021-12-10 08:13:26 +00:00
elif method_name == " imdb_chart " :
for value in util . get_list ( method_data ) :
if value in imdb . movie_charts and not self . library . is_movie :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: chart: { value } does not work with show libraries " )
2021-12-10 08:13:26 +00:00
elif value in imdb . show_charts and self . library . is_movie :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: chart: { value } does not work with movie libraries " )
2021-12-10 08:13:26 +00:00
elif value in imdb . charts :
self . builders . append ( ( method_name , value ) )
2021-12-10 08:17:24 +00:00
else :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: chart: { value } is invalid options are { [ i for i in imdb . charts ] } " )
2021-07-23 18:45:49 +00:00
def _letterboxd ( self , method_name , method_data ) :
if method_name . startswith ( " letterboxd_list " ) :
letterboxd_lists = self . config . Letterboxd . validate_letterboxd_lists ( method_data , self . language )
for letterboxd_list in letterboxd_lists :
2021-07-29 02:26:39 +00:00
self . builders . append ( ( " letterboxd_list " , letterboxd_list ) )
2021-07-23 18:45:49 +00:00
if method_name . endswith ( " _details " ) :
self . summaries [ method_name ] = self . config . Letterboxd . get_list_description ( letterboxd_lists [ 0 ] , self . language )
def _mal ( self , method_name , method_data ) :
if method_name == " mal_id " :
for mal_id in util . get_int_list ( method_data , " MyAnimeList ID " ) :
2021-07-29 02:26:39 +00:00
self . builders . append ( ( method_name , mal_id ) )
2021-07-23 18:45:49 +00:00
elif method_name in [ " mal_all " , " mal_airing " , " mal_upcoming " , " mal_tv " , " mal_ova " , " mal_movie " , " mal_special " , " mal_popular " , " mal_favorite " , " mal_suggested " ] :
2021-12-13 07:30:19 +00:00
self . builders . append ( ( method_name , self . _parse ( method_name , method_data , datatype = " int " , default = 10 , maximum = 100 if method_name == " mal_suggested " else 500 ) ) )
2021-07-23 18:45:49 +00:00
elif method_name in [ " mal_season " , " mal_userlist " ] :
2021-12-13 07:30:19 +00:00
for dict_data , dict_methods in self . _parse ( method_name , method_data , datatype = " dictlist " ) :
2021-07-23 18:45:49 +00:00
if method_name == " mal_season " :
2021-08-10 13:34:13 +00:00
if self . current_time . month in [ 1 , 2 , 3 ] : default_season = " winter "
elif self . current_time . month in [ 4 , 5 , 6 ] : default_season = " spring "
elif self . current_time . month in [ 7 , 8 , 9 ] : default_season = " summer "
else : default_season = " fall "
self . builders . append ( ( method_name , {
2021-12-13 07:30:19 +00:00
" season " : self . _parse ( " season " , dict_data , methods = dict_methods , parent = method_name , default = default_season , options = util . seasons ) ,
" sort_by " : self . _parse ( " sort_by " , dict_data , methods = dict_methods , parent = method_name , default = " members " , options = mal . season_sort_options , translation = mal . season_sort_translation ) ,
" year " : self . _parse ( " year " , dict_data , datatype = " int " , methods = dict_methods , default = self . current_year , parent = method_name , minimum = 1917 , maximum = self . current_year + 1 ) ,
" limit " : self . _parse ( " limit " , dict_data , datatype = " int " , methods = dict_methods , default = 100 , parent = method_name , maximum = 500 )
2021-08-10 13:34:13 +00:00
} ) )
2021-07-23 18:45:49 +00:00
elif method_name == " mal_userlist " :
2021-08-10 13:34:13 +00:00
self . builders . append ( ( method_name , {
2021-12-13 07:30:19 +00:00
" username " : self . _parse ( " username " , dict_data , methods = dict_methods , parent = method_name ) ,
" status " : self . _parse ( " status " , dict_data , methods = dict_methods , parent = method_name , default = " all " , options = mal . userlist_status ) ,
" sort_by " : self . _parse ( " sort_by " , dict_data , methods = dict_methods , parent = method_name , default = " score " , options = mal . userlist_sort_options , translation = mal . userlist_sort_translation ) ,
" limit " : self . _parse ( " limit " , dict_data , datatype = " int " , methods = dict_methods , default = 100 , parent = method_name , maximum = 1000 )
2021-08-10 13:34:13 +00:00
} ) )
2021-08-17 00:07:35 +00:00
elif method_name in [ " mal_genre " , " mal_studio " ] :
2021-08-10 13:34:13 +00:00
id_name = f " { method_name [ 4 : ] } _id "
final_data = [ ]
for data in util . get_list ( method_data ) :
final_data . append ( data if isinstance ( data , dict ) else { id_name : data , " limit " : 0 } )
2021-12-13 07:30:19 +00:00
for dict_data , dict_methods in self . _parse ( method_name , method_data , datatype = " dictlist " ) :
2021-08-10 13:34:13 +00:00
self . builders . append ( ( method_name , {
2021-12-13 07:30:19 +00:00
id_name : self . _parse ( id_name , dict_data , datatype = " int " , methods = dict_methods , parent = method_name , maximum = 999999 ) ,
" limit " : self . _parse ( " limit " , dict_data , datatype = " int " , methods = dict_methods , default = 0 , parent = method_name )
2021-08-10 13:34:13 +00:00
} ) )
2021-07-23 18:45:49 +00:00
def _plex ( self , method_name , method_data ) :
if method_name == " plex_all " :
2021-07-29 02:26:39 +00:00
self . builders . append ( ( method_name , True ) )
2021-07-23 18:45:49 +00:00
elif method_name in [ " plex_search " , " plex_collectionless " ] :
2021-12-13 07:30:19 +00:00
for dict_data , dict_methods in self . _parse ( method_name , method_data , datatype = " dictlist " ) :
2021-07-23 18:45:49 +00:00
new_dictionary = { }
if method_name == " plex_search " :
2021-08-22 15:54:33 +00:00
type_override = f " { self . collection_level } s " if self . collection_level in plex . collection_level_options else None
new_dictionary = self . build_filter ( " plex_search " , dict_data , type_override = type_override )
2021-07-23 18:45:49 +00:00
elif method_name == " plex_collectionless " :
2021-12-13 07:30:19 +00:00
prefix_list = self . _parse ( " exclude_prefix " , dict_data , datatype = " list " , methods = dict_methods )
exact_list = self . _parse ( " exclude " , dict_data , datatype = " list " , methods = dict_methods )
2021-07-23 18:45:49 +00:00
if len ( prefix_list ) == 0 and len ( exact_list ) == 0 :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: you must have at least one exclusion " )
2021-07-23 18:45:49 +00:00
exact_list . append ( self . name )
new_dictionary [ " exclude_prefix " ] = prefix_list
new_dictionary [ " exclude " ] = exact_list
2021-07-29 02:26:39 +00:00
self . builders . append ( ( method_name , new_dictionary ) )
2021-07-23 18:45:49 +00:00
else :
2021-07-29 02:26:39 +00:00
self . builders . append ( ( " plex_search " , self . build_filter ( " plex_search " , { " any " : { method_name : method_data } } ) ) )
2021-07-23 18:45:49 +00:00
2021-08-01 01:23:17 +00:00
def _stevenlu ( self , method_name , method_data ) :
2021-12-13 07:30:19 +00:00
self . builders . append ( ( method_name , self . _parse ( method_name , method_data , " bool " ) ) )
2021-08-01 01:23:17 +00:00
2021-07-23 18:45:49 +00:00
def _tautulli ( self , method_name , method_data ) :
2021-12-13 07:30:19 +00:00
for dict_data , dict_methods in self . _parse ( method_name , method_data , datatype = " dictlist " ) :
2021-07-29 02:26:39 +00:00
self . builders . append ( ( method_name , {
2021-07-23 18:45:49 +00:00
" list_type " : " popular " if method_name == " tautulli_popular " else " watched " ,
2021-12-13 07:30:19 +00:00
" list_days " : self . _parse ( " list_days " , dict_data , datatype = " int " , methods = dict_methods , default = 30 , parent = method_name ) ,
" list_size " : self . _parse ( " list_size " , dict_data , datatype = " int " , methods = dict_methods , default = 10 , parent = method_name ) ,
" list_buffer " : self . _parse ( " list_buffer " , dict_data , datatype = " int " , methods = dict_methods , default = 20 , parent = method_name ) ,
" list_minimum " : self . _parse ( " list_minimum " , dict_data , datatype = " int " , methods = dict_methods , default = 0 , parent = method_name )
2021-07-23 18:45:49 +00:00
} ) )
def _tmdb ( self , method_name , method_data ) :
if method_name == " tmdb_discover " :
2021-12-13 07:30:19 +00:00
for dict_data , dict_methods in self . _parse ( method_name , method_data , datatype = " dictlist " ) :
new_dictionary = { " limit " : self . _parse ( " limit " , dict_data , datatype = " int " , methods = dict_methods , default = 100 , parent = method_name ) }
2021-08-14 22:59:35 +00:00
for discover_method , discover_data in dict_data . items ( ) :
discover_attr , modifier , discover_final = self . _split ( discover_method )
if discover_data is None :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: { method_name } { discover_final } attribute is blank " )
2021-08-14 22:59:35 +00:00
elif discover_final not in tmdb . discover_all :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: { method_name } { discover_final } attribute not supported " )
2021-08-14 22:59:35 +00:00
elif self . library . is_movie and discover_attr in tmdb . discover_tv_only :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: { method_name } { discover_final } attribute only works for show libraries " )
2021-08-14 22:59:35 +00:00
elif self . library . is_show and discover_attr in tmdb . discover_movie_only :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: { method_name } { discover_final } attribute only works for movie libraries " )
2021-08-14 22:59:35 +00:00
elif discover_attr in [ " language " , " region " ] :
regex = ( " ([a-z] {2} )-([A-Z] {2} ) " , " en-US " ) if discover_attr == " language " else ( " ^[A-Z] {2} $ " , " US " )
2021-12-13 07:30:19 +00:00
new_dictionary [ discover_attr ] = self . _parse ( discover_attr , discover_data , parent = method_name , regex = regex )
2021-08-14 22:59:35 +00:00
elif discover_attr == " sort_by " and self . library . is_movie :
options = tmdb . discover_movie_sort if self . library . is_movie else tmdb . discover_tv_sort
2021-12-13 07:30:19 +00:00
new_dictionary [ discover_final ] = self . _parse ( discover_attr , discover_data , parent = method_name , options = options )
2021-08-14 22:59:35 +00:00
elif discover_attr == " certification_country " :
if " certification " in dict_data or " certification.lte " in dict_data or " certification.gte " in dict_data :
2021-11-26 08:24:36 +00:00
new_dictionary [ discover_final ] = discover_data
2021-07-23 18:45:49 +00:00
else :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: { method_name } { discover_attr } attribute: must be used with either certification, certification.lte, or certification.gte " )
2021-08-14 22:59:35 +00:00
elif discover_attr == " certification " :
if " certification_country " in dict_data :
new_dictionary [ discover_final ] = discover_data
else :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: { method_name } { discover_final } attribute: must be used with certification_country " )
2021-11-26 08:24:36 +00:00
elif discover_attr == " watch_region " :
2021-11-29 00:27:15 +00:00
if " with_watch_providers " in dict_data or " without_watch_providers " in dict_data or " with_watch_monetization_types " in dict_data :
2021-11-26 08:24:36 +00:00
new_dictionary [ discover_final ] = discover_data
else :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: { method_name } { discover_final } attribute: must be used with either with_watch_providers, without_watch_providers, or with_watch_monetization_types " )
2021-11-26 08:24:36 +00:00
elif discover_attr == " with_watch_monetization_types " :
if " watch_region " in dict_data :
2021-12-13 07:30:19 +00:00
new_dictionary [ discover_final ] = self . _parse ( discover_attr , discover_data , parent = method_name , options = tmdb . discover_monetization_types )
2021-11-26 08:24:36 +00:00
else :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: { method_name } { discover_final } attribute: must be used with watch_region " )
2021-11-29 16:02:16 +00:00
elif discover_attr in tmdb . discover_booleans :
2021-12-13 07:30:19 +00:00
new_dictionary [ discover_attr ] = self . _parse ( discover_attr , discover_data , datatype = " bool " , parent = method_name )
2021-11-29 00:27:15 +00:00
elif discover_attr == " vote_average " :
2021-12-13 07:30:19 +00:00
new_dictionary [ discover_final ] = self . _parse ( discover_final , discover_data , datatype = " float " , parent = method_name )
2021-11-26 08:24:36 +00:00
elif discover_attr == " with_status " :
2021-12-13 07:30:19 +00:00
new_dictionary [ discover_attr ] = self . _parse ( discover_attr , discover_data , datatype = " int " , parent = method_name , minimum = 0 , maximum = 5 )
2021-11-26 08:24:36 +00:00
elif discover_attr == " with_type " :
2021-12-13 07:30:19 +00:00
new_dictionary [ discover_attr ] = self . _parse ( discover_attr , discover_data , datatype = " int " , parent = method_name , minimum = 0 , maximum = 6 )
2021-11-29 00:27:15 +00:00
elif discover_final in tmdb . discover_dates :
new_dictionary [ discover_final ] = util . validate_date ( discover_data , f " { method_name } { discover_final } attribute " , return_as = " % m/ %d / % Y " )
elif discover_attr in tmdb . discover_years :
2021-12-13 07:30:19 +00:00
new_dictionary [ discover_attr ] = self . _parse ( discover_attr , discover_data , datatype = " int " , parent = method_name , minimum = 1800 , maximum = self . current_year + 1 )
2021-11-29 00:27:15 +00:00
elif discover_attr in tmdb . discover_ints :
2021-12-13 07:30:19 +00:00
new_dictionary [ discover_final ] = self . _parse ( discover_final , discover_data , datatype = " int " , parent = method_name )
2021-11-29 00:27:15 +00:00
elif discover_final in tmdb . discover_strings :
2021-08-14 22:59:35 +00:00
new_dictionary [ discover_final ] = discover_data
elif discover_attr != " limit " :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: { method_name } { discover_final } attribute not supported " )
2021-07-23 18:45:49 +00:00
if len ( new_dictionary ) > 1 :
2021-07-29 02:26:39 +00:00
self . builders . append ( ( method_name , new_dictionary ) )
2021-07-23 18:45:49 +00:00
else :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: { method_name } had no valid fields " )
2021-07-23 18:45:49 +00:00
elif method_name in [ " tmdb_popular " , " tmdb_top_rated " , " tmdb_now_playing " , " tmdb_trending_daily " , " tmdb_trending_weekly " ] :
2021-12-13 07:30:19 +00:00
self . builders . append ( ( method_name , self . _parse ( method_name , method_data , datatype = " int " , default = 10 ) ) )
2021-07-23 18:45:49 +00:00
else :
values = self . config . TMDb . validate_tmdb_ids ( method_data , method_name )
if method_name . endswith ( " _details " ) :
2021-07-26 15:46:36 +00:00
if method_name . startswith ( ( " tmdb_collection " , " tmdb_movie " , " tmdb_show " ) ) :
2021-07-23 18:45:49 +00:00
item = self . config . TMDb . get_movie_show_or_collection ( values [ 0 ] , self . library . is_movie )
if hasattr ( item , " overview " ) and item . overview :
self . summaries [ method_name ] = item . overview
if hasattr ( item , " backdrop_path " ) and item . backdrop_path :
self . backgrounds [ method_name ] = f " { self . config . TMDb . image_url } { item . backdrop_path } "
if hasattr ( item , " poster_path " ) and item . poster_path :
self . posters [ method_name ] = f " { self . config . TMDb . image_url } { item . poster_path } "
2021-07-26 15:46:36 +00:00
elif method_name . startswith ( ( " tmdb_actor " , " tmdb_crew " , " tmdb_director " , " tmdb_producer " , " tmdb_writer " ) ) :
2021-07-23 18:45:49 +00:00
item = self . config . TMDb . get_person ( values [ 0 ] )
if hasattr ( item , " biography " ) and item . biography :
self . summaries [ method_name ] = item . biography
if hasattr ( item , " profile_path " ) and item . profile_path :
self . posters [ method_name ] = f " { self . config . TMDb . image_url } { item . profile_path } "
2021-07-26 15:46:36 +00:00
elif method_name . startswith ( " tmdb_list " ) :
2021-07-23 18:45:49 +00:00
item = self . config . TMDb . get_list ( values [ 0 ] )
if hasattr ( item , " description " ) and item . description :
self . summaries [ method_name ] = item . description
for value in values :
2021-07-29 02:26:39 +00:00
self . builders . append ( ( method_name [ : - 8 ] if method_name . endswith ( " _details " ) else method_name , value ) )
2021-07-23 18:45:49 +00:00
def _trakt ( self , method_name , method_data ) :
if method_name . startswith ( " trakt_list " ) :
trakt_lists = self . config . Trakt . validate_trakt ( method_data , self . library . is_movie )
for trakt_list in trakt_lists :
2021-07-29 02:26:39 +00:00
self . builders . append ( ( " trakt_list " , trakt_list ) )
2021-07-23 18:45:49 +00:00
if method_name . endswith ( " _details " ) :
self . summaries [ method_name ] = self . config . Trakt . list_description ( trakt_lists [ 0 ] )
elif method_name in [ " trakt_watchlist " , " trakt_collection " ] :
for trakt_list in self . config . Trakt . validate_trakt ( method_data , self . library . is_movie , trakt_type = method_name [ 6 : ] ) :
2021-07-29 02:26:39 +00:00
self . builders . append ( ( method_name , trakt_list ) )
2021-11-13 23:51:12 +00:00
elif method_name == " trakt_boxoffice " :
2021-12-13 07:30:19 +00:00
if self . _parse ( method_name , method_data , datatype = " bool " , default = False ) :
2021-11-13 23:51:12 +00:00
self . builders . append ( ( method_name , 10 ) )
else :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: { method_name } must be set to true " )
2021-11-13 23:51:12 +00:00
elif method_name in trakt . builders :
2021-12-13 07:30:19 +00:00
self . builders . append ( ( method_name , self . _parse ( method_name , method_data , datatype = " int " , default = 10 ) ) )
2021-07-23 18:45:49 +00:00
def _tvdb ( self , method_name , method_data ) :
values = util . get_list ( method_data )
if method_name . endswith ( " _details " ) :
if method_name . startswith ( ( " tvdb_movie " , " tvdb_show " ) ) :
2021-10-26 15:01:08 +00:00
item = self . config . TVDb . get_item ( values [ 0 ] , method_name . startswith ( " tvdb_movie " ) )
2021-07-23 18:45:49 +00:00
if hasattr ( item , " description " ) and item . description :
self . summaries [ method_name ] = item . description
if hasattr ( item , " background_path " ) and item . background_path :
self . backgrounds [ method_name ] = f " { self . config . TMDb . image_url } { item . background_path } "
if hasattr ( item , " poster_path " ) and item . poster_path :
self . posters [ method_name ] = f " { self . config . TMDb . image_url } { item . poster_path } "
elif method_name . startswith ( " tvdb_list " ) :
2021-10-26 15:01:08 +00:00
self . summaries [ method_name ] = self . config . TVDb . get_list_description ( values [ 0 ] )
2021-07-23 18:45:49 +00:00
for value in values :
2021-07-29 02:26:39 +00:00
self . builders . append ( ( method_name [ : - 8 ] if method_name . endswith ( " _details " ) else method_name , value ) )
2021-07-23 18:45:49 +00:00
def _filters ( self , method_name , method_data ) :
2021-12-13 07:30:19 +00:00
for dict_data , dict_methods in self . _parse ( method_name , method_data , datatype = " dictlist " ) :
2021-07-23 18:45:49 +00:00
validate = True
if " validate " in dict_data :
if dict_data [ " validate " ] is None :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: validate filter attribute is blank " )
2021-07-23 18:45:49 +00:00
if not isinstance ( dict_data [ " validate " ] , bool ) :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: validate filter attribute must be either true or false " )
2021-07-23 18:45:49 +00:00
validate = dict_data [ " validate " ]
for filter_method , filter_data in dict_data . items ( ) :
filter_attr , modifier , filter_final = self . _split ( filter_method )
2021-08-05 14:59:45 +00:00
message = None
2021-07-23 18:45:49 +00:00
if filter_final not in all_filters :
2021-12-13 07:30:19 +00:00
message = f " { self . Type } Error: { filter_final } is not a valid filter attribute "
2021-07-23 18:45:49 +00:00
elif filter_final in movie_only_filters and self . library . is_show :
2021-12-13 07:30:19 +00:00
message = f " { self . Type } Error: { filter_final } filter attribute only works for movie libraries "
2021-07-23 18:45:49 +00:00
elif filter_final in show_only_filters and self . library . is_movie :
2021-12-13 07:30:19 +00:00
message = f " { self . Type } Error: { filter_final } filter attribute only works for show libraries "
2021-07-23 18:45:49 +00:00
elif filter_final is None :
2021-12-13 07:30:19 +00:00
message = f " { self . Type } Error: { filter_final } filter attribute is blank "
2021-08-09 15:40:44 +00:00
elif filter_attr in tmdb_filters :
self . tmdb_filters . append ( ( filter_final , self . validate_attribute ( filter_attr , modifier , f " { filter_final } filter " , filter_data , validate ) ) )
2021-07-23 18:45:49 +00:00
else :
self . filters . append ( ( filter_final , self . validate_attribute ( filter_attr , modifier , f " { filter_final } filter " , filter_data , validate ) ) )
2021-08-05 14:59:45 +00:00
if message :
if validate :
raise Failed ( message )
else :
logger . error ( message )
2021-07-23 18:45:49 +00:00
2021-12-14 05:51:36 +00:00
def gather_ids ( self , method , value ) :
if " plex " in method :
return self . library . get_rating_keys ( method , value )
elif " tautulli " in method :
return self . library . Tautulli . get_rating_keys ( self . library , value )
elif " anidb " in method :
anidb_ids = self . config . AniDB . get_anidb_ids ( method , value , self . language )
return self . config . Convert . anidb_to_ids ( anidb_ids , self . library )
elif " anilist " in method :
anilist_ids = self . config . AniList . get_anilist_ids ( method , value )
return self . config . Convert . anilist_to_ids ( anilist_ids , self . library )
elif " mal " in method :
mal_ids = self . config . MyAnimeList . get_mal_ids ( method , value )
return self . config . Convert . myanimelist_to_ids ( mal_ids , self . library )
elif " tvdb " in method :
return self . config . TVDb . get_tvdb_ids ( method , value )
elif " imdb " in method :
return self . config . IMDb . get_imdb_ids ( method , value , self . language )
elif " flixpatrol " in method :
return self . config . FlixPatrol . get_flixpatrol_ids ( method , value , self . language , self . library . is_movie )
elif " icheckmovies " in method :
return self . config . ICheckMovies . get_icheckmovies_ids ( method , value , self . language )
elif " letterboxd " in method :
return self . config . Letterboxd . get_tmdb_ids ( method , value , self . language )
elif " stevenlu " in method :
return self . config . StevenLu . get_stevenlu_ids ( method )
elif " tmdb " in method :
return self . config . TMDb . get_tmdb_ids ( method , value , self . library . is_movie )
elif " trakt " in method :
return self . config . Trakt . get_trakt_ids ( method , value , self . library . is_movie )
else :
logger . error ( f " { self . Type } Error: { method } method not supported " )
2021-08-16 05:41:04 +00:00
def find_rating_keys ( self ) :
2021-07-29 02:26:39 +00:00
for method , value in self . builders :
2021-07-21 17:40:05 +00:00
logger . debug ( " " )
logger . debug ( f " Builder: { method } : { value } " )
logger . info ( " " )
2021-12-15 15:50:20 +00:00
items = [ ]
2021-12-14 05:51:36 +00:00
ids = self . gather_ids ( method , value )
2021-08-07 06:01:21 +00:00
if len ( ids ) > 0 :
total_ids = len ( ids )
2021-12-14 05:51:36 +00:00
logger . debug ( " " )
logger . debug ( f " { total_ids } IDs Found: { ids } " )
for i , input_data in enumerate ( ids , 1 ) :
input_id , id_type = input_data
util . print_return ( f " Parsing ID { i } / { total_ids } " )
2021-12-15 15:50:20 +00:00
if id_type == " tvdb_season " and self . collection_level == " season " :
2021-12-14 05:51:36 +00:00
show_id , season_num = input_id . split ( " _ " )
show_id = int ( show_id )
if show_id in self . library . show_map :
show_item = self . library . fetchItem ( self . library . show_map [ show_id ] [ 0 ] )
try :
2021-12-15 15:50:20 +00:00
items . append ( show_item . season ( season = int ( season_num ) ) )
2021-12-14 05:51:36 +00:00
except NotFound :
self . missing_parts . append ( f " { show_item . title } Season: { season_num } Missing " )
elif show_id not in self . missing_shows :
self . missing_shows . append ( show_id )
2021-12-18 05:59:53 +00:00
elif id_type in [ " tvdb_episode " , " imdb " ] and self . collection_level == " episode " :
if id_type == " tvdb_episode " :
show_id , season_num , episode_num = input_id . split ( " _ " )
elif id_type == " imdb " and input_id not in self . ignore_imdb_ids :
try :
_id , tmdb_type = self . config . Convert . imdb_to_tmdb ( input_id , fail = True )
if tmdb_type != " episode " :
continue
tmdb_id , season_num , episode_num = _id . split ( " _ " )
show_id = self . config . Convert . tmdb_to_tvdb ( tmdb_id , fail = True )
except Failed as e :
logger . error ( e )
continue
else :
continue
2021-12-14 05:51:36 +00:00
show_id = int ( show_id )
if show_id in self . library . show_map :
show_item = self . library . fetchItem ( self . library . show_map [ show_id ] [ 0 ] )
try :
2021-12-15 15:50:20 +00:00
items . append ( show_item . episode ( season = int ( season_num ) , episode = int ( episode_num ) ) )
2021-12-14 05:51:36 +00:00
except NotFound :
2021-12-18 05:59:53 +00:00
self . missing_parts . append ( f " { show_item . title } Season: { season_num } Episode: { episode_num } Missing " )
2021-12-14 05:51:36 +00:00
elif show_id not in self . missing_shows :
self . missing_shows . append ( show_id )
2021-12-15 15:50:20 +00:00
else :
rating_keys = [ ]
if id_type == " ratingKey " :
rating_keys = input_id
elif id_type == " tmdb " and not self . parts_collection :
if input_id not in self . ignore_ids :
if input_id in self . library . movie_map :
rating_keys = self . library . movie_map [ input_id ]
elif input_id not in self . missing_movies :
self . missing_movies . append ( input_id )
elif id_type in [ " tvdb " , " tmdb_show " ] and not self . parts_collection :
if id_type == " tmdb_show " :
try :
input_id = self . config . Convert . tmdb_to_tvdb ( input_id , fail = True )
except Failed as e :
logger . error ( e )
continue
if input_id not in self . ignore_ids :
if input_id in self . library . show_map :
rating_keys = self . library . show_map [ input_id ]
elif input_id not in self . missing_shows :
self . missing_shows . append ( input_id )
elif id_type == " imdb " and not self . parts_collection :
if input_id not in self . ignore_imdb_ids :
if input_id in self . library . imdb_map :
rating_keys = self . library . imdb_map [ input_id ]
elif self . do_missing :
try :
tmdb_id , tmdb_type = self . config . Convert . imdb_to_tmdb ( input_id , fail = True )
if tmdb_type == " movie " :
if tmdb_id not in self . missing_movies :
self . missing_movies . append ( tmdb_id )
2021-12-18 05:59:53 +00:00
elif tmdb_type == " show " :
2021-12-15 15:50:20 +00:00
tvdb_id = self . config . Convert . tmdb_to_tvdb ( tmdb_id , fail = True )
if tvdb_id not in self . missing_shows :
self . missing_shows . append ( tvdb_id )
except Failed as e :
logger . error ( e )
continue
if not isinstance ( rating_keys , list ) :
rating_keys = [ rating_keys ]
for rk in rating_keys :
2021-08-07 06:01:21 +00:00
try :
2021-12-15 15:50:20 +00:00
items . append ( self . fetch_item ( rk ) )
2021-08-07 06:01:21 +00:00
except Failed as e :
logger . error ( e )
2021-12-15 15:50:20 +00:00
util . print_end ( )
if len ( items ) > 0 :
self . filter_and_save_items ( items )
def filter_and_save_items ( self , items ) :
name = self . obj . title if self . obj else self . name
total = len ( items )
max_length = len ( str ( total ) )
if ( self . filters or self . tmdb_filters ) and self . details [ " show_filtered " ] is True :
logger . info ( " " )
logger . info ( " Filtering Builders: " )
for i , item in enumerate ( items , 1 ) :
if not isinstance ( item , ( Movie , Show , Season , Episode ) ) :
logger . error ( f " { self . Type } Error: Item: { item } must be Movie, Show, Season, or Episode " )
continue
2021-12-17 14:24:46 +00:00
if item not in self . added_items :
2021-12-15 15:50:20 +00:00
if item . ratingKey in self . filtered_keys :
if self . details [ " show_filtered " ] is True :
logger . info ( f " { name } { self . Type } | X | { self . filtered_keys [ item . ratingKey ] } " )
else :
2021-12-17 14:24:46 +00:00
current_title = util . item_title ( item )
2021-12-15 15:50:20 +00:00
if self . check_filters ( item , f " { ( ' ' * ( max_length - len ( str ( i ) ) ) ) } { i } / { total } " ) :
2021-12-17 14:24:46 +00:00
self . added_items . append ( item )
2021-12-15 15:50:20 +00:00
else :
self . filtered_keys [ item . ratingKey ] = current_title
if self . details [ " show_filtered " ] is True :
logger . info ( f " { name } { self . Type } | X | { current_title } " )
2021-08-05 14:59:45 +00:00
2021-08-22 15:54:33 +00:00
def build_filter ( self , method , plex_filter , smart = False , type_override = None ) :
2021-05-30 02:19:38 +00:00
if smart :
2021-05-29 02:33:55 +00:00
logger . info ( " " )
logger . info ( f " Validating Method: { method } " )
if plex_filter is None :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: { method } attribute is blank " )
2021-05-29 02:33:55 +00:00
if not isinstance ( plex_filter , dict ) :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: { method } must be a dictionary: { plex_filter } " )
2021-05-30 02:19:38 +00:00
if smart :
2021-05-29 02:33:55 +00:00
logger . debug ( f " Value: { plex_filter } " )
filter_alias = { m . lower ( ) : m for m in plex_filter }
if " any " in filter_alias and " all " in filter_alias :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: Cannot have more then one base " )
2021-05-29 02:33:55 +00:00
2021-08-22 15:54:33 +00:00
if type_override :
sort_type = type_override
elif smart and " type " in filter_alias and self . library . is_show :
2021-05-29 02:33:55 +00:00
if plex_filter [ filter_alias [ " type " ] ] not in [ " shows " , " seasons " , " episodes " ] :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: type: { plex_filter [ filter_alias [ ' type ' ] ] } is invalid, must be either shows, season, or episodes " )
2021-05-29 02:33:55 +00:00
sort_type = plex_filter [ filter_alias [ " type " ] ]
elif self . library . is_show :
sort_type = " shows "
else :
sort_type = " movies "
ms = method . split ( " _ " )
filter_details = f " { ms [ 0 ] . capitalize ( ) } { sort_type . capitalize ( ) [ : - 1 ] } { ms [ 1 ] . capitalize ( ) } \n "
type_key , sorts = plex . sort_types [ sort_type ]
2021-05-30 02:19:38 +00:00
sort = " random " if smart else " title.asc "
2021-05-29 02:33:55 +00:00
if " sort_by " in filter_alias :
if plex_filter [ filter_alias [ " sort_by " ] ] is None :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: sort_by attribute is blank " )
2021-05-29 02:33:55 +00:00
if plex_filter [ filter_alias [ " sort_by " ] ] not in sorts :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: sort_by: { plex_filter [ filter_alias [ ' sort_by ' ] ] } is invalid " )
2021-05-29 02:33:55 +00:00
sort = plex_filter [ filter_alias [ " sort_by " ] ]
filter_details + = f " Sort By: { sort } \n "
limit = None
if " limit " in filter_alias :
if plex_filter [ filter_alias [ " limit " ] ] is None :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: limit attribute is blank " )
2021-05-29 02:33:55 +00:00
if not isinstance ( plex_filter [ filter_alias [ " limit " ] ] , int ) or plex_filter [ filter_alias [ " limit " ] ] < 1 :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: limit attribute must be an integer greater then 0 " )
2021-05-29 02:33:55 +00:00
limit = plex_filter [ filter_alias [ " limit " ] ]
filter_details + = f " Limit: { limit } \n "
validate = True
if " validate " in filter_alias :
if plex_filter [ filter_alias [ " validate " ] ] is None :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: validate attribute is blank " )
2021-05-29 02:33:55 +00:00
if not isinstance ( plex_filter [ filter_alias [ " validate " ] ] , bool ) :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: validate attribute must be either true or false " )
2021-05-29 02:33:55 +00:00
validate = plex_filter [ filter_alias [ " validate " ] ]
filter_details + = f " Validate: { validate } \n "
def _filter ( filter_dict , is_all = True , level = 1 ) :
output = " "
display = f " \n { ' ' * level } Match { ' all ' if is_all else ' any ' } of the following: "
level + = 1
indent = f " \n { ' ' * level } "
conjunction = f " { ' and ' if is_all else ' or ' } =1& "
for _key , _data in filter_dict . items ( ) :
2021-07-14 14:47:20 +00:00
attr , modifier , final_attr = self . _split ( _key )
2021-05-29 02:33:55 +00:00
def build_url_arg ( arg , mod = None , arg_s = None , mod_s = None ) :
arg_key = plex . search_translation [ attr ] if attr in plex . search_translation else attr
2021-07-26 18:52:32 +00:00
arg_key = plex . show_translation [ arg_key ] if self . library . is_show and arg_key in plex . show_translation else arg_key
2021-05-29 02:33:55 +00:00
if mod is None :
mod = plex . modifier_translation [ modifier ] if modifier in plex . modifier_translation else modifier
if arg_s is None :
arg_s = arg
if attr in string_filters and modifier in [ " " , " .not " ] :
mod_s = " does not contain " if modifier == " .not " else " contains "
elif mod_s is None :
2021-08-14 22:59:35 +00:00
mod_s = util . mod_displays [ modifier ]
2021-05-29 02:33:55 +00:00
param_s = plex . search_display [ attr ] if attr in plex . search_display else attr . title ( ) . replace ( ' _ ' , ' ' )
display_line = f " { indent } { param_s } { mod_s } { arg_s } "
return f " { arg_key } { mod } = { arg } & " , display_line
2021-07-14 14:47:20 +00:00
if final_attr not in plex . searches and not final_attr . startswith ( ( " any " , " all " ) ) :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: { final_attr } is not a valid { method } attribute " )
2021-07-14 14:47:20 +00:00
elif final_attr in plex . movie_only_searches and self . library . is_show :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: { final_attr } { method } attribute only works for movie libraries " )
2021-07-14 14:47:20 +00:00
elif final_attr in plex . show_only_searches and self . library . is_movie :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: { final_attr } { method } attribute only works for show libraries " )
2021-05-29 02:33:55 +00:00
elif _data is None :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: { final_attr } { method } attribute is blank " )
2021-07-14 14:47:20 +00:00
elif final_attr . startswith ( ( " any " , " all " ) ) :
2021-05-29 02:33:55 +00:00
dicts = util . get_list ( _data )
results = " "
display_add = " "
for dict_data in dicts :
if not isinstance ( dict_data , dict ) :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: { attr } must be either a dictionary or list of dictionaries " )
2021-05-29 02:33:55 +00:00
inside_filter , inside_display = _filter ( dict_data , is_all = attr == " all " , level = level )
if len ( inside_filter ) > 0 :
display_add + = inside_display
results + = f " { conjunction if len ( results ) > 0 else ' ' } push=1& { inside_filter } pop=1& "
else :
2021-07-14 14:47:20 +00:00
validation = self . validate_attribute ( attr , modifier , final_attr , _data , validate , pairs = True )
2021-05-29 02:33:55 +00:00
if validation is None :
continue
elif attr in plex . date_attributes and modifier in [ " " , " .not " ] :
last_text = " is not in the last " if modifier == " .not " else " is in the last "
last_mod = " %3E %3E " if modifier == " " else " % 3C % 3C "
results , display_add = build_url_arg ( f " - { validation } d " , mod = last_mod , arg_s = f " { validation } Days " , mod_s = last_text )
elif attr == " duration " and modifier in [ " .gt " , " .gte " , " .lt " , " .lte " ] :
results , display_add = build_url_arg ( validation * 60000 )
elif attr in plex . boolean_attributes :
bool_mod = " " if validation else " ! "
bool_arg = " true " if validation else " false "
results , display_add = build_url_arg ( 1 , mod = bool_mod , arg_s = bool_arg , mod_s = " is " )
2021-10-20 19:58:25 +00:00
elif ( attr in [ " title " , " episode_title " , " studio " , " decade " , " year " , " episode_year " ] or attr in plex . tags ) and modifier in [ " " , " .is " , " .isnot " , " .not " , " .begins " , " .ends " ] :
2021-05-29 02:33:55 +00:00
results = " "
display_add = " "
for og_value , result in validation :
2021-10-20 19:58:25 +00:00
built_arg = build_url_arg ( quote ( str ( result ) ) if attr in string_filters else result , arg_s = og_value )
2021-05-29 02:33:55 +00:00
display_add + = built_arg [ 1 ]
results + = f " { conjunction if len ( results ) > 0 else ' ' } { built_arg [ 0 ] } "
else :
results , display_add = build_url_arg ( validation )
display + = display_add
output + = f " { conjunction if len ( output ) > 0 else ' ' } { results } "
return output , display
if " any " not in filter_alias and " all " not in filter_alias :
base_dict = { }
2021-05-30 02:19:38 +00:00
any_dicts = [ ]
2021-05-29 02:33:55 +00:00
for alias_key , alias_value in filter_alias . items ( ) :
2021-06-22 14:54:11 +00:00
_ , _ , final = self . _split ( alias_key )
if final in plex . and_searches :
2021-05-30 02:19:38 +00:00
base_dict [ alias_value [ : - 4 ] ] = plex_filter [ alias_value ]
2021-06-22 14:54:11 +00:00
elif final in plex . or_searches :
2021-05-30 02:19:38 +00:00
any_dicts . append ( { alias_value : plex_filter [ alias_value ] } )
2021-06-22 14:54:11 +00:00
elif final in plex . searches :
2021-05-29 02:33:55 +00:00
base_dict [ alias_value ] = plex_filter [ alias_value ]
2021-05-30 02:19:38 +00:00
if len ( any_dicts ) > 0 :
base_dict [ " any " ] = any_dicts
2021-05-29 02:33:55 +00:00
base_all = True
if len ( base_dict ) == 0 :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: Must have either any or all as a base for { method } " )
2021-05-29 02:33:55 +00:00
else :
base = " all " if " all " in filter_alias else " any "
base_all = base == " all "
if plex_filter [ filter_alias [ base ] ] is None :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: { base } attribute is blank " )
2021-05-29 02:33:55 +00:00
if not isinstance ( plex_filter [ filter_alias [ base ] ] , dict ) :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: { base } must be a dictionary: { plex_filter [ filter_alias [ base ] ] } " )
2021-05-29 02:33:55 +00:00
base_dict = plex_filter [ filter_alias [ base ] ]
built_filter , filter_text = _filter ( base_dict , is_all = base_all )
filter_details = f " { filter_details } Filter: { filter_text } "
if len ( built_filter ) > 0 :
final_filter = built_filter [ : - 1 ] if base_all else f " push=1& { built_filter } pop=1 "
filter_url = f " ?type= { type_key } & { f ' limit= { limit } & ' if limit else ' ' } sort= { sorts [ sort ] } & { final_filter } "
else :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: No Filter Created " )
2021-05-29 02:33:55 +00:00
return type_key , filter_details , filter_url
2021-05-30 02:19:38 +00:00
def validate_attribute ( self , attribute , modifier , final , data , validate , pairs = False ) :
2021-05-27 17:40:35 +00:00
def smart_pair ( list_to_pair ) :
2021-05-30 02:19:38 +00:00
return [ ( t , t ) for t in list_to_pair ] if pairs else list_to_pair
2021-06-02 22:13:00 +00:00
if modifier == " .regex " :
regex_list = util . get_list ( data , split = False )
valid_regex = [ ]
for reg in regex_list :
try :
re . compile ( reg )
valid_regex . append ( reg )
except re . error :
util . print_stacktrace ( )
2021-12-13 07:30:19 +00:00
err = f " { self . Type } Error: Regular Expression Invalid: { reg } "
2021-06-02 22:13:00 +00:00
if validate :
raise Failed ( err )
else :
logger . error ( err )
return valid_regex
2021-09-13 02:42:33 +00:00
elif attribute in [ " title " , " studio " , " episode_title " , " audio_track_title " ] and modifier in [ " " , " .not " , " .is " , " .isnot " , " .begins " , " .ends " ] :
2021-05-27 17:40:35 +00:00
return smart_pair ( util . get_list ( data , split = False ) )
2021-05-28 23:18:28 +00:00
elif attribute == " original_language " :
return util . get_list ( data , lower = True )
elif attribute == " filepath " :
return util . get_list ( data )
2021-06-03 04:20:49 +00:00
elif attribute == " history " :
try :
2021-12-13 07:30:19 +00:00
return self . _parse ( final , data , datatype = " int " , maximum = 30 )
2021-06-03 04:20:49 +00:00
except Failed :
if str ( data ) . lower ( ) in [ " day " , " month " ] :
return data . lower ( )
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: history attribute invalid: { data } must be a number between 1-30, day, or month " )
2021-05-29 02:44:01 +00:00
elif attribute in plex . tags and modifier in [ " " , " .not " ] :
2021-05-28 23:18:28 +00:00
if attribute in plex . tmdb_attributes :
2021-05-27 17:40:35 +00:00
final_values = [ ]
for value in util . get_list ( data ) :
if value . lower ( ) == " tmdb " and " tmdb_person " in self . details :
for name in self . details [ " tmdb_person " ] :
final_values . append ( name )
else :
final_values . append ( value )
else :
final_values = util . get_list ( data )
2021-12-17 00:16:08 +00:00
use_title = not pairs
search_choices , names = self . library . get_search_choices ( attribute , title = use_title )
2021-06-16 03:20:45 +00:00
valid_list = [ ]
for value in final_values :
if str ( value ) . lower ( ) in search_choices :
if pairs :
valid_list . append ( ( value , search_choices [ str ( value ) . lower ( ) ] ) )
else :
valid_list . append ( search_choices [ str ( value ) . lower ( ) ] )
2021-05-27 17:40:35 +00:00
else :
2021-06-16 03:20:45 +00:00
error = f " Plex Error: { attribute } : { value } not found "
2021-12-17 00:16:08 +00:00
if self . details [ " show_options " ] :
error + = f " \n Options: { names } "
2021-06-16 03:20:45 +00:00
if validate :
raise Failed ( error )
else :
logger . error ( error )
return valid_list
2021-08-09 15:40:44 +00:00
elif attribute in [ " year " , " episode_year " , " tmdb_year " ] and modifier in [ " .gt " , " .gte " , " .lt " , " .lte " ] :
2021-12-13 07:30:19 +00:00
return self . _parse ( final , data , datatype = " int " , minimum = 1800 , maximum = self . current_year )
2021-07-21 17:40:05 +00:00
elif attribute in plex . date_attributes and modifier in [ " .before " , " .after " ] :
2021-07-21 19:25:29 +00:00
return util . validate_date ( data , final , return_as = " % Y- % m- %d " )
2021-05-28 23:18:28 +00:00
elif attribute in plex . number_attributes and modifier in [ " " , " .not " , " .gt " , " .gte " , " .lt " , " .lte " ] :
2021-12-13 07:30:19 +00:00
return self . _parse ( final , data , datatype = " int " )
2021-05-28 23:18:28 +00:00
elif attribute in plex . float_attributes and modifier in [ " .gt " , " .gte " , " .lt " , " .lte " ] :
2021-12-13 07:30:19 +00:00
return self . _parse ( final , data , datatype = " float " , minimum = 0 , maximum = 10 )
2021-08-09 15:40:44 +00:00
elif attribute in [ " decade " , " year " , " episode_year " , " tmdb_year " ] and modifier in [ " " , " .not " ] :
2021-07-30 19:19:43 +00:00
final_years = [ ]
values = util . get_list ( data )
for value in values :
2021-12-13 07:30:19 +00:00
final_years . append ( self . _parse ( final , value , datatype = " int " , minimum = 1800 , maximum = self . current_year ) )
2021-07-30 19:19:43 +00:00
return smart_pair ( final_years )
2021-12-18 05:59:53 +00:00
elif attribute in plex . boolean_attributes + boolean_filters :
2021-12-13 07:30:19 +00:00
return self . _parse ( attribute , data , datatype = " bool " )
2021-05-27 17:40:35 +00:00
else :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: { final } attribute not supported " )
2021-05-27 17:40:35 +00:00
def _split ( self , text ) :
attribute , modifier = os . path . splitext ( str ( text ) . lower ( ) )
attribute = method_alias [ attribute ] if attribute in method_alias else attribute
modifier = modifier_alias [ modifier ] if modifier in modifier_alias else modifier
2021-07-03 04:18:09 +00:00
if attribute == " add_to_arr " :
2021-05-27 17:40:35 +00:00
attribute = " radarr_add " if self . library . is_movie else " sonarr_add "
2021-07-03 04:18:09 +00:00
elif attribute in [ " arr_tag " , " arr_folder " ] :
attribute = f " { ' rad ' if self . library . is_movie else ' son ' } { attribute } "
2021-05-30 21:03:03 +00:00
elif attribute in plex . date_attributes and modifier in [ " .gt " , " .gte " ] :
modifier = " .after "
elif attribute in plex . date_attributes and modifier in [ " .lt " , " .lte " ] :
modifier = " .before "
2021-05-27 17:40:35 +00:00
final = f " { attribute } { modifier } "
if text != final :
logger . warning ( f " Collection Warning: { text } attribute will run as { final } " )
return attribute , modifier , final
2021-05-26 19:14:51 +00:00
def fetch_item ( self , item ) :
try :
2021-08-22 15:54:33 +00:00
current = self . library . fetchItem ( item . ratingKey if isinstance ( item , ( Movie , Show , Season , Episode ) ) else int ( item ) )
if not isinstance ( current , ( Movie , Show , Season , Episode ) ) :
2021-05-26 19:14:51 +00:00
raise NotFound
2021-05-27 20:09:39 +00:00
return current
2021-05-26 19:14:51 +00:00
except ( BadRequest , NotFound ) :
raise Failed ( f " Plex Error: Item { item } not found " )
2021-05-26 14:45:33 +00:00
def add_to_collection ( self ) :
2021-05-12 14:25:48 +00:00
name , collection_items = self . library . get_collection_name_and_items ( self . obj if self . obj else self . name , self . smart_label_collection )
2021-12-17 14:24:46 +00:00
total = len ( self . added_items )
2021-11-03 14:36:11 +00:00
amount_added = 0
2021-12-17 14:24:46 +00:00
playlist_adds = [ ]
for item in self . added_items :
current_operation = " = " if item in collection_items else " + "
logger . info ( util . adjust_space ( f " { name } { self . Type } | { current_operation } | { util . item_title ( item ) } " ) )
if item in collection_items :
self . plex_map [ item . ratingKey ] = None
2021-07-07 16:16:00 +00:00
else :
2021-12-17 14:24:46 +00:00
if self . playlist :
playlist_adds . append ( item )
else :
self . library . alter_collection ( item , name , smart_label_collection = self . smart_label_collection )
2021-11-03 14:36:11 +00:00
amount_added + = 1
2021-12-07 06:29:41 +00:00
if self . details [ " collection_changes_webhooks " ] :
2021-12-17 23:18:34 +00:00
if item . ratingKey in self . library . movie_rating_key_map :
2021-12-17 14:24:46 +00:00
add_id = self . library . movie_rating_key_map [ item . ratingKey ]
2021-12-17 23:18:34 +00:00
elif item . ratingKey in self . library . show_rating_key_map :
2021-12-17 14:24:46 +00:00
add_id = self . library . show_rating_key_map [ item . ratingKey ]
2021-10-04 17:51:32 +00:00
else :
add_id = None
2021-12-17 23:18:34 +00:00
self . notification_additions . append ( util . item_set ( item , add_id ) )
2021-12-17 14:24:46 +00:00
if self . playlist and playlist_adds and not self . obj :
self . obj = self . library . create_playlist ( self . name , playlist_adds )
logger . info ( " " )
logger . info ( f " Playlist: { self . name } created " )
elif self . playlist and playlist_adds :
self . obj . addItems ( playlist_adds )
2021-05-26 13:25:32 +00:00
util . print_end ( )
2021-05-24 03:38:46 +00:00
logger . info ( " " )
2021-08-22 15:54:33 +00:00
logger . info ( f " { total } { self . collection_level . capitalize ( ) } { ' s ' if total > 1 else ' ' } Processed " )
2021-11-03 14:36:11 +00:00
return amount_added
2021-02-20 05:41:45 +00:00
2021-10-20 19:58:25 +00:00
def sync_collection ( self ) :
2021-11-03 14:36:11 +00:00
amount_removed = 0
2021-12-17 14:24:46 +00:00
playlist_removes = [ ]
2021-10-20 19:58:25 +00:00
for ratingKey , item in self . plex_map . items ( ) :
if item is not None :
2021-11-03 14:36:11 +00:00
if amount_removed == 0 :
2021-10-20 19:58:25 +00:00
logger . info ( " " )
2021-12-17 14:24:46 +00:00
util . separator ( f " Removed from { self . name } { self . Type } " , space = False , border = False )
2021-10-20 19:58:25 +00:00
logger . info ( " " )
self . library . reload ( item )
2021-12-17 14:24:46 +00:00
logger . info ( f " { self . name } { self . Type } | - | { util . item_title ( item ) } " )
if self . playlist :
playlist_removes . append ( item )
else :
self . library . alter_collection ( item , self . name , smart_label_collection = self . smart_label_collection , add = False )
amount_removed + = 1
2021-12-07 06:29:41 +00:00
if self . details [ " collection_changes_webhooks " ] :
2021-12-17 23:18:34 +00:00
if item . ratingKey in self . library . movie_rating_key_map :
2021-10-20 19:58:25 +00:00
remove_id = self . library . movie_rating_key_map [ item . ratingKey ]
2021-12-17 23:18:34 +00:00
elif item . ratingKey in self . library . show_rating_key_map :
2021-10-20 19:58:25 +00:00
remove_id = self . library . show_rating_key_map [ item . ratingKey ]
else :
remove_id = None
2021-12-17 23:18:34 +00:00
self . notification_removals . append ( util . item_set ( item , remove_id ) )
2021-12-17 14:24:46 +00:00
if self . playlist and playlist_removes :
2021-12-17 23:18:34 +00:00
self . obj . reload ( )
2021-12-17 14:24:46 +00:00
self . obj . removeItems ( playlist_removes )
2021-11-03 14:36:11 +00:00
if amount_removed > 0 :
2021-10-20 19:58:25 +00:00
logger . info ( " " )
2021-11-03 14:36:11 +00:00
logger . info ( f " { amount_removed } { self . collection_level . capitalize ( ) } { ' s ' if amount_removed == 1 else ' ' } Removed " )
return amount_removed
2021-10-20 19:58:25 +00:00
2021-08-07 06:01:21 +00:00
def check_tmdb_filter ( self , item_id , is_movie , item = None , check_released = False ) :
if self . tmdb_filters or check_released :
try :
if item is None :
item = self . config . TMDb . get_movie ( item_id ) if is_movie else self . config . TMDb . get_show ( self . config . Convert . tvdb_to_tmdb ( item_id ) )
if check_released :
if util . validate_date ( item . release_date if is_movie else item . first_air_date , " " ) > self . current_time :
return False
for filter_method , filter_data in self . tmdb_filters :
filter_attr , modifier , filter_final = self . _split ( filter_method )
if filter_attr == " original_language " :
if ( modifier == " .not " and item . original_language in filter_data ) \
or ( modifier == " " and item . original_language not in filter_data ) :
return False
elif filter_attr in [ " first_episode_aired " , " last_episode_aired " ] :
tmdb_date = None
if filter_attr == " first_episode_aired " :
tmdb_date = util . validate_date ( item . first_air_date , " TMDB First Air Date " )
elif filter_attr == " last_episode_aired " :
tmdb_date = util . validate_date ( item . last_air_date , " TMDB Last Air Date " )
if util . is_date_filter ( tmdb_date , modifier , filter_data , filter_final , self . current_time ) :
return False
elif modifier in [ " .gt " , " .gte " , " .lt " , " .lte " ] :
attr = None
if filter_attr == " tmdb_vote_count " :
attr = item . vote_count
2021-08-09 15:40:44 +00:00
elif filter_attr == " tmdb_year " and is_movie :
2021-08-07 06:01:21 +00:00
attr = item . year
2021-08-09 15:40:44 +00:00
elif filter_attr == " tmdb_year " and not is_movie :
2021-08-07 06:01:21 +00:00
air_date = item . first_air_date
if air_date :
2021-08-09 15:40:44 +00:00
attr = util . validate_date ( air_date , " TMDb Year Filter " ) . year
2021-08-07 06:01:21 +00:00
if util . is_number_filter ( attr , modifier , filter_data ) :
return False
except Failed :
return False
return True
2021-05-26 14:58:04 +00:00
def check_filters ( self , current , display ) :
2021-12-01 16:59:49 +00:00
if ( self . filters or self . tmdb_filters ) and not self . details [ " only_filter_missing " ] :
2021-05-26 14:58:04 +00:00
util . print_return ( f " Filtering { display } { current . title } " )
2021-08-09 15:40:44 +00:00
if self . tmdb_filters :
if current . ratingKey not in self . library . movie_rating_key_map and current . ratingKey not in self . library . show_rating_key_map :
logger . warning ( f " Filter Error: No { ' TMDb ' if self . library . is_movie else ' TVDb ' } ID found for { current . title } " )
return False
try :
if current . ratingKey in self . library . movie_rating_key_map :
t_id = self . library . movie_rating_key_map [ current . ratingKey ]
else :
t_id = self . library . show_rating_key_map [ current . ratingKey ]
except Failed as e :
logger . error ( e )
return False
if not self . check_tmdb_filter ( t_id , current . ratingKey in self . library . movie_rating_key_map ) :
return False
2021-05-26 14:58:04 +00:00
for filter_method , filter_data in self . filters :
2021-05-28 23:18:28 +00:00
filter_attr , modifier , filter_final = self . _split ( filter_method )
filter_actual = filter_translation [ filter_attr ] if filter_attr in filter_translation else filter_attr
2021-08-09 15:40:44 +00:00
if filter_attr in [ " release " , " added " , " last_played " ] :
2021-08-07 06:01:21 +00:00
if util . is_date_filter ( getattr ( current , filter_actual ) , modifier , filter_data , filter_final , self . current_time ) :
2021-08-04 19:17:34 +00:00
return False
2021-08-07 06:01:21 +00:00
elif filter_attr in [ " audio_track_title " , " filepath " , " title " , " studio " ] :
values = [ ]
if filter_attr == " audio_track_title " :
for media in current . media :
for part in media . parts :
values . extend ( [ a . title for a in part . audioStreams ( ) if a . title ] )
elif filter_attr == " filepath " :
values = [ loc for loc in current . locations ]
elif filter_attr in [ " title " , " studio " ] :
values = [ getattr ( current , filter_actual ) ]
if util . is_string_filter ( values , modifier , filter_data ) :
2021-05-27 17:40:35 +00:00
return False
2021-12-18 05:59:53 +00:00
elif filter_attr in boolean_filters :
filter_check = False
if filter_attr == " has_collection " :
filter_check = len ( current . collections ) > 0
elif filter_attr == " has_overlay " :
for label in current . labels :
if label . tag . lower ( ) . endswith ( " overlay " ) :
filter_check = True
if util . is_boolean_filter ( filter_data , filter_check ) :
2021-12-18 03:27:05 +00:00
return False
2021-06-03 04:20:49 +00:00
elif filter_attr == " history " :
item_date = current . originallyAvailableAt
if item_date is None :
return False
elif filter_data == " day " :
2021-08-02 15:52:43 +00:00
if item_date . month != self . current_time . month or item_date . day != self . current_time . day :
2021-06-03 04:20:49 +00:00
return False
elif filter_data == " month " :
2021-08-02 15:52:43 +00:00
if item_date . month != self . current_time . month :
2021-06-03 04:20:49 +00:00
return False
else :
date_match = False
for i in range ( filter_data ) :
2021-08-02 15:52:43 +00:00
check_date = self . current_time - timedelta ( days = i )
2021-06-03 04:20:49 +00:00
if item_date . month == check_date . month and item_date . day == check_date . day :
date_match = True
if date_match is False :
return False
2021-05-28 23:18:28 +00:00
elif modifier in [ " .gt " , " .gte " , " .lt " , " .lte " ] :
2021-08-07 06:01:21 +00:00
divider = 60000 if filter_attr == " duration " else 1
if util . is_number_filter ( getattr ( current , filter_actual ) / divider , modifier , filter_data ) :
2021-05-26 14:58:04 +00:00
return False
else :
attrs = [ ]
2021-05-28 23:18:28 +00:00
if filter_attr in [ " resolution " , " audio_language " , " subtitle_language " ] :
2021-05-26 14:58:04 +00:00
for media in current . media :
2021-05-28 23:18:28 +00:00
if filter_attr == " resolution " :
2021-05-26 14:58:04 +00:00
attrs . extend ( [ media . videoResolution ] )
for part in media . parts :
2021-05-28 23:18:28 +00:00
if filter_attr == " audio_language " :
2021-05-26 14:58:04 +00:00
attrs . extend ( [ a . language for a in part . audioStreams ( ) ] )
2021-05-28 23:18:28 +00:00
if filter_attr == " subtitle_language " :
2021-05-26 14:58:04 +00:00
attrs . extend ( [ s . language for s in part . subtitleStreams ( ) ] )
2021-05-28 23:18:28 +00:00
elif filter_attr in [ " content_rating " , " year " , " rating " ] :
attrs = [ str ( getattr ( current , filter_actual ) ) ]
elif filter_attr in [ " actor " , " country " , " director " , " genre " , " label " , " producer " , " writer " , " collection " ] :
attrs = [ attr . tag for attr in getattr ( current , filter_actual ) ]
2021-05-26 14:58:04 +00:00
else :
2021-05-28 23:18:28 +00:00
raise Failed ( f " Filter Error: filter: { filter_final } not supported " )
2021-05-26 14:58:04 +00:00
2021-05-28 23:18:28 +00:00
if ( not list ( set ( filter_data ) & set ( attrs ) ) and modifier == " " ) \
or ( list ( set ( filter_data ) & set ( attrs ) ) and modifier == " .not " ) :
2021-05-26 14:58:04 +00:00
return False
util . print_return ( f " Filtering { display } { current . title } " )
return True
2021-05-14 19:22:59 +00:00
def run_missing ( self ) :
2021-11-03 14:36:11 +00:00
added_to_radarr = 0
added_to_sonarr = 0
2021-05-14 19:22:59 +00:00
if len ( self . missing_movies ) > 0 :
2021-05-12 14:25:48 +00:00
missing_movies_with_names = [ ]
2021-05-14 19:22:59 +00:00
for missing_id in self . missing_movies :
2021-05-12 14:25:48 +00:00
try :
movie = self . config . TMDb . get_movie ( missing_id )
except Failed as e :
logger . error ( e )
continue
2021-07-21 19:25:29 +00:00
current_title = f " { movie . title } ( { util . validate_date ( movie . release_date , ' test ' ) . year } ) " if movie . release_date else movie . title
2021-08-16 05:41:04 +00:00
if self . check_tmdb_filter ( missing_id , True , item = movie , check_released = self . details [ " missing_only_released " ] ) :
2021-06-27 23:21:49 +00:00
missing_movies_with_names . append ( ( current_title , missing_id ) )
2021-05-12 14:25:48 +00:00
if self . details [ " show_missing " ] is True :
2021-12-17 14:24:46 +00:00
logger . info ( f " { self . name } { self . Type } | ? | { current_title } (TMDb: { missing_id } ) " )
2021-08-06 17:46:13 +00:00
else :
if self . details [ " show_filtered " ] is True and self . details [ " show_missing " ] is True :
2021-12-17 14:24:46 +00:00
logger . info ( f " { self . name } { self . Type } | X | { current_title } (TMDb: { missing_id } ) " )
2021-05-24 03:38:46 +00:00
logger . info ( " " )
2021-05-12 14:25:48 +00:00
logger . info ( f " { len ( missing_movies_with_names ) } Movie { ' s ' if len ( missing_movies_with_names ) > 1 else ' ' } Missing " )
2021-08-12 13:37:30 +00:00
if len ( missing_movies_with_names ) > 0 :
if self . details [ " save_missing " ] is True :
self . library . add_missing ( self . name , missing_movies_with_names , True )
2021-08-16 05:41:04 +00:00
if self . run_again or ( self . library . Radarr and ( self . radarr_details [ " add " ] or " item_radarr_tag " in self . item_details ) ) :
2021-08-12 13:37:30 +00:00
missing_tmdb_ids = [ missing_id for title , missing_id in missing_movies_with_names ]
if self . library . Radarr :
2021-08-16 05:41:04 +00:00
if self . radarr_details [ " add " ] :
2021-08-12 13:37:30 +00:00
try :
2021-11-03 14:36:11 +00:00
added_to_radarr + = self . library . Radarr . add_tmdb ( missing_tmdb_ids , * * self . radarr_details )
2021-08-12 13:37:30 +00:00
except Failed as e :
logger . error ( e )
if " item_radarr_tag " in self . item_details :
try :
self . library . Radarr . edit_tags ( missing_tmdb_ids , self . item_details [ " item_radarr_tag " ] , self . item_details [ " apply_tags " ] )
except Failed as e :
logger . error ( e )
if self . run_again :
self . run_again_movies . extend ( missing_tmdb_ids )
2021-05-14 19:22:59 +00:00
if len ( self . missing_shows ) > 0 and self . library . is_show :
2021-05-12 14:25:48 +00:00
missing_shows_with_names = [ ]
2021-05-14 19:22:59 +00:00
for missing_id in self . missing_shows :
2021-05-12 14:25:48 +00:00
try :
2021-10-26 15:01:08 +00:00
show = self . config . TVDb . get_series ( missing_id )
2021-05-12 14:25:48 +00:00
except Failed as e :
logger . error ( e )
continue
2021-08-16 05:41:04 +00:00
if self . check_tmdb_filter ( missing_id , False , check_released = self . details [ " missing_only_released " ] ) :
2021-10-26 13:39:30 +00:00
missing_shows_with_names . append ( ( show . title , missing_id ) )
2021-05-12 14:25:48 +00:00
if self . details [ " show_missing " ] is True :
2021-12-17 14:24:46 +00:00
logger . info ( f " { self . name } { self . Type } | ? | { show . title } (TVDB: { missing_id } ) " )
2021-08-06 17:46:13 +00:00
else :
if self . details [ " show_filtered " ] is True and self . details [ " show_missing " ] is True :
2021-12-17 14:24:46 +00:00
logger . info ( f " { self . name } { self . Type } | X | { show . title } (TVDb: { missing_id } ) " )
2021-05-24 03:38:46 +00:00
logger . info ( " " )
2021-05-12 14:25:48 +00:00
logger . info ( f " { len ( missing_shows_with_names ) } Show { ' s ' if len ( missing_shows_with_names ) > 1 else ' ' } Missing " )
2021-08-12 13:37:30 +00:00
if len ( missing_shows_with_names ) > 0 :
if self . details [ " save_missing " ] is True :
self . library . add_missing ( self . name , missing_shows_with_names , False )
2021-08-16 05:41:04 +00:00
if self . run_again or ( self . library . Sonarr and ( self . sonarr_details [ " add " ] or " item_sonarr_tag " in self . item_details ) ) :
2021-08-12 13:37:30 +00:00
missing_tvdb_ids = [ missing_id for title , missing_id in missing_shows_with_names ]
if self . library . Sonarr :
2021-08-16 05:41:04 +00:00
if self . sonarr_details [ " add " ] :
2021-08-12 13:37:30 +00:00
try :
2021-11-03 14:36:11 +00:00
added_to_sonarr + = self . library . Sonarr . add_tvdb ( missing_tvdb_ids , * * self . sonarr_details )
2021-08-12 13:37:30 +00:00
except Failed as e :
logger . error ( e )
if " item_sonarr_tag " in self . item_details :
try :
self . library . Sonarr . edit_tags ( missing_tvdb_ids , self . item_details [ " item_sonarr_tag " ] , self . item_details [ " apply_tags " ] )
except Failed as e :
logger . error ( e )
if self . run_again :
self . run_again_shows . extend ( missing_tvdb_ids )
2021-08-22 15:54:33 +00:00
if len ( self . missing_parts ) > 0 and self . library . is_show and self . details [ " save_missing " ] is True :
for missing in self . missing_parts :
2021-12-17 14:24:46 +00:00
logger . info ( f " { self . name } { self . Type } | X | { missing } " )
2021-11-03 14:36:11 +00:00
return added_to_radarr , added_to_sonarr
2021-08-22 15:54:33 +00:00
2021-09-15 03:16:59 +00:00
def load_collection_items ( self ) :
if self . build_collection and self . obj :
self . items = self . library . get_collection_items ( self . obj , self . smart_label_collection )
elif not self . build_collection :
2021-08-05 18:55:39 +00:00
logger . info ( " " )
2021-12-17 14:24:46 +00:00
util . separator ( f " Items Found for { self . name } { self . Type } " , space = False , border = False )
2021-08-05 18:55:39 +00:00
logger . info ( " " )
2021-12-17 14:24:46 +00:00
self . items = self . added_items
2021-09-15 03:16:59 +00:00
if not self . items :
2021-12-17 14:24:46 +00:00
raise Failed ( f " Plex Error: No { self . Type } items found " )
2021-05-26 19:14:51 +00:00
2021-09-15 03:16:59 +00:00
def update_item_details ( self ) :
2021-08-05 18:55:39 +00:00
logger . info ( " " )
2021-12-17 14:24:46 +00:00
util . separator ( f " Updating Details of the Items in { self . name } { self . Type } " , space = False , border = False )
2021-08-05 18:55:39 +00:00
logger . info ( " " )
2021-06-30 03:08:38 +00:00
overlay = None
overlay_folder = None
2021-08-12 20:36:38 +00:00
overlay_name = " "
2021-06-30 03:08:38 +00:00
rating_keys = [ ]
if " item_overlay " in self . item_details :
overlay_name = self . item_details [ " item_overlay " ]
2021-07-01 22:01:30 +00:00
if self . config . Cache :
2021-08-12 20:36:38 +00:00
cache_keys = self . config . Cache . query_image_map_overlay ( self . library . image_table_name , overlay_name )
if cache_keys :
for rating_key in cache_keys :
try :
item = self . fetch_item ( rating_key )
except Failed as e :
logger . error ( e )
continue
2021-09-21 02:24:07 +00:00
if isinstance ( item , ( Movie , Show ) ) :
self . library . edit_tags ( " label " , item , add_tags = [ f " { overlay_name } Overlay " ] )
2021-08-12 20:36:38 +00:00
self . config . Cache . update_remove_overlay ( self . library . image_table_name , overlay_name )
rating_keys = [ int ( item . ratingKey ) for item in self . library . get_labeled_items ( f " { overlay_name } Overlay " ) ]
2021-06-30 03:08:38 +00:00
overlay_folder = os . path . join ( self . config . default_dir , " overlays " , overlay_name )
2021-07-26 14:55:28 +00:00
overlay_image = Image . open ( os . path . join ( overlay_folder , " overlay.png " ) ) . convert ( " RGBA " )
2021-06-30 03:08:38 +00:00
temp_image = os . path . join ( overlay_folder , f " temp.png " )
overlay = ( overlay_name , overlay_folder , overlay_image , temp_image )
2021-09-15 03:16:59 +00:00
revert = " revert_overlay " in self . item_details
2021-08-22 15:55:37 +00:00
if revert :
overlay = None
2021-09-15 03:16:59 +00:00
add_tags = self . item_details [ " item_label " ] if " item_label " in self . item_details else None
remove_tags = self . item_details [ " item_label.remove " ] if " item_label.remove " in self . item_details else None
sync_tags = self . item_details [ " item_label.sync " ] if " item_label.sync " in self . item_details else None
2021-11-24 13:22:17 +00:00
tmdb_paths = [ ]
tvdb_paths = [ ]
2021-09-15 03:16:59 +00:00
for item in self . items :
2021-08-22 15:55:37 +00:00
if int ( item . ratingKey ) in rating_keys and not revert :
2021-06-30 03:08:38 +00:00
rating_keys . remove ( int ( item . ratingKey ) )
2021-09-15 03:16:59 +00:00
if " item_assets " in self . item_details or overlay is not None :
2021-07-06 18:54:53 +00:00
try :
self . library . update_item_from_assets ( item , overlay = overlay )
2021-07-06 19:59:55 +00:00
except Failed as e :
logger . error ( e )
2021-05-26 19:14:51 +00:00
self . library . edit_tags ( " label " , item , add_tags = add_tags , remove_tags = remove_tags , sync_tags = sync_tags )
2021-11-24 13:22:17 +00:00
path = os . path . dirname ( str ( item . locations [ 0 ] ) ) if self . library . is_movie else str ( item . locations [ 0 ] )
2021-11-29 14:11:23 +00:00
if self . library . Radarr and item . ratingKey in self . library . movie_rating_key_map :
2021-12-09 15:23:51 +00:00
path = path . replace ( self . library . Radarr . plex_path , self . library . Radarr . radarr_path )
path = path [ : - 1 ] if path . endswith ( ( ' / ' , ' \\ ' ) ) else path
tmdb_paths . append ( ( self . library . movie_rating_key_map [ item . ratingKey ] , path ) )
2021-11-29 14:11:23 +00:00
if self . library . Sonarr and item . ratingKey in self . library . show_rating_key_map :
2021-12-09 15:23:51 +00:00
path = path . replace ( self . library . Sonarr . plex_path , self . library . Sonarr . sonarr_path )
path = path [ : - 1 ] if path . endswith ( ( ' / ' , ' \\ ' ) ) else path
tvdb_paths . append ( ( self . library . show_rating_key_map [ item . ratingKey ] , path ) )
2021-05-26 19:14:51 +00:00
advance_edits = { }
for method_name , method_data in self . item_details . items ( ) :
if method_name in plex . item_advance_keys :
key , options = plex . item_advance_keys [ method_name ]
if getattr ( item , key ) != options [ method_data ] :
advance_edits [ key ] = options [ method_data ]
2021-08-22 15:54:33 +00:00
self . library . edit_item ( item , item . title , self . collection_level . capitalize ( ) , advance_edits , advanced = True )
2021-11-23 19:45:41 +00:00
2021-12-09 06:37:11 +00:00
if " item_tmdb_season_titles " in self . item_details and item . ratingKey in self . library . show_rating_key_map :
try :
tmdb_id = self . config . Convert . tvdb_to_tmdb ( self . library . show_rating_key_map [ item . ratingKey ] )
names = { str ( s . season_number ) : s . name for s in self . config . TMDb . get_show ( tmdb_id ) . seasons }
for season in self . library . query ( item . seasons ) :
if str ( season . index ) in names :
self . library . edit_query ( season , { " title.locked " : 1 , " title.value " : names [ str ( season . index ) ] } )
except Failed as e :
logger . error ( e )
2021-11-23 19:45:41 +00:00
# Locking should come before refreshing since refreshing can change metadata (i.e. if specified to both lock
# background/poster and also refreshing, assume that the current background/poster should be kept)
2021-11-21 00:15:45 +00:00
if " item_lock_background " in self . item_details :
2021-12-09 06:37:11 +00:00
self . library . query ( item . lockArt )
2021-11-20 23:50:17 +00:00
if " item_lock_poster " in self . item_details :
2021-12-09 06:37:11 +00:00
self . library . query ( item . lockPoster )
2021-11-23 19:45:41 +00:00
if " item_lock_title " in self . item_details :
2021-12-09 06:37:11 +00:00
self . library . edit_query ( item , { " title.locked " : 1 } )
2021-10-20 20:09:51 +00:00
if " item_refresh " in self . item_details :
2021-12-09 06:37:11 +00:00
self . library . query ( item . refresh )
2021-05-26 19:14:51 +00:00
2021-11-29 14:11:23 +00:00
if self . library . Radarr and tmdb_paths :
2021-08-16 05:41:04 +00:00
if " item_radarr_tag " in self . item_details :
2021-11-29 14:11:23 +00:00
self . library . Radarr . edit_tags ( [ t [ 0 ] if isinstance ( t , tuple ) else t for t in tmdb_paths ] , self . item_details [ " item_radarr_tag " ] , self . item_details [ " apply_tags " ] )
2021-08-16 05:41:04 +00:00
if self . radarr_details [ " add_existing " ] :
2021-11-29 14:11:23 +00:00
self . library . Radarr . add_tmdb ( tmdb_paths , * * self . radarr_details )
2021-07-03 04:18:09 +00:00
2021-11-29 14:11:23 +00:00
if self . library . Sonarr and tvdb_paths :
2021-08-16 05:41:04 +00:00
if " item_sonarr_tag " in self . item_details :
2021-11-29 14:11:23 +00:00
self . library . Sonarr . edit_tags ( [ t [ 0 ] if isinstance ( t , tuple ) else t for t in tvdb_paths ] , self . item_details [ " item_sonarr_tag " ] , self . item_details [ " apply_tags " ] )
2021-08-16 05:41:04 +00:00
if self . sonarr_details [ " add_existing " ] :
2021-11-29 14:11:23 +00:00
self . library . Sonarr . add_tvdb ( tvdb_paths , * * self . sonarr_details )
2021-07-03 04:18:09 +00:00
2021-06-30 03:08:38 +00:00
for rating_key in rating_keys :
try :
item = self . fetch_item ( rating_key )
except Failed as e :
logger . error ( e )
continue
2021-08-12 20:36:38 +00:00
self . library . edit_tags ( " label " , item , remove_tags = [ f " { overlay_name } Overlay " ] )
2021-06-30 03:08:38 +00:00
og_image = os . path . join ( overlay_folder , f " { rating_key } .png " )
if os . path . exists ( og_image ) :
2021-07-14 14:47:20 +00:00
self . library . upload_file_poster ( item , og_image )
2021-06-30 03:08:38 +00:00
os . remove ( og_image )
2021-08-12 20:36:38 +00:00
self . config . Cache . update_image_map ( item . ratingKey , self . library . image_table_name , " " , " " )
2021-06-30 03:08:38 +00:00
2021-09-13 01:37:56 +00:00
def delete_collection ( self ) :
if self . obj :
self . library . query ( self . obj . delete )
2021-09-15 03:16:59 +00:00
def load_collection ( self ) :
2021-05-12 14:25:48 +00:00
if not self . obj and self . smart_url :
self . library . create_smart_collection ( self . name , self . smart_type_key , self . smart_url )
2021-05-17 14:35:47 +00:00
elif self . smart_label_collection :
2021-05-16 22:06:51 +00:00
try :
2021-05-17 14:35:47 +00:00
smart_type , self . smart_url = self . library . smart_label_url ( self . name , self . smart_sort )
if not self . obj :
self . library . create_smart_collection ( self . name , smart_type , self . smart_url )
2021-05-16 22:06:51 +00:00
except Failed :
2021-12-13 07:30:19 +00:00
raise Failed ( f " { self . Type } Error: Label: { self . name } was not added to any items in the Library " )
2021-12-17 14:24:46 +00:00
self . obj = self . library . get_playlist ( self . name ) if self . playlist else self . library . get_collection ( self . name )
2021-10-04 17:51:32 +00:00
if not self . exists :
self . created = True
2021-05-12 14:25:48 +00:00
2021-09-15 03:16:59 +00:00
def update_details ( self ) :
logger . info ( " " )
2021-12-17 14:24:46 +00:00
util . separator ( f " Updating Details of { self . name } { self . Type } " , space = False , border = False )
2021-09-15 03:16:59 +00:00
logger . info ( " " )
2021-05-12 14:25:48 +00:00
if self . smart_url and self . smart_url != self . library . smart_filter ( self . obj ) :
self . library . update_smart_collection ( self . obj , self . smart_url )
2021-05-02 04:22:48 +00:00
logger . info ( f " Detail: Smart Filter updated to { self . smart_url } " )
2021-02-20 05:41:45 +00:00
edits = { }
2021-02-28 23:06:04 +00:00
def get_summary ( summary_method , summaries ) :
2021-12-17 14:24:46 +00:00
logger . info ( f " Detail: { summary_method } updated { self . Type } Summary " )
2021-02-28 23:06:04 +00:00
return summaries [ summary_method ]
if " summary " in self . summaries : summary = get_summary ( " summary " , self . summaries )
elif " tmdb_description " in self . summaries : summary = get_summary ( " tmdb_description " , self . summaries )
2021-03-08 21:54:19 +00:00
elif " letterboxd_description " in self . summaries : summary = get_summary ( " letterboxd_description " , self . summaries )
2021-02-28 23:06:04 +00:00
elif " tmdb_summary " in self . summaries : summary = get_summary ( " tmdb_summary " , self . summaries )
2021-03-08 19:53:05 +00:00
elif " tvdb_summary " in self . summaries : summary = get_summary ( " tvdb_summary " , self . summaries )
2021-02-28 23:06:04 +00:00
elif " tmdb_biography " in self . summaries : summary = get_summary ( " tmdb_biography " , self . summaries )
elif " tmdb_person " in self . summaries : summary = get_summary ( " tmdb_person " , self . summaries )
elif " tmdb_collection_details " in self . summaries : summary = get_summary ( " tmdb_collection_details " , self . summaries )
2021-03-08 15:25:35 +00:00
elif " trakt_list_details " in self . summaries : summary = get_summary ( " trakt_list_details " , self . summaries )
2021-02-28 23:06:04 +00:00
elif " tmdb_list_details " in self . summaries : summary = get_summary ( " tmdb_list_details " , self . summaries )
2021-06-11 14:26:11 +00:00
elif " letterboxd_list_details " in self . summaries : summary = get_summary ( " letterboxd_list_details " , self . summaries )
2021-07-03 19:17:05 +00:00
elif " icheckmovies_list_details " in self . summaries : summary = get_summary ( " icheckmovies_list_details " , self . summaries )
2021-03-02 05:28:32 +00:00
elif " tmdb_actor_details " in self . summaries : summary = get_summary ( " tmdb_actor_details " , self . summaries )
elif " tmdb_crew_details " in self . summaries : summary = get_summary ( " tmdb_crew_details " , self . summaries )
elif " tmdb_director_details " in self . summaries : summary = get_summary ( " tmdb_director_details " , self . summaries )
elif " tmdb_producer_details " in self . summaries : summary = get_summary ( " tmdb_producer_details " , self . summaries )
elif " tmdb_writer_details " in self . summaries : summary = get_summary ( " tmdb_writer_details " , self . summaries )
2021-02-28 23:06:04 +00:00
elif " tmdb_movie_details " in self . summaries : summary = get_summary ( " tmdb_movie_details " , self . summaries )
2021-03-08 17:02:40 +00:00
elif " tvdb_movie_details " in self . summaries : summary = get_summary ( " tvdb_movie_details " , self . summaries )
elif " tvdb_show_details " in self . summaries : summary = get_summary ( " tvdb_show_details " , self . summaries )
2021-02-28 23:06:04 +00:00
elif " tmdb_show_details " in self . summaries : summary = get_summary ( " tmdb_show_details " , self . summaries )
else : summary = None
if summary :
2021-05-12 14:25:48 +00:00
if str ( summary ) != str ( self . obj . summary ) :
2021-12-17 14:24:46 +00:00
if self . playlist :
self . obj . edit ( summary = str ( summary ) )
logger . info ( " Details: have been updated " )
else :
edits [ " summary.value " ] = summary
edits [ " summary.locked " ] = 1
2021-03-01 04:16:08 +00:00
2021-02-20 05:41:45 +00:00
if " sort_title " in self . details :
2021-05-12 14:25:48 +00:00
if str ( self . details [ " sort_title " ] ) != str ( self . obj . titleSort ) :
2021-05-02 04:22:48 +00:00
edits [ " titleSort.value " ] = self . details [ " sort_title " ]
edits [ " titleSort.locked " ] = 1
logger . info ( f " Detail: sort_title updated Collection Sort Title to { self . details [ ' sort_title ' ] } " )
2021-03-01 04:16:08 +00:00
2021-02-20 05:41:45 +00:00
if " content_rating " in self . details :
2021-05-12 14:25:48 +00:00
if str ( self . details [ " content_rating " ] ) != str ( self . obj . contentRating ) :
2021-05-02 04:22:48 +00:00
edits [ " contentRating.value " ] = self . details [ " content_rating " ]
edits [ " contentRating.locked " ] = 1
logger . info ( f " Detail: content_rating updated Collection Content Rating to { self . details [ ' content_rating ' ] } " )
2021-03-01 04:16:08 +00:00
2021-02-20 05:41:45 +00:00
if " collection_mode " in self . details :
2021-05-12 14:25:48 +00:00
if int ( self . obj . collectionMode ) not in plex . collection_mode_keys \
or plex . collection_mode_keys [ int ( self . obj . collectionMode ) ] != self . details [ " collection_mode " ] :
self . library . collection_mode_query ( self . obj , self . details [ " collection_mode " ] )
2021-05-02 04:22:48 +00:00
logger . info ( f " Detail: collection_mode updated Collection Mode to { self . details [ ' collection_mode ' ] } " )
2021-03-01 04:16:08 +00:00
2021-02-20 05:41:45 +00:00
if " collection_order " in self . details :
2021-05-12 14:25:48 +00:00
if int ( self . obj . collectionSort ) not in plex . collection_order_keys \
or plex . collection_order_keys [ int ( self . obj . collectionSort ) ] != self . details [ " collection_order " ] :
self . library . collection_order_query ( self . obj , self . details [ " collection_order " ] )
2021-05-02 04:22:48 +00:00
logger . info ( f " Detail: collection_order updated Collection Order to { self . details [ ' collection_order ' ] } " )
2021-02-20 05:41:45 +00:00
2021-06-30 15:07:02 +00:00
if " visible_library " in self . details or " visible_home " in self . details or " visible_shared " in self . details :
visibility = self . library . collection_visibility ( self . obj )
visible_library = None
visible_home = None
visible_shared = None
if " visible_library " in self . details and self . details [ " visible_library " ] != visibility [ " library " ] :
visible_library = self . details [ " visible_library " ]
if " visible_home " in self . details and self . details [ " visible_home " ] != visibility [ " library " ] :
visible_home = self . details [ " visible_home " ]
if " visible_shared " in self . details and self . details [ " visible_shared " ] != visibility [ " library " ] :
visible_shared = self . details [ " visible_shared " ]
if visible_library is not None or visible_home is not None or visible_shared is not None :
self . library . collection_visibility_update ( self . obj , visibility = visibility , library = visible_library , home = visible_home , shared = visible_shared )
logger . info ( " Detail: Collection visibility updated " )
2021-05-20 19:26:56 +00:00
add_tags = self . details [ " label " ] if " label " in self . details else None
remove_tags = self . details [ " label.remove " ] if " label.remove " in self . details else None
sync_tags = self . details [ " label.sync " ] if " label.sync " in self . details else None
self . library . edit_tags ( " label " , self . obj , add_tags = add_tags , remove_tags = remove_tags , sync_tags = sync_tags )
2021-03-01 04:16:08 +00:00
if len ( edits ) > 0 :
logger . debug ( edits )
2021-05-12 14:25:48 +00:00
self . library . edit_query ( self . obj , edits )
2021-03-01 04:16:08 +00:00
logger . info ( " Details: have been updated " )
2021-02-20 05:41:45 +00:00
if self . library . asset_directory :
name_mapping = self . name
if " name_mapping " in self . details :
2021-02-28 23:06:04 +00:00
if self . details [ " name_mapping " ] : name_mapping = self . details [ " name_mapping " ]
2021-12-13 07:30:19 +00:00
else : logger . error ( f " { self . Type } Error: name_mapping attribute is blank " )
2021-06-22 20:28:12 +00:00
poster_image , background_image = self . library . find_collection_assets ( self . obj , name = name_mapping )
2021-05-19 19:21:22 +00:00
if poster_image :
self . posters [ " asset_directory " ] = poster_image
if background_image :
self . backgrounds [ " asset_directory " ] = background_image
2021-02-21 08:13:07 +00:00
2021-12-13 19:43:36 +00:00
self . collection_poster = None
2021-07-02 04:04:24 +00:00
if len ( self . posters ) > 0 :
logger . debug ( f " { len ( self . posters ) } posters found: " )
2021-02-28 23:06:04 +00:00
for p in self . posters :
2021-07-02 04:04:24 +00:00
logger . debug ( f " Method: { p } Poster: { self . posters [ p ] } " )
2021-02-28 23:06:04 +00:00
2021-12-13 19:43:36 +00:00
if " url_poster " in self . posters : self . collection_poster = ImageData ( " url_poster " , self . posters [ " url_poster " ] )
elif " file_poster " in self . posters : self . collection_poster = ImageData ( " file_poster " , self . posters [ " file_poster " ] , is_url = False )
elif " tmdb_poster " in self . posters : self . collection_poster = ImageData ( " tmdb_poster " , self . posters [ " tmdb_poster " ] )
elif " tmdb_profile " in self . posters : self . collection_poster = ImageData ( " tmdb_poster " , self . posters [ " tmdb_profile " ] )
elif " tvdb_poster " in self . posters : self . collection_poster = ImageData ( " tvdb_poster " , self . posters [ " tvdb_poster " ] )
elif " asset_directory " in self . posters : self . collection_poster = self . posters [ " asset_directory " ]
elif " tmdb_person " in self . posters : self . collection_poster = ImageData ( " tmdb_person " , self . posters [ " tmdb_person " ] )
elif " tmdb_collection_details " in self . posters : self . collection_poster = ImageData ( " tmdb_collection_details " , self . posters [ " tmdb_collection_details " ] )
elif " tmdb_actor_details " in self . posters : self . collection_poster = ImageData ( " tmdb_actor_details " , self . posters [ " tmdb_actor_details " ] )
elif " tmdb_crew_details " in self . posters : self . collection_poster = ImageData ( " tmdb_crew_details " , self . posters [ " tmdb_crew_details " ] )
elif " tmdb_director_details " in self . posters : self . collection_poster = ImageData ( " tmdb_director_details " , self . posters [ " tmdb_director_details " ] )
elif " tmdb_producer_details " in self . posters : self . collection_poster = ImageData ( " tmdb_producer_details " , self . posters [ " tmdb_producer_details " ] )
elif " tmdb_writer_details " in self . posters : self . collection_poster = ImageData ( " tmdb_writer_details " , self . posters [ " tmdb_writer_details " ] )
elif " tmdb_movie_details " in self . posters : self . collection_poster = ImageData ( " tmdb_movie_details " , self . posters [ " tmdb_movie_details " ] )
elif " tvdb_movie_details " in self . posters : self . collection_poster = ImageData ( " tvdb_movie_details " , self . posters [ " tvdb_movie_details " ] )
elif " tvdb_show_details " in self . posters : self . collection_poster = ImageData ( " tvdb_show_details " , self . posters [ " tvdb_show_details " ] )
elif " tmdb_show_details " in self . posters : self . collection_poster = ImageData ( " tmdb_show_details " , self . posters [ " tmdb_show_details " ] )
2021-07-01 18:21:14 +00:00
else :
2021-12-17 14:24:46 +00:00
logger . info ( f " No poster { self . type } detail or asset folder found " )
2021-07-01 18:21:14 +00:00
2021-12-13 19:43:36 +00:00
self . collection_background = None
2021-07-02 04:04:24 +00:00
if len ( self . backgrounds ) > 0 :
logger . debug ( f " { len ( self . backgrounds ) } backgrounds found: " )
2021-02-28 23:06:04 +00:00
for b in self . backgrounds :
2021-07-02 04:04:24 +00:00
logger . debug ( f " Method: { b } Background: { self . backgrounds [ b ] } " )
2021-02-28 23:06:04 +00:00
2021-12-13 19:43:36 +00:00
if " url_background " in self . backgrounds : self . collection_background = ImageData ( " url_background " , self . backgrounds [ " url_background " ] , is_poster = False )
elif " file_background " in self . backgrounds : self . collection_background = ImageData ( " file_background " , self . backgrounds [ " file_background " ] , is_poster = False , is_url = False )
elif " tmdb_background " in self . backgrounds : self . collection_background = ImageData ( " tmdb_background " , self . backgrounds [ " tmdb_background " ] , is_poster = False )
elif " tvdb_background " in self . backgrounds : self . collection_background = ImageData ( " tvdb_background " , self . backgrounds [ " tvdb_background " ] , is_poster = False )
elif " asset_directory " in self . backgrounds : self . collection_background = self . backgrounds [ " asset_directory " ]
elif " tmdb_collection_details " in self . backgrounds : self . collection_background = ImageData ( " tmdb_collection_details " , self . backgrounds [ " tmdb_collection_details " ] , is_poster = False )
elif " tmdb_movie_details " in self . backgrounds : self . collection_background = ImageData ( " tmdb_movie_details " , self . backgrounds [ " tmdb_movie_details " ] , is_poster = False )
elif " tvdb_movie_details " in self . backgrounds : self . collection_background = ImageData ( " tvdb_movie_details " , self . backgrounds [ " tvdb_movie_details " ] , is_poster = False )
elif " tvdb_show_details " in self . backgrounds : self . collection_background = ImageData ( " tvdb_show_details " , self . backgrounds [ " tvdb_show_details " ] , is_poster = False )
elif " tmdb_show_details " in self . backgrounds : self . collection_background = ImageData ( " tmdb_show_details " , self . backgrounds [ " tmdb_show_details " ] , is_poster = False )
2021-07-01 18:21:14 +00:00
else :
2021-12-17 14:24:46 +00:00
logger . info ( f " No background { self . type } detail or asset folder found " )
2021-03-01 20:59:10 +00:00
2021-12-13 19:43:36 +00:00
if self . collection_poster or self . collection_background :
self . library . upload_images ( self . obj , poster = self . collection_poster , background = self . collection_background )
2021-06-12 15:29:17 +00:00
2021-07-29 13:36:30 +00:00
def sort_collection ( self ) :
2021-09-15 03:16:59 +00:00
logger . info ( " " )
2021-12-17 14:24:46 +00:00
util . separator ( f " Sorting { self . name } { self . Type } " , space = False , border = False )
2021-09-15 03:16:59 +00:00
logger . info ( " " )
2021-12-13 22:51:31 +00:00
if self . sort_by :
search_data = self . build_filter ( " plex_search " , { " sort_by " : self . sort_by , " any " : { " collection " : self . name } } )
2021-12-17 14:24:46 +00:00
items = self . library . get_filter_items ( search_data [ 2 ] )
2021-12-13 22:51:31 +00:00
else :
2021-12-17 14:24:46 +00:00
items = self . added_items
2021-07-29 13:36:30 +00:00
previous = None
2021-12-17 14:24:46 +00:00
for item in items :
text = f " after { util . item_title ( previous ) } " if previous else " to the beginning "
logger . info ( f " Moving { util . item_title ( item ) } { text } " )
self . library . moveItem ( self . obj , item , previous )
previous = item
def send_notifications ( self , playlist = False ) :
2021-12-07 06:29:41 +00:00
if self . obj and self . details [ " collection_changes_webhooks " ] and \
( self . created or len ( self . notification_additions ) > 0 or len ( self . notification_removals ) > 0 ) :
2021-10-04 17:51:32 +00:00
self . obj . reload ( )
2021-11-28 07:14:35 +00:00
try :
self . library . Webhooks . collection_hooks (
2021-12-07 06:29:41 +00:00
self . details [ " collection_changes_webhooks " ] ,
2021-11-28 07:14:35 +00:00
self . obj ,
2021-12-17 23:18:34 +00:00
poster_url = self . collection_poster . location if self . collection_poster and self . collection_poster . is_url else None ,
background_url = self . collection_background . location if self . collection_background and self . collection_background . is_url else None ,
2021-11-28 07:14:35 +00:00
created = self . created ,
2021-12-09 04:57:00 +00:00
deleted = self . deleted ,
2021-11-28 07:14:35 +00:00
additions = self . notification_additions ,
2021-12-17 14:24:46 +00:00
removals = self . notification_removals ,
playlist = playlist
2021-11-28 07:14:35 +00:00
)
except Failed as e :
util . print_stacktrace ( )
logger . error ( f " Webhooks Error: { e } " )
2021-10-04 17:51:32 +00:00
2021-05-26 14:45:33 +00:00
def run_collections_again ( self ) :
2021-05-12 14:25:48 +00:00
self . obj = self . library . get_collection ( self . name )
name , collection_items = self . library . get_collection_name_and_items ( self . obj , self . smart_label_collection )
2021-10-04 17:51:32 +00:00
self . created = False
2021-04-22 03:13:40 +00:00
rating_keys = [ ]
2021-11-03 14:36:11 +00:00
self . notification_additions = [ ]
2021-05-14 19:22:59 +00:00
for mm in self . run_again_movies :
2021-05-26 14:45:33 +00:00
if mm in self . library . movie_map :
rating_keys . extend ( self . library . movie_map [ mm ] )
2021-03-05 16:04:28 +00:00
if self . library . is_show :
2021-05-14 19:22:59 +00:00
for sm in self . run_again_shows :
2021-05-26 14:45:33 +00:00
if sm in self . library . show_map :
rating_keys . extend ( self . library . show_map [ sm ] )
2021-03-01 20:59:10 +00:00
if len ( rating_keys ) > 0 :
for rating_key in rating_keys :
try :
2021-03-05 16:04:28 +00:00
current = self . library . fetchItem ( int ( rating_key ) )
2021-03-01 20:59:10 +00:00
except ( BadRequest , NotFound ) :
logger . error ( f " Plex Error: Item { rating_key } not found " )
continue
if current in collection_items :
2021-12-17 14:24:46 +00:00
logger . info ( f " { name } { self . Type } | = | { util . item_title ( current ) } " )
2021-03-01 20:59:10 +00:00
else :
2021-09-30 20:55:29 +00:00
self . library . alter_collection ( current , name , smart_label_collection = self . smart_label_collection )
2021-12-17 14:24:46 +00:00
logger . info ( f " { name } { self . Type } | + | { util . item_title ( current ) } " )
2021-10-04 17:51:32 +00:00
if self . library . is_movie and current . ratingKey in self . library . movie_rating_key_map :
add_id = self . library . movie_rating_key_map [ current . ratingKey ]
elif self . library . is_show and current . ratingKey in self . library . show_rating_key_map :
add_id = self . library . show_rating_key_map [ current . ratingKey ]
else :
add_id = None
2021-12-17 23:18:34 +00:00
self . notification_additions . append ( util . item_set ( current , add_id ) )
2021-10-04 17:51:32 +00:00
self . send_notifications ( )
2021-08-22 15:54:33 +00:00
logger . info ( f " { len ( rating_keys ) } { self . collection_level . capitalize ( ) } { ' s ' if len ( rating_keys ) > 1 else ' ' } Processed " )
2021-03-01 20:59:10 +00:00
2021-05-14 19:22:59 +00:00
if len ( self . run_again_movies ) > 0 :
2021-03-01 20:59:10 +00:00
logger . info ( " " )
2021-05-14 19:22:59 +00:00
for missing_id in self . run_again_movies :
2021-05-26 14:45:33 +00:00
if missing_id not in self . library . movie_map :
2021-03-01 20:59:10 +00:00
try :
movie = self . config . TMDb . get_movie ( missing_id )
except Failed as e :
logger . error ( e )
continue
if self . details [ " show_missing " ] is True :
2021-07-21 19:25:29 +00:00
current_title = f " { movie . title } ( { util . validate_date ( movie . release_date , ' test ' ) . year } ) " if movie . release_date else movie . title
2021-12-17 14:24:46 +00:00
logger . info ( f " { name } { self . Type } | ? | { current_title } (TMDb: { missing_id } ) " )
2021-03-01 20:59:10 +00:00
logger . info ( " " )
2021-05-14 19:22:59 +00:00
logger . info ( f " { len ( self . run_again_movies ) } Movie { ' s ' if len ( self . run_again_movies ) > 1 else ' ' } Missing " )
2021-03-01 20:59:10 +00:00
2021-05-14 19:22:59 +00:00
if len ( self . run_again_shows ) > 0 and self . library . is_show :
2021-03-01 20:59:10 +00:00
logger . info ( " " )
2021-05-14 19:22:59 +00:00
for missing_id in self . run_again_shows :
2021-05-26 14:45:33 +00:00
if missing_id not in self . library . show_map :
2021-03-01 20:59:10 +00:00
try :
2021-10-26 15:01:08 +00:00
title = self . config . TVDb . get_series ( missing_id ) . title
2021-03-01 20:59:10 +00:00
except Failed as e :
logger . error ( e )
continue
if self . details [ " show_missing " ] is True :
2021-12-17 14:24:46 +00:00
logger . info ( f " { name } { self . Type } | ? | { title } (TVDb: { missing_id } ) " )
2021-05-14 19:22:59 +00:00
logger . info ( f " { len ( self . run_again_shows ) } Show { ' s ' if len ( self . run_again_shows ) > 1 else ' ' } Missing " )