diff --git a/VERSION b/VERSION
index cd72c7fc..29624a93 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.18.0-develop53
+1.18.0-develop54
diff --git a/docs/metadata/builders/myanimelist.md b/docs/metadata/builders/myanimelist.md
index c63628ca..ff8ca93c 100644
--- a/docs/metadata/builders/myanimelist.md
+++ b/docs/metadata/builders/myanimelist.md
@@ -35,9 +35,9 @@ The `sync_mode: sync` and `collection_order: custom` Details are recommended sin
| `prefix` | **Description:** Results must begin with this prefix |
| `type` | **Description:** Type of Anime to search for
**Values:** `tv`, `movie`, `ova`, `special`, `ona`, `music` |
| `status` | **Description:** Status to search for
**Values:** `airing`, `complete`, `upcoming` |
-| `genre` | **Description:** List of Genres to include
**Values:** Genre Name or ID |
-| `genre.not` | **Description:** List of Genres to exclude
**Values:** Genre Name or ID |
-| `studio` | **Description:** List of Studios to include
**Values:** Studio Name or ID |
+| `genre` | **Description:** Comma-separated String of Genres to include using `,` for `AND` and |
for `OR`
**Values:** Genre Name or ID |
+| `genre.not` | **Description:** Comma-separated String of Genres to exclude using `,` for `AND` and |
for `OR`
**Values:** Genre Name or ID |
+| `studio` | **Description:** Comma-separated String of Genres to include using `,` for `AND` and |
for `OR`
**Values:** Studio Name or ID |
| `content_rating` | **Description:** Content Rating to search for
**Values:** `g`, `pg`, `pg13`, `r17`, `r`, `rx` |
| `score.gt`/`score.gte` | **Description:** Score must be greater than the given number
**Values:** Float between `0.00`-`10.00` |
| `score.lt`/`score.lte` | **Description:** Score must be less than the given number
**Values:** Float between `0.00`-`10.00` |
diff --git a/modules/builder.py b/modules/builder.py
index 02112847..9b09ad6d 100644
--- a/modules/builder.py
+++ b/modules/builder.py
@@ -1269,20 +1269,17 @@ class CollectionBuilder:
final_attributes["status"] = util.parse(self.Type, "status", dict_data, methods=dict_methods, parent=method_name, options=mal.search_status)
final_text += f"\nStatus: {final_attributes['status']}"
if "genre" in dict_methods:
- genre_list = util.parse(self.Type, "genre", dict_data, datatype="commalist", methods=dict_methods, parent=method_name)
- final_genres = [str(self.config.MyAnimeList.genres[g]) for g in genre_list if g in self.config.MyAnimeList.genres]
- final_attributes["genres"] = ",".join(final_genres)
- final_text += f"\nGenre: {' or '.join([str(self.config.MyAnimeList.genres[g]) for g in final_genres])}"
+ genre_str = str(util.parse(self.Type, "genre", dict_data, methods=dict_methods, parent=method_name))
+ final_text += f"\nGenre: {util.parse_and_or(self.Type, 'Genre', genre_str, test_list=self.config.MyAnimeList.genres)}"
+ final_attributes["genres"] = genre_str
if "genre.not" in dict_methods:
- genre_list = util.parse(self.Type, "genre.not", dict_data, datatype="commalist", methods=dict_methods, parent=method_name)
- final_genres = [str(self.config.MyAnimeList.genres[g]) for g in genre_list if g in self.config.MyAnimeList.genres]
- final_attributes["genres_exclude"] = ",".join(final_genres)
- final_text += f"\nNot Genre: {' or '.join([str(self.config.MyAnimeList.genres[g]) for g in final_genres])}"
+ genre_str = str(util.parse(self.Type, "genre.not", dict_data, methods=dict_methods, parent=method_name))
+ final_text += f"\nNot Genre: {util.parse_and_or(self.Type, 'Genre', genre_str, test_list=self.config.MyAnimeList.genres)}"
+ final_attributes["genres_exclude"] = genre_str
if "studio" in dict_methods:
- studio_list = util.parse(self.Type, "studio", dict_data, datatype="commalist", methods=dict_methods, parent=method_name)
- final_studios = [str(self.config.MyAnimeList.studios[s]) for s in studio_list if s in self.config.MyAnimeList.studios]
- final_attributes["producers"] = ",".join(final_studios)
- final_text += f"\nStudio: {' or '.join([str(self.config.MyAnimeList.studios[s]) for s in final_studios])}"
+ studio_str = str(util.parse(self.Type, "studio", dict_data, methods=dict_methods, parent=method_name))
+ final_text += f"\nStudio: {util.parse_and_or(self.Type, 'Studio', studio_str, test_list=self.config.MyAnimeList.studios)}"
+ final_attributes["producers"] = studio_str
if "content_rating" in dict_methods:
final_attributes["rating"] = util.parse(self.Type, "content_rating", dict_data, methods=dict_methods, parent=method_name, options=mal.search_ratings)
final_text += f"\nContent Rating: {final_attributes['rating']}"
diff --git a/modules/mal.py b/modules/mal.py
index c40bb619..c388b6f7 100644
--- a/modules/mal.py
+++ b/modules/mal.py
@@ -200,6 +200,8 @@ class MyAnimeList:
raise Failed(f"MyAnimeList Error: Connection Failed")
def _jikan_request(self, url, params=None):
+ logger.trace(f"URL: {jikan_base_url}{url}")
+ logger.trace(f"Params: {params}")
time_check = time.time()
if self._delay is not None:
while time_check - self._delay < 1:
diff --git a/modules/meta.py b/modules/meta.py
index d0f41006..dd8a8be4 100644
--- a/modules/meta.py
+++ b/modules/meta.py
@@ -1416,8 +1416,6 @@ class MetadataFile(DataFile):
else:
logger.error(f"Metadata Error: Album: {album_name} not found")
continue
- if not title:
- title = album.title
album.batchEdits()
add_edit("title", album, album_dict, album_methods, value=title)
add_edit("sort_title", album, album_dict, album_methods, key="titleSort")
@@ -1461,8 +1459,6 @@ class MetadataFile(DataFile):
logger.error(f"Metadata Error: Track: {track_num} not found")
continue
- if not title:
- title = track.title
track.batchEdits()
add_edit("title", track, track_dict, track_methods, value=title)
add_edit("user_rating", track, track_dict, track_methods, key="userRating", var_type="float")
diff --git a/modules/util.py b/modules/util.py
index 0128ee77..84d10009 100644
--- a/modules/util.py
+++ b/modules/util.py
@@ -672,6 +672,28 @@ def check_int(value, datatype="int", minimum=1, maximum=None):
except ValueError:
pass
+def parse_and_or(error, attribute, data, test_list=None):
+ out = ""
+ ands = data.split(",")
+ for an in ands:
+ ors = an.split("|")
+ for item in ors:
+ if not item:
+ raise Failed(f"{error} Error: Cannot have a blank {attribute}")
+ if test_list and item not in test_list:
+ raise Failed(f"{error} Error: {attribute} {item} is invalid")
+ if out:
+ out += f" and "
+ if len(ands) > 1 and len(ors) > 1:
+ out += "("
+ if len(ors) > 1:
+ out += f"{' or '.join([test_list[o] if test_list else o for o in ors])}"
+ else:
+ out += f"{test_list[ors[0]]}" if test_list else f"{ors[0]}"
+ if len(ands) > 1 and len(ors) > 1:
+ out += ")"
+ return out
+
def parse(error, attribute, data, datatype=None, methods=None, parent=None, default=None, options=None, translation=None, minimum=1, maximum=None, regex=None, range_split=None):
display = f"{parent + ' ' if parent else ''}{attribute} attribute"
if options is None and translation is not None: