@ -721,7 +721,8 @@ class CollectionBuilder:
self . summaries [ method_name ] = config . Letterboxd . get_list_description ( values [ 0 ] , self . library . Plex . language )
self . methods . append ( ( method_name [ : - 8 ] , values ) )
elif method_name in dictionary_builders :
if isinstance ( method_data , dict ) :
for dict_data in util . get_list ( method_data ) :
if isinstance ( dict_data , dict ) :
def get_int ( parent , int_method , data_in , methods_in , default_in , minimum = 1 , maximum = None ) :
if int_method not in methods_in :
logger . warning ( f " Collection Warning: { parent } { int_method } attribute not found using { default_in } as default " )
@ -737,13 +738,13 @@ class CollectionBuilder:
return default_in
if method_name == " filters " :
validate = True
if " validate " in metho d_data:
if metho d_data[ " validate " ] is None :
if " validate " in dict _data:
if dict _data[ " validate " ] is None :
raise Failed ( " Collection Error: validate filter attribute is blank " )
if not isinstance ( metho d_data[ " validate " ] , bool ) :
if not isinstance ( dict _data[ " validate " ] , bool ) :
raise Failed ( " Collection Error: validate filter attribute must be either true or false " )
validate = metho d_data[ " validate " ]
for filter_method , filter_data in metho d_data. items ( ) :
validate = dict _data[ " validate " ]
for filter_method , filter_data in dict _data. items ( ) :
filter_attr , modifier , filter_final = self . _split ( filter_method )
if filter_final not in all_filters :
raise Failed ( f " Collection Error: { filter_final } is not a valid filter attribute " )
@ -757,19 +758,19 @@ class CollectionBuilder:
self . filters . append ( ( filter_final , self . validate_attribute ( filter_attr , modifier , f " { filter_final } filter " , filter_data , validate ) ) )
elif method_name == " plex_collectionless " :
new_dictionary = { }
dict_methods = { dm . lower ( ) : dm for dm in metho d_data}
dict_methods = { dm . lower ( ) : dm for dm in dict _data}
prefix_list = [ ]
if " exclude_prefix " in dict_methods and metho d_data[ dict_methods [ " exclude_prefix " ] ] :
if isinstance ( metho d_data[ dict_methods [ " exclude_prefix " ] ] , list ) :
prefix_list . extend ( [ exclude for exclude in metho d_data[ dict_methods [ " exclude_prefix " ] ] if exclude ] )
if " exclude_prefix " in dict_methods and dict _data[ dict_methods [ " exclude_prefix " ] ] :
if isinstance ( dict _data[ dict_methods [ " exclude_prefix " ] ] , list ) :
prefix_list . extend ( [ exclude for exclude in dict _data[ dict_methods [ " exclude_prefix " ] ] if exclude ] )
else :
prefix_list . append ( str ( metho d_data[ dict_methods [ " exclude_prefix " ] ] ) )
prefix_list . append ( str ( dict _data[ dict_methods [ " exclude_prefix " ] ] ) )
exact_list = [ ]
if " exclude " in dict_methods and metho d_data[ dict_methods [ " exclude " ] ] :
if isinstance ( metho d_data[ dict_methods [ " exclude " ] ] , list ) :
exact_list . extend ( [ exclude for exclude in metho d_data[ dict_methods [ " exclude " ] ] if exclude ] )
if " exclude " in dict_methods and dict _data[ dict_methods [ " exclude " ] ] :
if isinstance ( dict _data[ dict_methods [ " exclude " ] ] , list ) :
exact_list . extend ( [ exclude for exclude in dict _data[ dict_methods [ " exclude " ] ] if exclude ] )
else :
exact_list . append ( str ( metho d_data[ dict_methods [ " exclude " ] ] ) )
exact_list . append ( str ( dict _data[ dict_methods [ " exclude " ] ] ) )
if len ( prefix_list ) == 0 and len ( exact_list ) == 0 :
raise Failed ( " Collection Error: you must have at least one exclusion " )
exact_list . append ( self . name )
@ -777,10 +778,10 @@ class CollectionBuilder:
new_dictionary [ " exclude " ] = exact_list
self . methods . append ( ( method_name , [ new_dictionary ] ) )
elif method_name == " plex_search " :
self . methods . append ( ( method_name , [ self . build_filter ( " plex_search " , metho d_data) ] ) )
self . methods . append ( ( method_name , [ self . build_filter ( " plex_search " , dict _data) ] ) )
elif method_name == " tmdb_discover " :
new_dictionary = { " limit " : 100 }
for discover_name , discover_data in metho d_data. items ( ) :
for discover_name , discover_data in dict _data. items ( ) :
discover_final = discover_name . lower ( )
if discover_data :
if ( self . library . is_movie and discover_final in tmdb . discover_movie ) or ( self . library . is_show and discover_final in tmdb . discover_tv ) :
@ -800,12 +801,12 @@ class CollectionBuilder:
else :
raise Failed ( f " Collection Error: { method_name } attribute { discover_final } : { discover_data } is invalid " )
elif discover_final == " certification_country " :
if " certification " in metho d_data or " certification.lte " in metho d_data or " certification.gte " in metho d_data:
if " certification " in dict _data or " certification.lte " in dict _data or " certification.gte " in dict _data:
new_dictionary [ discover_final ] = discover_data
else :
raise Failed ( f " Collection Error: { method_name } attribute { discover_final } : must be used with either certification, certification.lte, or certification.gte " )
elif discover_final in [ " certification " , " certification.lte " , " certification.gte " ] :
if " certification_country " in metho d_data:
if " certification_country " in dict _data:
new_dictionary [ discover_final ] = discover_data
else :
raise Failed ( f " Collection Error: { method_name } attribute { discover_final } : must be used with certification_country " )
@ -843,22 +844,22 @@ class CollectionBuilder:
new_dictionary [ " list_type " ] = " watched "
else :
raise Failed ( f " Collection Error: { method_name } attribute not supported " )
dict_methods = { dm . lower ( ) : dm for dm in metho d_data}
new_dictionary [ " list_days " ] = get_int ( method_name , " list_days " , metho d_data, dict_methods , 30 )
new_dictionary [ " list_size " ] = get_int ( method_name , " list_size " , metho d_data, dict_methods , 10 )
new_dictionary [ " list_buffer " ] = get_int ( method_name , " list_buffer " , metho d_data, dict_methods , 20 )
dict_methods = { dm . lower ( ) : dm for dm in dict _data}
new_dictionary [ " list_days " ] = get_int ( method_name , " list_days " , dict _data, dict_methods , 30 )
new_dictionary [ " list_size " ] = get_int ( method_name , " list_size " , dict _data, dict_methods , 10 )
new_dictionary [ " list_buffer " ] = get_int ( method_name , " list_buffer " , dict _data, dict_methods , 20 )
self . methods . append ( ( method_name , [ new_dictionary ] ) )
elif method_name == " mal_season " :
new_dictionary = { " sort_by " : " anime_num_list_users " }
dict_methods = { dm . lower ( ) : dm for dm in metho d_data}
dict_methods = { dm . lower ( ) : dm for dm in dict _data}
if " sort_by " not in dict_methods :
logger . warning ( " Collection Warning: mal_season sort_by attribute not found using members as default " )
elif not metho d_data[ dict_methods [ " sort_by " ] ] :
elif not dict _data[ dict_methods [ " sort_by " ] ] :
logger . warning ( " Collection Warning: mal_season sort_by attribute is blank using members as default " )
elif metho d_data[ dict_methods [ " sort_by " ] ] not in mal . season_sort :
logger . warning ( f " Collection Warning: mal_season sort_by attribute { metho d_data[ dict_methods [ ' sort_by ' ] ] } invalid must be either ' members ' or ' score ' using members as default " )
elif dict _data[ dict_methods [ " sort_by " ] ] not in mal . season_sort :
logger . warning ( f " Collection Warning: mal_season sort_by attribute { dict _data[ dict_methods [ ' sort_by ' ] ] } invalid must be either ' members ' or ' score ' using members as default " )
else :
new_dictionary [ " sort_by " ] = mal . season_sort [ metho d_data[ dict_methods [ " sort_by " ] ] ]
new_dictionary [ " sort_by " ] = mal . season_sort [ dict _data[ dict_methods [ " sort_by " ] ] ]
if self . current_time . month in [ 1 , 2 , 3 ] : new_dictionary [ " season " ] = " winter "
elif self . current_time . month in [ 4 , 5 , 6 ] : new_dictionary [ " season " ] = " spring "
@ -867,49 +868,49 @@ class CollectionBuilder:
if " season " not in dict_methods :
logger . warning ( f " Collection Warning: mal_season season attribute not found using the current season: { new_dictionary [ ' season ' ] } as default " )
elif not metho d_data[ dict_methods [ " season " ] ] :
elif not dict _data[ dict_methods [ " season " ] ] :
logger . warning ( f " Collection Warning: mal_season season attribute is blank using the current season: { new_dictionary [ ' season ' ] } as default " )
elif metho d_data[ dict_methods [ " season " ] ] not in util . pretty_seasons :
logger . warning ( f " Collection Warning: mal_season season attribute { metho d_data[ dict_methods [ ' season ' ] ] } invalid must be either ' winter ' , ' spring ' , ' summer ' or ' fall ' using the current season: { new_dictionary [ ' season ' ] } as default " )
elif dict _data[ dict_methods [ " season " ] ] not in util . pretty_seasons :
logger . warning ( f " Collection Warning: mal_season season attribute { dict _data[ dict_methods [ ' season ' ] ] } invalid must be either ' winter ' , ' spring ' , ' summer ' or ' fall ' using the current season: { new_dictionary [ ' season ' ] } as default " )
else :
new_dictionary [ " season " ] = metho d_data[ dict_methods [ " season " ] ]
new_dictionary [ " season " ] = dict _data[ dict_methods [ " season " ] ]
new_dictionary [ " year " ] = get_int ( method_name , " year " , metho d_data, dict_methods , self . current_time . year , minimum = 1917 , maximum = self . current_time . year + 1 )
new_dictionary [ " limit " ] = get_int ( method_name , " limit " , metho d_data, dict_methods , 100 , maximum = 500 )
new_dictionary [ " year " ] = get_int ( method_name , " year " , dict _data, dict_methods , self . current_time . year , minimum = 1917 , maximum = self . current_time . year + 1 )
new_dictionary [ " limit " ] = get_int ( method_name , " limit " , dict _data, dict_methods , 100 , maximum = 500 )
self . methods . append ( ( method_name , [ new_dictionary ] ) )
elif method_name == " mal_userlist " :
new_dictionary = { " status " : " all " , " sort_by " : " list_score " }
dict_methods = { dm . lower ( ) : dm for dm in metho d_data}
dict_methods = { dm . lower ( ) : dm for dm in dict _data}
if " username " not in dict_methods :
raise Failed ( " Collection Error: mal_userlist username attribute is required " )
elif not metho d_data[ dict_methods [ " username " ] ] :
elif not dict _data[ dict_methods [ " username " ] ] :
raise Failed ( " Collection Error: mal_userlist username attribute is blank " )
else :
new_dictionary [ " username " ] = metho d_data[ dict_methods [ " username " ] ]
new_dictionary [ " username " ] = dict _data[ dict_methods [ " username " ] ]
if " status " not in dict_methods :
logger . warning ( " Collection Warning: mal_season status attribute not found using all as default " )
elif not metho d_data[ dict_methods [ " status " ] ] :
elif not dict _data[ dict_methods [ " status " ] ] :
logger . warning ( " Collection Warning: mal_season status attribute is blank using all as default " )
elif metho d_data[ dict_methods [ " status " ] ] not in mal . userlist_status :
logger . warning ( f " Collection Warning: mal_season status attribute { metho d_data[ dict_methods [ ' status ' ] ] } invalid must be either ' all ' , ' watching ' , ' completed ' , ' on_hold ' , ' dropped ' or ' plan_to_watch ' using all as default " )
elif dict _data[ dict_methods [ " status " ] ] not in mal . userlist_status :
logger . warning ( f " Collection Warning: mal_season status attribute { dict _data[ dict_methods [ ' status ' ] ] } invalid must be either ' all ' , ' watching ' , ' completed ' , ' on_hold ' , ' dropped ' or ' plan_to_watch ' using all as default " )
else :
new_dictionary [ " status " ] = mal . userlist_status [ metho d_data[ dict_methods [ " status " ] ] ]
new_dictionary [ " status " ] = mal . userlist_status [ dict _data[ dict_methods [ " status " ] ] ]
if " sort_by " not in dict_methods :
logger . warning ( " Collection Warning: mal_season sort_by attribute not found using score as default " )
elif not metho d_data[ dict_methods [ " sort_by " ] ] :
elif not dict _data[ dict_methods [ " sort_by " ] ] :
logger . warning ( " Collection Warning: mal_season sort_by attribute is blank using score as default " )
elif metho d_data[ dict_methods [ " sort_by " ] ] not in mal . userlist_sort :
logger . warning ( f " Collection Warning: mal_season sort_by attribute { metho d_data[ dict_methods [ ' sort_by ' ] ] } invalid must be either ' score ' , ' last_updated ' , ' title ' or ' start_date ' using score as default " )
elif dict _data[ dict_methods [ " sort_by " ] ] not in mal . userlist_sort :
logger . warning ( f " Collection Warning: mal_season sort_by attribute { dict _data[ dict_methods [ ' sort_by ' ] ] } invalid must be either ' score ' , ' last_updated ' , ' title ' or ' start_date ' using score as default " )
else :
new_dictionary [ " sort_by " ] = mal . userlist_sort [ metho d_data[ dict_methods [ " sort_by " ] ] ]
new_dictionary [ " sort_by " ] = mal . userlist_sort [ dict _data[ dict_methods [ " sort_by " ] ] ]
new_dictionary [ " limit " ] = get_int ( method_name , " limit " , metho d_data, dict_methods , 100 , maximum = 1000 )
new_dictionary [ " limit " ] = get_int ( method_name , " limit " , dict _data, dict_methods , 100 , maximum = 1000 )
self . methods . append ( ( method_name , [ new_dictionary ] ) )
elif " anilist " in method_name :
new_dictionary = { " sort_by " : " score " }
dict_methods = { dm . lower ( ) : dm for dm in metho d_data}
dict_methods = { dm . lower ( ) : dm for dm in dict _data}
if method_name == " anilist_season " :
if self . current_time . month in [ 12 , 1 , 2 ] : new_dictionary [ " season " ] = " winter "
elif self . current_time . month in [ 3 , 4 , 5 ] : new_dictionary [ " season " ] = " spring "
@ -918,43 +919,43 @@ class CollectionBuilder:
if " season " not in dict_methods :
logger . warning ( f " Collection Warning: anilist_season season attribute not found using the current season: { new_dictionary [ ' season ' ] } as default " )
elif not metho d_data[ dict_methods [ " season " ] ] :
elif not dict _data[ dict_methods [ " season " ] ] :
logger . warning ( f " Collection Warning: anilist_season season attribute is blank using the current season: { new_dictionary [ ' season ' ] } as default " )
elif metho d_data[ dict_methods [ " season " ] ] not in util . pretty_seasons :
logger . warning ( f " Collection Warning: anilist_season season attribute { metho d_data[ dict_methods [ ' season ' ] ] } invalid must be either ' winter ' , ' spring ' , ' summer ' or ' fall ' using the current season: { new_dictionary [ ' season ' ] } as default " )
elif dict _data[ dict_methods [ " season " ] ] not in util . pretty_seasons :
logger . warning ( f " Collection Warning: anilist_season season attribute { dict _data[ dict_methods [ ' season ' ] ] } invalid must be either ' winter ' , ' spring ' , ' summer ' or ' fall ' using the current season: { new_dictionary [ ' season ' ] } as default " )
else :
new_dictionary [ " season " ] = metho d_data[ dict_methods [ " season " ] ]
new_dictionary [ " season " ] = dict _data[ dict_methods [ " season " ] ]
new_dictionary [ " year " ] = get_int ( method_name , " year " , metho d_data, dict_methods , self . current_time . year , minimum = 1917 , maximum = self . current_time . year + 1 )
new_dictionary [ " year " ] = get_int ( method_name , " year " , dict _data, dict_methods , self . current_time . year , minimum = 1917 , maximum = self . current_time . year + 1 )
elif method_name == " anilist_genre " :
if " genre " not in dict_methods :
raise Failed ( f " Collection Warning: anilist_genre genre attribute not found " )
elif not metho d_data[ dict_methods [ " genre " ] ] :
elif not dict _data[ dict_methods [ " genre " ] ] :
raise Failed ( f " Collection Warning: anilist_genre genre attribute is blank " )
else :
new_dictionary [ " genre " ] = self . config . AniList . validate_genre ( metho d_data[ dict_methods [ " genre " ] ] )
new_dictionary [ " genre " ] = self . config . AniList . validate_genre ( dict _data[ dict_methods [ " genre " ] ] )
elif method_name == " anilist_tag " :
if " tag " not in dict_methods :
raise Failed ( f " Collection Warning: anilist_tag tag attribute not found " )
elif not metho d_data[ dict_methods [ " tag " ] ] :
elif not dict _data[ dict_methods [ " tag " ] ] :
raise Failed ( f " Collection Warning: anilist_tag tag attribute is blank " )
else :
new_dictionary [ " tag " ] = self . config . AniList . validate_tag ( metho d_data[ dict_methods [ " tag " ] ] )
new_dictionary [ " tag " ] = self . config . AniList . validate_tag ( dict _data[ dict_methods [ " tag " ] ] )
if " sort_by " not in dict_methods :
logger . warning ( f " Collection Warning: { method_name } sort_by attribute not found using score as default " )
elif not metho d_data[ dict_methods [ " sort_by " ] ] :
elif not dict _data[ dict_methods [ " sort_by " ] ] :
logger . warning ( f " Collection Warning: { method_name } sort_by attribute is blank using score as default " )
elif str ( metho d_data[ dict_methods [ " sort_by " ] ] ) . lower ( ) not in [ " score " , " popular " ] :
logger . warning ( f " Collection Warning: { method_name } sort_by attribute { metho d_data[ dict_methods [ ' sort_by ' ] ] } invalid must be either ' score ' or ' popular ' using score as default " )
elif str ( dict _data[ dict_methods [ " sort_by " ] ] ) . lower ( ) not in [ " score " , " popular " ] :
logger . warning ( f " Collection Warning: { method_name } sort_by attribute { dict _data[ dict_methods [ ' sort_by ' ] ] } invalid must be either ' score ' or ' popular ' using score as default " )
else :
new_dictionary [ " sort_by " ] = metho d_data[ dict_methods [ " sort_by " ] ]
new_dictionary [ " sort_by " ] = dict _data[ dict_methods [ " sort_by " ] ]
new_dictionary [ " limit " ] = get_int ( method_name , " limit " , metho d_data, dict_methods , 0 , maximum = 500 )
new_dictionary [ " limit " ] = get_int ( method_name , " limit " , dict _data, dict_methods , 0 , maximum = 500 )
self . methods . append ( ( method_name , [ new_dictionary ] ) )
else :
raise Failed ( f " Collection Error: { method_name } attribute is not a dictionary: { metho d_data} " )
raise Failed ( f " Collection Error: { method_name } attribute is not a dictionary: { dict _data} " )
elif method_name in numbered_builders :
list_count = util . regex_first_int ( method_data , " List Size " , default = 10 )
if list_count < 1 :