[76] Or Filters

This commit is contained in:
meisnate12 2022-10-03 15:32:50 -04:00
parent bef04781cd
commit 93797ff4df
18 changed files with 159 additions and 189 deletions

View file

@ -1 +1 @@
1.17.3-develop75
1.17.3-develop76

View file

@ -111,7 +111,7 @@ dynamic_collections:
- TV-Y
- E
- gb/E
- 01
- "01"
2:
- gb/U
- gb/0+
@ -119,7 +119,7 @@ dynamic_collections:
- TV-Y
- E
- gb/E
- 02
- "02"
3:
- gb/U
- gb/0+
@ -128,38 +128,38 @@ dynamic_collections:
- E
- gb/E
- TV-G
- 03
- "03"
4:
- TV-G
- G
- 04
- "04"
5:
- TV-G
- G
- 05
- "05"
6:
- gb/PG
- TV-PG
- 06
- "06"
7:
- gb/PG
- TV-PG
- TV-Y7
- TV-Y7-FV
- 07
- "07"
8:
- gb/PG
- TV-PG
- TV-Y7
- TV-Y7-FV
- 08
- "08"
9:
- gb/PG
- TV-PG
- TV-Y7
- TV-Y7-FV
- gb/9+
- 09
- "09"
10:
- gb/PG
- TV-PG
@ -174,17 +174,15 @@ dynamic_collections:
- gb/9+
12:
- gb/12
- 12
- gb/12A
- 12+
- 12
- "12"
13:
- gb/12
- 12
- gb/12A
- 12+
- PG-13
- 12
- "13"
14:
- gb/12
- 12
@ -192,7 +190,7 @@ dynamic_collections:
- 12+
- PG-13
- TV-14
- 12
- "14"
15:
- gb/15
- gb/14+

View file

@ -128,7 +128,7 @@ dynamic_collections:
valentine: range(02/01-02/29)
patrick: range(03/01-03/18)
easter: range(03/20-04/30)
mother: range(05/05-05-10)
mother: range(05/05-05/10)
memorial: range(5/18-6/7)
father: range(06/15-06/20)
independence: range(06/23-07/11)

View file

