diff --git a/PlexAniSync.py b/PlexAniSync.py index 140a4fc..078546e 100644 --- a/PlexAniSync.py +++ b/PlexAniSync.py @@ -12,7 +12,7 @@ import plexmodule import graphql -__version__ = "1.3.14" +__version__ = "1.3.15" # Logger settings LOG_FILENAME = "PlexAniSync.log" diff --git a/README.md b/README.md index a29f2f5..09ef60b 100644 --- a/README.md +++ b/README.md @@ -180,6 +180,12 @@ https://anilist.co/anime/99263/Tate-no-Yuusha-no-Nariagari - You can remove any existing entries from the example file as they are purely instructional - Upon startup it will check if the file is a valid YAML file. The most likely reason it's not is because you didn't put quotes around an anime title with special characters (e.g. ":") in it. +#### Community mappings + +There are some mappings provided by the Github community at https://github.com/RickDB/PlexAniSync-Custom-Mappings/. For now you can use the mapping files by copying parts into your own mapping file. + +The feature of synonyms was introduced for the community mappings where you can specify that a show can have one of multiple titles but should be mapped the same way. See Shaman King (2021) in the example mapping file. + ### Custom settings file location If you want to load a different settings.in file you can do so by supplying it in the first argument like so: diff --git a/TautulliSyncHelper.py b/TautulliSyncHelper.py index 773a8eb..6c21a62 100644 --- a/TautulliSyncHelper.py +++ b/TautulliSyncHelper.py @@ -11,7 +11,7 @@ import plexmodule import graphql -__version__ = "1.3.14" +__version__ = "1.3.15" # Logger settings logger = logging.getLogger("PlexAniSync") diff --git a/anilist.py b/anilist.py index 9d4c849..cff87d2 100644 --- a/anilist.py +++ b/anilist.py @@ -287,12 +287,12 @@ def match_to_plex(anilist_series: List[AnilistSeries], plex_series_watched: List if season_mappings: watchcounts = map_watchcount_to_seasons(plex_title, season_mappings, plex_season.watched_episodes) - for anime_id in watchcounts: + for anime_id, watchcount in watchcounts.items(): logger.info( f"[ANILIST] Used custom mapping | title: {plex_title} | season: {season_number} | anilist id: {anime_id}" ) - add_or_update_show_by_id(anilist_series, plex_title, plex_year, True, watchcounts[anime_id], anime_id) + add_or_update_show_by_id(anilist_series, plex_title, plex_year, True, watchcount, anime_id) # If custom match found continue to next continue @@ -376,11 +376,11 @@ def match_to_plex(anilist_series: List[AnilistSeries], plex_series_watched: List if season_mappings: watchcounts = map_watchcount_to_seasons(plex_title, season_mappings, plex_season.watched_episodes) - for anime_id in watchcounts: + for anime_id, watchcount in watchcounts.items(): logger.info( f"[ANILIST] Used custom mapping | title: {plex_title} | season: {season_number} | anilist id: {anime_id}" ) - add_or_update_show_by_id(anilist_series, plex_title, plex_year, True, watchcounts[anime_id], anime_id) + add_or_update_show_by_id(anilist_series, plex_title, plex_year, True, watchcount, anime_id) # If custom match found continue to next continue diff --git a/custom_mappings.py b/custom_mappings.py index 5df1af5..66723cc 100644 --- a/custom_mappings.py +++ b/custom_mappings.py @@ -1,10 +1,12 @@ # coding=utf-8 import os import logging +import sys from typing import List from dataclasses import dataclass -from ruyaml import YAML +import yamale +from yamale.yamale_error import YamaleError logger = logging.getLogger("PlexAniSync") @@ -24,19 +26,29 @@ def read_custom_mappings(): logger.info(f"[MAPPING] Custom map file not found: {MAPPING_FILE}") else: logger.info(f"[MAPPING] Custom map file found: {MAPPING_FILE}") - file = open(MAPPING_FILE, "r", encoding="utf-8") - yaml = YAML(typ='safe') - file_mappings = yaml.load(file) - - for file_entry in file_mappings['entries']: + schema = yamale.make_schema('./custom_mappings_schema.yaml', parser='ruamel') + + # Create a Data object + file_mappings = yamale.make_data(MAPPING_FILE, parser='ruamel') + + try: + # Validate data against the schema same as before. + yamale.validate(schema, file_mappings) + except YamaleError as e: + logger.error('Custom Mappings validation failed!\n') + for result in e.results: + for error in result.errors: + logger.error(f"{error}\n") + sys.exit(1) + + for file_entry in file_mappings[0][0]['entries']: series_title = str(file_entry['title']).lower() + synonyms = file_entry.get('synonyms', []) series_mappings: List[AnilistCustomMapping] = [] for file_season in file_entry['seasons']: season = file_season['season'] anilist_id = file_season['anilist-id'] - start = 1 - if 'start' in file_season: - start = file_season['start'] + start = file_season.get('start', 1) logger.info( f"[MAPPING] Adding custom mapping | title: {file_entry['title']} | season: {season} | anilist id: {anilist_id} | start: {start}" @@ -44,4 +56,6 @@ def read_custom_mappings(): series_mappings.append(AnilistCustomMapping(season, anilist_id, start)) custom_mappings[series_title] = series_mappings + for synonym in synonyms: + custom_mappings[synonym] = series_mappings return custom_mappings diff --git a/custom_mappings.yaml.example b/custom_mappings.yaml.example index 7873c44..8a4f59c 100644 --- a/custom_mappings.yaml.example +++ b/custom_mappings.yaml.example @@ -42,4 +42,10 @@ entries: start: 1 - season: 10 anilist-id: 101925 - start: 13 \ No newline at end of file + start: 13 + - title: 'Shaman King (2021)' + synonyms: + - 'Shaman King' + seasons: + - season: 1 + anilist-id: 119675 \ No newline at end of file diff --git a/custom_mappings_schema.yaml b/custom_mappings_schema.yaml new file mode 100644 index 0000000..fc62f3b --- /dev/null +++ b/custom_mappings_schema.yaml @@ -0,0 +1,11 @@ +entries: list(include('entry'), min=1) +--- +entry: + title: str() + synonyms: list(str(), required=False) + seasons: list(include('season'), min=1) + +season: + season: int(min=1) + anilist-id: int(min=1) + start: int(required=False) \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index fe48b44..515e67b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,20 +1,21 @@ -babelfish>=0.5.5 -beautifulsoup4>=4.9.3 -certifi>=2020.12.5 -chardet>=4.0.0 -colorama>=0.4.4 -coloredlogs>=15.0 -guessit>=3.3.0 -humanfriendly>=9.1 -idna>=2.10 -inflect>=5.0.2 -PlexAPI>=4.5.2 -pyreadline>=2.1 -python-dateutil>=2.8.1 -rebulk>=3.0.1 -requests>=2.25.1 -ruyaml>=0.20.0 -six>=1.15.0 -tqdm>=4.56.0 -urllib3>=1.26.3 -websocket-client>=0.57.0 +-babelfish>=0.5.5 +-beautifulsoup4>=4.9.3 +-certifi>=2020.12.5 +-chardet>=4.0.0 +-colorama>=0.4.4 +-coloredlogs>=15.0 +-guessit>=3.3.0 +-humanfriendly>=9.1 +-idna>=2.10 +-inflect>=5.0.2 +-PlexAPI>=4.5.2 +-pyreadline>=2.1 +-python-dateutil>=2.8.1 +-rebulk>=3.0.1 +-requests>=2.25.1 +-ruamel.yaml>=0.17.17 +-six>=1.15.0 +-tqdm>=4.56.0 +-urllib3>=1.26.3 +-websocket-client>=0.57.0 +-yamale>=4.0.2 \ No newline at end of file