[76] Or Filters
2
VERSION
|
@ -1 +1 @@
|
|||
1.17.3-develop75
|
||||
1.17.3-develop76
|
||||
|
|
|
@ -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+
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)))'}
|
||||
|
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 5.9 KiB |
Before Width: | Height: | Size: 4 KiB After Width: | Height: | Size: 4 KiB |
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 5 KiB After Width: | Height: | Size: 5 KiB |
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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("")
|
||||
|
|
|
@ -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
|
||||
|
|