@ -70,8 +70,6 @@ templates:
optional:
- overlay_level
- use_<<slug>>
- filepath
- audio
default:
overlay: <<overlay_name>>
horizontal_offset: 0
@ -94,7 +92,7 @@ templates:
ignore_blank_results: true
overlay:
name: <<overlay_name>>
pmm: audio_codec/<<style>>/<<overlay>>
pmm: audio_codec/<<style>>/<<slug>>
group: audio_codec
weight: <<weight>>
horizontal_offset: <<horizontal_offset>>
@ -107,92 +105,55 @@ templates:
back_height: <<height>>
plex_all: true
filters:
audio_track_title.regex: <<audio>>
filepath.regex: <<filepath>>
- audio_track_title.regex: <<regex>>
- filepath.regex: <<regex>>
overlays:
Opus:
template: {name: AudioCodec, weight: 250, slug: opus, audio: '(?i)\bOPUS(\b|\d)'}
Opus-Filepath:
template: {name: AudioCodec, weight: 250, slug: opus, filepath: '(?i)\bOPUS(\b|\d)'}
template: {name: AudioCodec, weight: 250, slug: opus, regex: '(?i)\bOPUS(\b|\d)'}
MP3:
template: {name: AudioCodec, weight: 500, slug: mp3, audio: '(?i)\bmp3(\b|\d)'}
MP3-Filepath:
template: {name: AudioCodec, weight: 500, slug: mp3, filepath: '(?i)\bmp3(\b|\d)'}
AAC2.0:
template: {name: AudioCodec, overlay: AAC, weight: 700, slug: aac, audio: '(?i)(?=.*(\baac[ .]?stereo\b))|(?=.*(\baac[ .]2[ .]0\b))'}
AAC2.0-Filepath:
template: {name: AudioCodec, overlay: AAC, weight: 700, slug: aac, filepath: '(?i)(?=.*(\baac[ .]?stereo\b))|(?=.*(\baac[ .]2[ .]0\b))'}
Dolby-Digital:
template: {name: AudioCodec, weight: 750, slug: digital, audio: '(?i)\bDD[^a-z+]|(?<!e)ac3'}
Dolby-Digital-Filepath:
template: {name: AudioCodec, weight: 750, slug: digital, filepath: '(?i)\bDD[^a-z+]|(?<!e)ac3'}
template: {name: AudioCodec, weight: 500, slug: mp3, regex: '(?i)\bmp3(\b|\d)'}
AAC:
template: {name: AudioCodec, weight: 1000, slug: aac, audio: '(?i)^(?!.*(stereo|2[ .]0))(?=.*\b(aac(\b|\d))).*'}
AAC-Filepath:
template: {name: AudioCodec, weight: 1000, slug: aac, filepath: '(?i)^(?!.*(stereo|2[ .]0))(?=.*\b(aac(\b|\d))).*'}
template: {name: AudioCodec, weight: 700, slug: aac, regex: '(?i)\b(aac|stereo|2[ .]0)\b'}
Dolby-Digital:
template: {name: AudioCodec, weight: 750, slug: digital, regex: '(?i)\bDD[^a-z+]|(?<!e)ac3'}
DTS:
template: {name: AudioCodec, weight: 1250, slug: dts, audio: '(?i)\bDTS(\b|\d)'}
DTS-Filepath:
template: {name: AudioCodec, weight: 1250, slug: dts, filepath: '(?i)\bDTS(\b|\d)'}
template: {name: AudioCodec, weight: 1250, slug: dts, regex: '(?i)\bDTS(\b|\d)'}
DTS-ES:
template: {name: AudioCodec, weight: 1500, slug: es, audio: 'dts[-. ]?es\b'}
DTS-ES-Filepath:
template: {name: AudioCodec, weight: 1500, slug: es, filepath: 'dts[-. ]?es\b'}
template: {name: AudioCodec, weight: 1500, slug: dtses, regex: '(?i)dts[-. ]?es\b'}
Dolby-Digital-Plus:
template: {name: AudioCodec, weight: 1750, slug: plus, audio: '(?i)^(?!.*(atmos))(?=.*\b([^-]DD[P+](?!A)|eac3)\b).*'}
Dolby-Digital-Plus-Filepath:
template: {name: AudioCodec, weight: 1750, slug: plus, filepath: '(?i)^(?!.*(atmos))(?=.*\b([^-]DD[P+](?!A)|eac3)\b).*'}
template: {name: AudioCodec, weight: 1750, slug: plus, regex: '(?i)(?!.*(atmos))(?=.*\b([^-]DD[P+](?!A)|eac3)\b).*'}
DTS-HD-HRA:
template: {name: AudioCodec, weight: 2000, slug: hra, audio: '(?i)dts[ ._-]?(hd[. ]?)?(hr|hi)'}
DTS-HD-HRA-Filepath:
template: {name: AudioCodec, weight: 2000, slug: hra, filepath: '(?i)dts[ ._-]?(hd[. ]?)?(hr|hi)'}
template: {name: AudioCodec, weight: 2000, slug: hra, regex: '(?i)dts[ ._-]?(hd[. ]?)?(hr|hi)'}
PCM:
template: {name: AudioCodec, weight: 2200, slug: pcm, audio: '(?i)\b(l?)PCM(\b|\d)'}
PCM-Filepath:
template: {name: AudioCodec, weight: 2200, slug: pcm, filepath: '(?i)\b(l?)PCM(\b|\d)'}
template: {name: AudioCodec, weight: 2200, slug: pcm, regex: '(?i)\b(l?)PCM(\b|\d)'}
FLAC:
template: {name: AudioCodec, weight: 2250, slug: flac, audio: '(?i)\bFLAC(\b|\d)'}
FLAC-Filepath:
template: {name: AudioCodec, weight: 2250, slug: flac, filepath: '(?i)\bFLAC(\b|\d)'}
template: {name: AudioCodec, weight: 2250, slug: flac, regex: '(?i)\bFLAC(\b|\d)'}
DTS-HD-MA:
template: {name: AudioCodec, weight: 2500, slug: hd, audio: '(?i)dts[ .-]?(ma\b|hd[ .-]?ma|hd)(?!china|r)'}
DTS-HD-MA-Filepath:
template: {name: AudioCodec, weight: 2500, slug: hd, filepath: '(?i)dts[ .-]?(ma\b|hd[ .-]?ma|hd)(?!china|r)'}
template: {name: AudioCodec, weight: 2500, slug: ma, regex: '(?i)dts[ .-]?(ma\b|hd[ .-]?ma|hd)(?!china|r)'}
Dolby-TrueHD:
template: {name: AudioCodec, weight: 2750, slug: truehd, audio: '(?i)^(?!.*(atmos))(?=.*\b(true[ .-]?hd)\b).*'}
Dolby-TrueHD-Filepath:
template: {name: AudioCodec, weight: 2750, slug: truehd, filepath: '(?i)^(?!.*(atmos))(?=.*\b(true[ .-]?hd)\b).*'}
template: {name: AudioCodec, weight: 2750, slug: truehd, regex: '(?i)^(?!.*(atmos))(?=.*\b(true[ .-]?hd)\b).*'}
Dolby-Digital-Plus-Atmos:
template: {name: AudioCodec, weight: 3000, slug: plus-atmos, standard_value: 189, audio: '(?i)((?=.*([^-]DD[P+](?!A)|eac3))(?=.*\b(atmos(\b|\d))))|(?=.*\b(DDPA(\b|\d)))'}
Dolby-Digital-Plus-Atmos-Filepath:
template: {name: AudioCodec, weight: 3000, slug: plus-atmos, standard_value: 189, filepath: '(?i)((?=.*([^-]DD[P+](?!A)|eac3))(?=.*\b(atmos(\b|\d))))|(?=.*\b(DDPA(\b|\d)))'}
template: {name: AudioCodec, weight: 3000, slug: plus_atmos, standard_value: 189, regex: '(?i)((?=.*([^-]DD[P+](?!A)|eac3))(?=.*\b(atmos(\b|\d))))|(?=.*\b(DDPA(\b|\d)))'}
Dolby-Atmos:
template: {name: AudioCodec, weight: 3000, slug: atmos, audio: '(?i)^(?!.*([^-]DD[P+](?!A)|eac3|true[ .-]?hd))(?=.*\b(atmos(\b|\d))).*'}
Dolby-Atmos-Filepath:
template: {name: AudioCodec, weight: 3000, slug: atmos, filepath: '(?i)^(?!.*([^-]DD[P+](?!A)|eac3|true[ .-]?hd))(?=.*\b(atmos(\b|\d))).*'}
template: {name: AudioCodec, weight: 3000, slug: dolby_atmos, regex: '(?i)^(?!.*([^-]DD[P+](?!A)|eac3|true[ .-]?hd))(?=.*\b(atmos(\b|\d))).*'}
DTS-X:
template: {name: AudioCodec, weight: 4500, slug: x, audio: 'dts[-. ]?x(?!\d)'}
DTS-X-Filepath:
template: {name: AudioCodec, weight: 4500, slug: x, filepath: 'dts[-. ]?x(?!\d)'}
template: {name: AudioCodec, weight: 4500, slug: dtsx, regex: 'dts[-. ]?x(?!\d)'}
Dolby-TrueHD-Atmos:
template: {name: AudioCodec, weight: 5000, slug: truehd-atmos, standard_value: 189, audio: '(?i)(?=.*\b(true[ .-]?hd))(?=.*\b(atmos(\b|\d)))'}
Dolby-TrueHD-Atmos-Filepath:
template: {name: AudioCodec, weight: 5000, slug: truehd-atmos, standard_value: 189, filepath: '(?i)(?=.*\b(true[ .-]?hd))(?=.*\b(atmos(\b|\d)))'}
template: {name: AudioCodec, weight: 5000, slug: truehd_atmos, standard_value: 189, regex: '(?i)(?=.*\b(true[ .-]?hd))(?=.*\b(atmos(\b|\d)))'}

