Skip to content

Commit 8dbbaae

Browse files
committed
Use guid for matching
1 parent 5e2e9cc commit 8dbbaae

File tree

4 files changed

+66
-11
lines changed

4 files changed

+66
-11
lines changed

README.md

+32
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,38 @@ https://anilist.co/anime/99263/Tate-no-Yuusha-no-Nariagari
189189
- You can remove any existing entries from the example file as they are purely instructional
190190
- 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.
191191

192+
#### Duplicate Plex Titles
193+
194+
For Plex shows and movies with the same title, use the optional `guid` field in the mapping.
195+
196+
For example, both of these Rurouni Kenshin shows are shown as "Rurouni Kenshin" in Plex:
197+
198+
```yaml
199+
- title: "Rurouni Kenshin"
200+
guid: plex://show/5d9c07ece264b7001fc38094
201+
seasons:
202+
- season: 1
203+
anilist-id: 45
204+
- season: 2
205+
anilist-id: 45
206+
- season: 3
207+
anilist-id: 45
208+
209+
- title: "Rurouni Kenshin (2023)"
210+
guid: plex://show/6330a57e9705fab2b34f656d
211+
seasons:
212+
- season: 1
213+
anilist-id: 142877
214+
```
215+
216+
When the `guid` field is set, the `title` and `synonyms` fields are ignored. However, you should still use different titles for human readability.
217+
218+
To find the guid, perform the following steps:
219+
1. Open this URL in an **incognito browser window**: https://app.plex.tv/desktop/#!/search?pivot=top&query=
220+
2. Search for your series or movie and click on the correct entry
221+
3. Copy everything after `metadata%2F`, so for https://app.plex.tv/desktop/#!/provider/tv.plex.provider.discover/details?key=%2Flibrary%2Fmetadata%2F6330a57e9705fab2b34f656d copy `6330a57e9705fab2b34f656d`
222+
4. If it's a TV show, add `plex://show/` before that identifier, for movies use `plex://movie/`
223+
192224
#### Community mappings
193225

194226
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.

plexanisync/anilist.py

