Skip to content

Commit

Permalink
Enable automatic mapping download from remote (#111)
Browse files Browse the repository at this point in the history
* Enable automatic mapping download from remote

* Made entries optional, added some fool-proofing

* Version 1.3.17
  • Loading branch information
reconman authored Feb 17, 2022
1 parent 885385c commit 05deb88
Show file tree
Hide file tree
Showing 10 changed files with 139 additions and 78 deletions.
10 changes: 5 additions & 5 deletions PlexAniSync.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
# coding=utf-8
import configparser
import logging
import logging.handlers
from logging.handlers import RotatingFileHandler
import os
import sys

import coloredlogs

from custom_mappings import read_custom_mappings
import anilist
import plexmodule
import graphql
import plexmodule
from _version import __version__
from custom_mappings import read_custom_mappings

# Logger settings
LOG_FILENAME = "PlexAniSync.log"
logger = logging.getLogger("PlexAniSync")

# Add the rotating log message handler to the standard log
handler = logging.handlers.RotatingFileHandler(
LOG_FILENAME, maxBytes=10000000, backupCount=5, encoding="utf-8"
handler = RotatingFileHandler(
LOG_FILENAME, maxBytes=10_000_000, backupCount=5, encoding="utf-8"
)
handler.setLevel(logging.INFO)
logger.addHandler(handler)
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,9 @@ https://anilist.co/anime/99263/Tate-no-Yuusha-no-Nariagari

#### 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.
There are some mappings provided by the Github community at https://github.com/RickDB/PlexAniSync-Custom-Mappings/. You can use them by specifying `remote-urls` like in the example mapping file.

If the local mapping file contains mappings for the same show as the community mapping, the local one will take precedence.

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.

Expand Down
4 changes: 2 additions & 2 deletions TautulliSyncHelper.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@

import coloredlogs

from custom_mappings import read_custom_mappings
import anilist
import plexmodule
import graphql
import plexmodule
from _version import __version__
from custom_mappings import read_custom_mappings

# Logger settings
logger = logging.getLogger("PlexAniSync")
Expand Down
2 changes: 1 addition & 1 deletion _version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "1.3.16"
__version__ = "1.3.17"
69 changes: 39 additions & 30 deletions anilist.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
# coding=utf-8
import logging
import re
from typing import Dict, List, Optional
from dataclasses import dataclass
from typing import Dict, List, Optional

import inflect

from plexmodule import PlexWatchedSeries
from custom_mappings import AnilistCustomMapping
from graphql import fetch_user_list, search_by_name, search_by_id, update_series
from plexmodule import PlexWatchedSeries

logger = logging.getLogger("PlexAniSync")
CUSTOM_MAPPINGS: Dict[str, List[AnilistCustomMapping]] = {}
Expand Down Expand Up @@ -80,7 +80,8 @@ def process_user_list(username: str) -> Optional[List[AnilistSeries]]:
if hasattr(media_collection, "entries"):
for list_entry in media_collection.entries:
if (hasattr(list_entry, "status")
and list_entry.status in ["CURRENT", "PLANNING", "COMPLETED", "DROPPED", "PAUSED", "REPEATING"]
and list_entry.status in ["CURRENT", "PLANNING", "COMPLETED", "DROPPED", "PAUSED",
"REPEATING"]
and list_entry.media is not None):
series_obj = mediaitem_to_object(list_entry)
anilist_series.append(series_obj)
Expand Down Expand Up @@ -193,7 +194,7 @@ def match_to_plex(anilist_series: List[AnilistSeries], plex_series_watched: List
plex_watched_episode_count_custom_mapping += plex_season.watched_episodes
custom_mapping_season_count += 1

custom_mapping_seasons_anilist_id = matched_id
custom_mapping_seasons_anilist_id = matched_id

# If we had custom mappings for multiple seasons with the same ID use
# cumulative episode count and skip per season processing
Expand All @@ -206,7 +207,8 @@ def match_to_plex(anilist_series: List[AnilistSeries], plex_series_watched: List
)

add_or_update_show_by_id(
anilist_series, plex_title, plex_year, True, plex_watched_episode_count_custom_mapping, custom_mapping_seasons_anilist_id
anilist_series, plex_title, plex_year, True, plex_watched_episode_count_custom_mapping,
custom_mapping_seasons_anilist_id
)
mapped_season_count = custom_mapping_season_count

Expand Down Expand Up @@ -275,8 +277,10 @@ def match_to_plex(anilist_series: List[AnilistSeries], plex_series_watched: List

# Reordered checks from above to ensure that custom mappings always take precedent
if plex_anilist_id:
logger.info(f"[ANILIST] Series {plex_title} has Anilist ID {plex_anilist_id} in its metadata, using that for updating")
add_or_update_show_by_id(anilist_series, plex_title, plex_year, True, plex_watched_episode_count, plex_anilist_id)
logger.info(
f"[ANILIST] Series {plex_title} has Anilist ID {plex_anilist_id} in its metadata, using that for updating")
add_or_update_show_by_id(anilist_series, plex_title, plex_year, True, plex_watched_episode_count,
plex_anilist_id)
continue

# Regular matching
Expand Down Expand Up @@ -374,7 +378,8 @@ def match_to_plex(anilist_series: List[AnilistSeries], plex_series_watched: List

plex_title_lookup = plex_title
if media_id_search:
add_or_update_show_by_id(anilist_series, plex_title, plex_year, skip_year_check, plex_watched_episode_count, media_id_search)
add_or_update_show_by_id(anilist_series, plex_title, plex_year, skip_year_check,
plex_watched_episode_count, media_id_search)
else:
error_message = (
f"[ANILIST] Failed to find valid season title match on AniList for: {plex_title_lookup} season {season_number}"
Expand All @@ -390,7 +395,7 @@ def find_mapped_series(anilist_series: List[AnilistSeries], anime_id: int):


def match_series_against_potential_titles(
series: AnilistSeries, potential_titles: List[str], matched_anilist_series: List[AnilistSeries]
series: AnilistSeries, potential_titles: List[str], matched_anilist_series: List[AnilistSeries]
):
if series.title_english:
if series.title_english.lower() in potential_titles:
Expand Down Expand Up @@ -548,17 +553,17 @@ def find_id_best_match(title: str, year: int) -> Optional[int]:

# logger.info('Comparing AniList: %s | %s[%s] <===> %s[%s]' % (title_english, title_romaji, started_year, match_title, match_year))
if (
match_title == title_english_for_matching
and match_year == started_year
match_title == title_english_for_matching
and match_year == started_year
):
media_id = media_item.id
logger.warning(
f"[ANILIST] Found match: {title_english} [{media_id}]"
)
break
if (
match_title == title_romaji_for_matching
and match_year == started_year
match_title == title_romaji_for_matching
and match_year == started_year
):
media_id = media_item.id
logger.warning(
Expand All @@ -570,24 +575,24 @@ def find_id_best_match(title: str, year: int) -> Optional[int]:
synonyms = synonym
synonyms_for_matching = clean_title(synonyms)
if (
match_title == synonyms_for_matching
and match_year == started_year
match_title == synonyms_for_matching
and match_year == started_year
):
media_id = media_item.id
logger.warning(
f"[ANILIST] Found match in synonyms: {synonyms} [{media_id}]"
)
break
if (
match_title == title_romaji_for_matching
and match_year != started_year
match_title == title_romaji_for_matching
and match_year != started_year
):
logger.info(
f"[ANILIST] Found match however started year is a mismatch: {title_romaji} [AL: {started_year} <==> Plex: {match_year}] "
)
elif (
match_title == title_english_for_matching
and match_year != started_year
match_title == title_english_for_matching
and match_year != started_year
):
logger.info(
f"[ANILIST] Found match however started year is a mismatch: {title_english} [AL: {started_year} <==> Plex: {match_year}] "
Expand All @@ -597,7 +602,8 @@ def find_id_best_match(title: str, year: int) -> Optional[int]:
return media_id


def add_or_update_show_by_id(anilist_series: List[AnilistSeries], plex_title: str, plex_year: int, skip_year_check: bool, watched_episodes: int, anime_id: int):
def add_or_update_show_by_id(anilist_series: List[AnilistSeries], plex_title: str, plex_year: int,
skip_year_check: bool, watched_episodes: int, anime_id: int):
series = find_mapped_series(anilist_series, anime_id)
if series:
logger.info(
Expand All @@ -624,7 +630,7 @@ def add_or_update_show_by_id(anilist_series: List[AnilistSeries], plex_title: st


def add_by_id(
anilist_id: int, plex_title: str, plex_year: int, plex_watched_episode_count: int, ignore_year: bool
anilist_id: int, plex_title: str, plex_year: int, plex_watched_episode_count: int, ignore_year: bool
):
media_lookup_result = search_by_id(anilist_id)
if media_lookup_result:
Expand All @@ -648,7 +654,8 @@ def add_by_id(


def update_entry(
title: str, year: int, watched_episode_count: int, matched_anilist_series: List[AnilistSeries], ignore_year: bool
title: str, year: int, watched_episode_count: int, matched_anilist_series: List[AnilistSeries],
ignore_year: bool
):
for series in matched_anilist_series:
status = ""
Expand Down Expand Up @@ -703,8 +710,8 @@ def update_entry(
pass

if (
watched_episode_count >= anilist_total_episodes > 0
and anilist_media_status == "FINISHED"
watched_episode_count >= anilist_total_episodes > 0
and anilist_media_status == "FINISHED"
):
# series completed watched
logger.warning(
Expand All @@ -716,8 +723,8 @@ def update_entry(
update_episode_incremental(series, watched_episode_count, anilist_episodes_watched, "COMPLETED")
return
elif (
watched_episode_count > anilist_episodes_watched
and anilist_total_episodes > 0
watched_episode_count > anilist_episodes_watched
and anilist_total_episodes > 0
):
# episode watch count higher than plex
new_status = status if status == "REPEATING" else "CURRENT"
Expand All @@ -736,8 +743,8 @@ def update_entry(
)
return
elif (
anilist_episodes_watched > watched_episode_count
and ANILIST_PLEX_EPISODE_COUNT_PRIORITY
anilist_episodes_watched > watched_episode_count
and ANILIST_PLEX_EPISODE_COUNT_PRIORITY
):
if watched_episode_count > 0:
logger.info(
Expand Down Expand Up @@ -766,7 +773,8 @@ def update_entry(
)


def update_episode_incremental(series: AnilistSeries, watched_episode_count: int, anilist_episodes_watched: int, new_status: str):
def update_episode_incremental(series: AnilistSeries, watched_episode_count: int, anilist_episodes_watched: int,
new_status: str):
# calculate episode difference and iterate up so activity stream lists
# episodes watched if episode difference exceeds 32 only update most
# recent as otherwise will flood the notification feed
Expand All @@ -789,7 +797,8 @@ def retrieve_season_mappings(title: str, season: int) -> List[AnilistCustomMappi
return season_mappings


def map_watchcount_to_seasons(title: str, season_mappings: List[AnilistCustomMapping], watched_episodes: int) -> Dict[int, int]:
def map_watchcount_to_seasons(title: str, season_mappings: List[AnilistCustomMapping], watched_episodes: int) -> Dict[
int, int]:
# mapping from anilist-id to watched episodes
episodes_in_anilist_entry: Dict[int, int] = {}
total_mapped_episodes = 0
Expand Down
Loading

0 comments on commit 05deb88

Please sign in to comment.