View file

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

View file

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

View file

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View file

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

View file

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

View file

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

View file

Before

Width:  |  Height:  |  Size: 4 KiB

After

Width:  |  Height:  |  Size: 4 KiB

View file

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

View file

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

View file

Before

Width:  |  Height:  |  Size: 5 KiB

After

Width:  |  Height:  |  Size: 5 KiB

View file

@ -97,8 +97,7 @@ templates:
sync_mode: sync
plex_all: true
filters:
<<filter_term>>: <<filter_value>>
<<filter_term2>>: <<filter_value2>>
<<filter_term>>: <<value>>
mdb_smart:
default:

View file

@ -1489,37 +1489,43 @@ class CollectionBuilder:
self.builders.append((method_name[:-8] if method_name.endswith("_details") else method_name, value))
def _filters(self, method_name, method_data):
dict_data = util.parse(self.Type, method_name, method_data, datatype="dict")
dict_methods = {dm.lower(): dm for dm in dict_data}
validate = True
if "validate" in dict_methods:
if dict_data[dict_methods["validate"]] is None:
raise Failed(f"{self.Type} Error: validate filter attribute is blank")
if not isinstance(dict_data[dict_methods["validate"]], bool):
raise Failed(f"{self.Type} Error: validate filter attribute must be either true or false")
validate = dict_data.pop(dict_methods["validate"])
for filter_method, filter_data in dict_data.items():
filter_attr, modifier, filter_final = self.library.split(filter_method)
message = None
if filter_final not in all_filters:
message = f"{self.Type} Error: {filter_final} is not a valid filter attribute"
elif self.builder_level in filters and filter_attr not in filters[self.builder_level]:
message = f"{self.Type} Error: {filter_final} is not a valid {self.builder_level} filter attribute"
elif filter_final is None:
message = f"{self.Type} Error: {filter_final} filter attribute is blank"
else:
final_data = self.validate_attribute(filter_attr, modifier, f"{filter_final} filter", filter_data, validate)
if filter_attr in tmdb_filters:
self.tmdb_filters.append((filter_final, final_data))
elif self.builder_level in ["show", "season", "artist", "album"] and filter_attr in sub_filters:
self.filters.append(("episodes" if self.builder_level in ["show", "season"] else "tracks", {filter_final: final_data, "percentage": self.default_percent}))
for dict_data in util.parse(self.Type, method_name, method_data, datatype="listdict"):
dict_methods = {dm.lower(): dm for dm in dict_data}
current_filters = []
current_tmdb = []
validate = True
if "validate" in dict_methods:
if dict_data[dict_methods["validate"]] is None:
raise Failed(f"{self.Type} Error: validate filter attribute is blank")
if not isinstance(dict_data[dict_methods["validate"]], bool):
raise Failed(f"{self.Type} Error: validate filter attribute must be either true or false")
validate = dict_data.pop(dict_methods["validate"])
for filter_method, filter_data in dict_data.items():
filter_attr, modifier, filter_final = self.library.split(filter_method)
message = None
if filter_final not in all_filters:
message = f"{self.Type} Error: {filter_final} is not a valid filter attribute"
elif self.builder_level in filters and filter_attr not in filters[self.builder_level]:
message = f"{self.Type} Error: {filter_final} is not a valid {self.builder_level} filter attribute"
elif filter_final is None:
message = f"{self.Type} Error: {filter_final} filter attribute is blank"
else:
self.filters.append((filter_final, final_data))
if message:
if validate:
raise Failed(message)
else:
logger.error(message)
final_data = self.validate_attribute(filter_attr, modifier, f"{filter_final} filter", filter_data, validate)
if filter_attr in tmdb_filters:
current_tmdb.append((filter_final, final_data))
elif self.builder_level in ["show", "season", "artist", "album"] and filter_attr in sub_filters:
current_filters.append(("episodes" if self.builder_level in ["show", "season"] else "tracks", {filter_final: final_data, "percentage": self.default_percent}))
else:
current_filters.append((filter_final, final_data))
if message:
if validate:
raise Failed(message)
else:
logger.error(message)
if current_filters:
self.filters.append(current_filters)
if current_tmdb:
self.tmdb_filters.append(current_tmdb)
def gather_ids(self, method, value):
expired = None
@ -2198,9 +2204,69 @@ class CollectionBuilder:
logger.info(f"{amount_removed} {self.builder_level.capitalize()}{'s' if amount_removed == 1 else ''} Removed")
return amount_removed
def single_tmdb_filter(self, item, filter_method, filter_data, is_movie):
filter_attr, modifier, filter_final = self.library.split(filter_method)
if filter_attr in ["tmdb_status", "tmdb_type", "original_language"]:
if filter_attr == "tmdb_status":
check_value = discover_status[item.status]
elif filter_attr == "tmdb_type":
check_value = discover_types[item.type]
elif filter_attr == "original_language":
check_value = item.language_iso
else:
raise Failed
if (modifier == ".not" and check_value in filter_data) or (modifier == "" and check_value not in filter_data):
return False
elif filter_attr in ["first_episode_aired", "last_episode_aired", "last_episode_aired_or_never"]:
tmdb_date = None
if filter_attr == "first_episode_aired":
tmdb_date = item.first_air_date
elif filter_attr in ["last_episode_aired", "last_episode_aired_or_never"]:
tmdb_date = item.last_air_date
# tmdb_date is empty if never aired yet
if tmdb_date is None and filter_attr == "last_episode_aired_or_never":
return True
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
elif filter_attr == "tmdb_year":
attr = item.release_date.year if is_movie else item.first_air_date.year
if util.is_number_filter(attr, modifier, filter_data):
return False
elif filter_attr in ["tmdb_genre", "tmdb_keyword", "origin_country"]:
if filter_attr == "tmdb_genre":
attrs = item.genres
elif filter_attr == "tmdb_keyword":
attrs = item.keywords
elif filter_attr == "origin_country":
attrs = [c.iso_3166_1 for c in item.countries]
else:
raise Failed
if modifier == ".regex":
has_match = False
for reg in filter_data:
for name in attrs:
if re.compile(reg).search(name):
has_match = True
if has_match is False:
return False
elif (not list(set(filter_data) & set(attrs)) and modifier == "") \
or (list(set(filter_data) & set(attrs)) and modifier == ".not"):
return False
elif filter_attr == "tmdb_title":
if util.is_string_filter([item.title], modifier, filter_data):
return False
return True
def check_tmdb_filter(self, item_id, is_movie, item=None, check_released=False):
final_return = True
if self.tmdb_filters or check_released:
try:
final_return = False
if item is None:
if is_movie:
item = self.config.TMDb.get_movie(item_id, ignore_cache=True)
@ -2210,70 +2276,20 @@ class CollectionBuilder:
date_to_check = item.release_date if is_movie else item.first_air_date
if not date_to_check or date_to_check > self.current_time:
return False
for filter_method, filter_data in self.tmdb_filters:
filter_attr, modifier, filter_final = self.library.split(filter_method)
if filter_attr in ["tmdb_status", "tmdb_type", "original_language"]:
if filter_attr == "tmdb_status":
check_value = discover_status[item.status]
elif filter_attr == "tmdb_type":
check_value = discover_types[item.type]
elif filter_attr == "original_language":
check_value = item.language_iso
else:
raise Failed
if (modifier == ".not" and check_value in filter_data) or (modifier == "" and check_value not in filter_data):
return False
elif filter_attr in ["first_episode_aired", "last_episode_aired", "last_episode_aired_or_never"]:
tmdb_date = None
if filter_attr == "first_episode_aired":
tmdb_date = item.first_air_date
elif filter_attr in ["last_episode_aired", "last_episode_aired_or_never"]:
tmdb_date = item.last_air_date
# tmdb_date is empty if never aired yet
if tmdb_date is None and filter_attr == "last_episode_aired_or_never":
return True
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
elif filter_attr == "tmdb_year":
attr = item.release_date.year if is_movie else item.first_air_date.year
if util.is_number_filter(attr, modifier, filter_data):
return False
elif filter_attr in ["tmdb_genre", "tmdb_keyword", "origin_country"]:
if filter_attr == "tmdb_genre":
attrs = item.genres
elif filter_attr == "tmdb_keyword":
attrs = item.keywords
elif filter_attr == "origin_country":
attrs = [c.iso_3166_1 for c in item.countries]
else:
raise Failed
if modifier == ".regex":
has_match = False
for reg in filter_data:
for name in attrs:
if re.compile(reg).search(name):
has_match = True
if has_match is False:
return False
elif (not list(set(filter_data) & set(attrs)) and modifier == "") \
or (list(set(filter_data) & set(attrs)) and modifier == ".not"):
return False
elif filter_attr == "tmdb_title":
if util.is_string_filter([item.title], modifier, filter_data):
return False
for filter_list in self.tmdb_filters:
for filter_method, filter_data in filter_list:
if self.single_tmdb_filter(item, filter_method, filter_data, is_movie):
final_return = True
except Failed:
return False
return True
return final_return
def check_filters(self, item, display):
final_return = True
if (self.filters or self.tmdb_filters) and not self.details["only_filter_missing"]:
logger.ghost(f"Filtering {display} {item.title}")
item = self.library.reload(item)
final_return = False
if self.tmdb_filters and isinstance(item, (Movie, Show)):
if item.ratingKey not in self.library.movie_rating_key_map and item.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 {item.title}")
@ -2286,11 +2302,23 @@ class CollectionBuilder:
except Failed as e:
logger.error(e)
return False
if not self.check_tmdb_filter(t_id, item.ratingKey in self.library.movie_rating_key_map):
return False
if self.library.check_filters(item, self.filters, self.current_time) is False:
return False
return True
if self.check_tmdb_filter(t_id, item.ratingKey in self.library.movie_rating_key_map):
final_return = True
for filter_list in self.filters:
if self.library.check_filters(item, filter_list, self.current_time):
final_return = True
return final_return
def display_filters(self):
if self.filters or self.tmdb_filters:
for filter_list in self.filters:
logger.info("")
for filter_key, filter_value in filter_list:
logger.info(f"Collection Filter {filter_key}: {filter_value}")
for filter_list in self.tmdb_filters:
logger.info("")
for filter_key, filter_value in filter_list:
logger.info(f"Collection Filter {filter_key}: {filter_value}")
def run_missing(self):
added_to_radarr = 0