+12-8
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ def match_to_plex(self, anilist_series: List[AnilistSeries], plex_series_watched
5050
plex_title = plex_series.title
5151
plex_title_sort = plex_series.title_sort
5252
plex_title_original = plex_series.title_original
53+
plex_guid = plex_series.guid
5354
plex_year = plex_series.year
5455
plex_seasons = plex_series.seasons
5556
plex_show_rating = plex_series.rating
@@ -65,7 +66,7 @@ def match_to_plex(self, anilist_series: List[AnilistSeries], plex_series_watched
6566
for plex_season in plex_seasons:
6667

6768
season_mappings: List[AnilistCustomMapping] = self.__retrieve_season_mappings(
68-
plex_title, plex_season.season_number
69+
plex_title, plex_guid, plex_season.season_number
6970
)
7071
# split season -> handle it in "any remaining seasons" section
7172
if season_mappings and len(season_mappings) == 1:
@@ -171,7 +172,7 @@ def match_to_plex(self, anilist_series: List[AnilistSeries], plex_series_watched
171172
]
172173
potential_titles = list(potential_titles_cleaned)
173174

174-
season_mappings = self.__retrieve_season_mappings(plex_title, season_number)
175+
season_mappings = self.__retrieve_season_mappings(plex_title, plex_guid, season_number)
175176
# Custom mapping check - check user list
176177
if season_mappings:
177178
watchcounts = self.__map_watchcount_to_seasons(plex_title, season_mappings, plex_season.watched_episodes)
@@ -262,7 +263,7 @@ def match_to_plex(self, anilist_series: List[AnilistSeries], plex_series_watched
262263
media_id_search = None
263264
# ignore the Plex year since Plex does not have years for seasons
264265
skip_year_check = True
265-
season_mappings = self.__retrieve_season_mappings(plex_title, season_number)
266+
season_mappings = self.__retrieve_season_mappings(plex_title, plex_guid, season_number)
266267
if season_mappings:
267268
watchcounts = self.__map_watchcount_to_seasons(plex_title, season_mappings, plex_season.watched_episodes)
268269

@@ -651,14 +652,17 @@ def __update_episode_incremental(
651652
for current_episodes_watched in range(anilist_episodes_watched + 1, watched_episode_count + 1):
652653
self.graphql.update_series(series.anilist_id, current_episodes_watched, new_status, plex_rating)
653654

654-
def __retrieve_season_mappings(self, title: str, season: int) -> List[AnilistCustomMapping]:
655+
def __retrieve_season_mappings(self, title: str, guid: str, season: int) -> List[AnilistCustomMapping]:
655656
season_mappings: List[AnilistCustomMapping] = []
656657

657-
if self.custom_mappings and title.lower() in self.custom_mappings:
658-
season_mappings = self.custom_mappings[title.lower()]
659-
# filter mappings by season
660-
season_mappings = [e for e in season_mappings if e.season == season]
658+
if self.custom_mappings:
659+
if guid in self.custom_mappings:
660+
season_mappings = self.custom_mappings[guid]
661+
elif title.lower() in self.custom_mappings:
662+
season_mappings = self.custom_mappings[title.lower()]
661663

664+
# filter mappings by season
665+
season_mappings = [e for e in season_mappings if e.season == season]
662666
return season_mappings
663667

664668
def __map_watchcount_to_seasons(

plexanisync/custom_mappings.py

+19-3
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ def construct_scalar(self, node):
7777

7878
def read_custom_mappings() -> Dict[str, List[AnilistCustomMapping]]:
7979
custom_mappings: Dict[str, List[AnilistCustomMapping]] = {}
80+
title_guid_mappings: Dict[str, str] = {}
8081
if not os.path.isfile(MAPPING_FILE):
8182
logger.info(f"Custom map file not found: {MAPPING_FILE}")
8283
return custom_mappings
@@ -112,9 +113,9 @@ def read_custom_mappings() -> Dict[str, List[AnilistCustomMapping]]:
112113
logger.error(f'Custom Mappings {mapping_location} validation failed!')
113114
__handle_yaml_error(file_mappings_remote, e)
114115

115-
__add_mappings(custom_mappings, mapping_location, file_mappings_remote)
116+
__add_mappings(custom_mappings, title_guid_mappings, mapping_location, file_mappings_remote)
116117

117-
__add_mappings(custom_mappings, MAPPING_FILE, file_mappings_local)
118+
__add_mappings(custom_mappings, title_guid_mappings, MAPPING_FILE, file_mappings_local)
118119

119120
return custom_mappings
120121

@@ -137,12 +138,15 @@ def __handle_yaml_error(file_mappings_local, error):
137138
sys.exit(1)
138139

139140

140-
def __add_mappings(custom_mappings, mapping_location, file_mappings):
141+
def __add_mappings(custom_mappings: Dict[str, List[AnilistCustomMapping]],
142+
title_guid_mappings: Dict[str, str],
143+
mapping_location, file_mappings):
141144
# handles missing and empty 'entries'
142145
entries = file_mappings.get('entries', []) or []
143146
for file_entry in entries:
144147
series_title = str(file_entry['title'])
145148
synonyms: List[str] = file_entry.get('synonyms', [])
149+
guid: str = str(file_entry.get('guid', ""))
146150
series_mappings: List[AnilistCustomMapping] = []
147151
for file_season in file_entry['seasons']:
148152
season = file_season['season']
@@ -155,12 +159,24 @@ def __add_mappings(custom_mappings, mapping_location, file_mappings):
155159
series_mappings.append(AnilistCustomMapping(season, anilist_id, start))
156160
if synonyms:
157161
logger.debug(f"{series_title} has synonyms: {synonyms}")
162+
163+
if guid:
164+
# store the mapping under the guid if one is set
165+
custom_mappings[guid] = series_mappings
166+
158167
for title in [series_title] + synonyms:
159168
title_lower = title.lower()
160169
if title_lower in custom_mappings:
161170
logger.info(f"Overwriting previous mapping for {title}")
171+
if title_lower in title_guid_mappings and not guid:
172+
# if the current mapping doesn't have a guid, remove the guid mapping with the same title
173+
# this ensures that users can override community mappings without specifying the guid field
174+
custom_mappings.pop(title_guid_mappings[title_lower], None)
162175
custom_mappings[title_lower] = series_mappings
163176

177+
if guid:
178+
title_guid_mappings[title_lower] = guid
179+
164180

165181
# Get the custom mappings from the web.
166182
def __get_custom_mapping_remote(file_mappings) -> List[Tuple[str, str]]:

plexanisync/plexmodule.py

+3
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ class PlexWatchedSeries:
3232
title: str
3333
title_sort: str
3434
title_original: str
35+
guid: str
3536
year: int
3637
seasons: List[PlexSeason]
3738
anilist_id: Optional[int]
@@ -220,6 +221,7 @@ def get_watched_shows(self, shows: List[Show]) -> Optional[List[PlexWatchedSerie
220221
show.title.strip(),
221222
show.titleSort.strip(),
222223
show.originalTitle.strip(),
224+
show.guid,
223225
year,
224226
seasons,
225227
anilist_id,
@@ -259,6 +261,7 @@ def get_watched_shows(self, shows: List[Show]) -> Optional[List[PlexWatchedSerie
259261
show.title.strip(),
260262
show.titleSort.strip(),
261263
show.originalTitle.strip(),
264+
show.guid,
262265
year,
263266
[PlexSeason(1, rating, 1, 1, 1)],
264267
anilist_id,

0 commit comments

Comments
 (0)