[76] Or Filters

pull/1077/head
meisnate12 2 years ago
parent bef04781cd
commit 93797ff4df

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

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

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

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

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

@ -1489,8 +1489,10 @@ class CollectionBuilder:
self.builders.append((method_name[:-8] if method_name.endswith("_details") else method_name, value)) self.builders.append((method_name[:-8] if method_name.endswith("_details") else method_name, value))
def _filters(self, method_name, method_data): def _filters(self, method_name, method_data):
dict_data = util.parse(self.Type, method_name, method_data, datatype="dict") for dict_data in util.parse(self.Type, method_name, method_data, datatype="listdict"):
dict_methods = {dm.lower(): dm for dm in dict_data} dict_methods = {dm.lower(): dm for dm in dict_data}
current_filters = []
current_tmdb = []
validate = True validate = True
if "validate" in dict_methods: if "validate" in dict_methods:
if dict_data[dict_methods["validate"]] is None: if dict_data[dict_methods["validate"]] is None:
@ -1510,16 +1512,20 @@ class CollectionBuilder:
else: else:
final_data = self.validate_attribute(filter_attr, modifier, f"{filter_final} filter", filter_data, validate) final_data = self.validate_attribute(filter_attr, modifier, f"{filter_final} filter", filter_data, validate)
if filter_attr in tmdb_filters: if filter_attr in tmdb_filters:
self.tmdb_filters.append((filter_final, final_data)) current_tmdb.append((filter_final, final_data))
elif self.builder_level in ["show", "season", "artist", "album"] and filter_attr in sub_filters: 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})) current_filters.append(("episodes" if self.builder_level in ["show", "season"] else "tracks", {filter_final: final_data, "percentage": self.default_percent}))
else: else:
self.filters.append((filter_final, final_data)) current_filters.append((filter_final, final_data))
if message: if message:
if validate: if validate:
raise Failed(message) raise Failed(message)
else: else:
logger.error(message) 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): def gather_ids(self, method, value):
expired = None expired = None
@ -2198,19 +2204,7 @@ class CollectionBuilder:
logger.info(f"{amount_removed} {self.builder_level.capitalize()}{'s' if amount_removed == 1 else ''} Removed") logger.info(f"{amount_removed} {self.builder_level.capitalize()}{'s' if amount_removed == 1 else ''} Removed")
return amount_removed return amount_removed
def check_tmdb_filter(self, item_id, is_movie, item=None, check_released=False): def single_tmdb_filter(self, item, filter_method, filter_data, is_movie):
if self.tmdb_filters or check_released:
try:
if item is None:
if is_movie:
item = self.config.TMDb.get_movie(item_id, ignore_cache=True)
else:
item = self.config.TMDb.get_show(self.config.Convert.tvdb_to_tmdb(item_id, fail=True), ignore_cache=True)
if check_released:
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) filter_attr, modifier, filter_final = self.library.split(filter_method)
if filter_attr in ["tmdb_status", "tmdb_type", "original_language"]: if filter_attr in ["tmdb_status", "tmdb_type", "original_language"]:
if filter_attr == "tmdb_status": if filter_attr == "tmdb_status":
@ -2266,14 +2260,36 @@ class CollectionBuilder:
elif filter_attr == "tmdb_title": elif filter_attr == "tmdb_title":
if util.is_string_filter([item.title], modifier, filter_data): if util.is_string_filter([item.title], modifier, filter_data):
return False 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)
else:
item = self.config.TMDb.get_show(self.config.Convert.tvdb_to_tmdb(item_id, fail=True), ignore_cache=True)
if check_released:
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_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: except Failed:
return False return False
return True return final_return
def check_filters(self, item, display): def check_filters(self, item, display):
final_return = True
if (self.filters or self.tmdb_filters) and not self.details["only_filter_missing"]: if (self.filters or self.tmdb_filters) and not self.details["only_filter_missing"]:
logger.ghost(f"Filtering {display} {item.title}") logger.ghost(f"Filtering {display} {item.title}")
item = self.library.reload(item) item = self.library.reload(item)
final_return = False
if self.tmdb_filters and isinstance(item, (Movie, Show)): 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: 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}") 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: except Failed as e:
logger.error(e) logger.error(e)
return False return False
if not self.check_tmdb_filter(t_id, item.ratingKey in self.library.movie_rating_key_map): if self.check_tmdb_filter(t_id, item.ratingKey in self.library.movie_rating_key_map):
return False final_return = True
if self.library.check_filters(item, self.filters, self.current_time) is False: for filter_list in self.filters:
return False if self.library.check_filters(item, filter_list, self.current_time):
return True 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): def run_missing(self):
added_to_radarr = 0 added_to_radarr = 0

@ -392,12 +392,7 @@ class Overlays:
raise Failed(f"Overlay Error: Overlay {builder.overlay.mapping_name} already exists") raise Failed(f"Overlay Error: Overlay {builder.overlay.mapping_name} already exists")
properties[builder.overlay.mapping_name] = builder.overlay properties[builder.overlay.mapping_name] = builder.overlay
if builder.filters or builder.tmdb_filters: builder.display_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}")
for method, value in builder.builders: for method, value in builder.builders:
logger.debug("") logger.debug("")

@ -590,12 +590,7 @@ def run_collection(config, library, metadata, requested_collections):
if not builder.added_items and builder.ignore_blank_results: if not builder.added_items and builder.ignore_blank_results:
raise NonExisting(f"Overlay Warning: No items found") raise NonExisting(f"Overlay Warning: No items found")
if builder.filters or builder.tmdb_filters: builder.display_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}")
if len(builder.added_items) > 0 and len(builder.added_items) + builder.beginning_count >= builder.minimum and builder.build_collection: 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() items_added, items_unchanged = builder.add_to_collection()
@ -786,15 +781,9 @@ def run_playlists(config):
else: else:
ids = builder.gather_ids(method, value) ids = builder.gather_ids(method, value)
builder.display_filters()
builder.filter_and_save_items(ids) 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: if len(builder.added_items) > 0 and len(builder.added_items) + builder.beginning_count >= builder.minimum:
items_added, items_unchanged = builder.add_to_collection() items_added, items_unchanged = builder.add_to_collection()
stats["added"] += items_added stats["added"] += items_added

Loading…
Cancel
Save