View file

@ -392,12 +392,7 @@ class Overlays:
raise Failed(f"Overlay Error: Overlay {builder.overlay.mapping_name} already exists")
properties[builder.overlay.mapping_name] = builder.overlay
if builder.filters or builder.tmdb_filters:
logger.info("")
for filter_key, filter_value in builder.filters:
logger.info(f"Collection Filter {filter_key}: {filter_value}")
for filter_key, filter_value in builder.tmdb_filters:
logger.info(f"Collection Filter {filter_key}: {filter_value}")
builder.display_filters()
for method, value in builder.builders:
logger.debug("")

View file

@ -590,12 +590,7 @@ def run_collection(config, library, metadata, requested_collections):
if not builder.added_items and builder.ignore_blank_results:
raise NonExisting(f"Overlay Warning: No items found")
if builder.filters or builder.tmdb_filters:
logger.info("")
for filter_key, filter_value in builder.filters:
logger.info(f"Collection Filter {filter_key}: {filter_value}")
for filter_key, filter_value in builder.tmdb_filters:
logger.info(f"Collection Filter {filter_key}: {filter_value}")
builder.display_filters()
if len(builder.added_items) > 0 and len(builder.added_items) + builder.beginning_count >= builder.minimum and builder.build_collection:
items_added, items_unchanged = builder.add_to_collection()
@ -786,15 +781,9 @@ def run_playlists(config):
else:
ids = builder.gather_ids(method, value)
builder.display_filters()
builder.filter_and_save_items(ids)
if builder.filters or builder.tmdb_filters:
logger.info("")
for filter_key, filter_value in builder.filters:
logger.info(f"Playlist Filter {filter_key}: {filter_value}")
for filter_key, filter_value in builder.tmdb_filters:
logger.info(f"Playlist Filter {filter_key}: {filter_value}")
if len(builder.added_items) > 0 and len(builder.added_items) + builder.beginning_count >= builder.minimum:
items_added, items_unchanged = builder.add_to_collection()
stats["added"] += items_added