Taxel / PlexTraktSync

A python script that syncs the movies, shows and ratings between trakt and Plex (without needing a PlexPass or Trakt VIP subscription)
MIT License
1.62k stars 105 forks source link

Sync crashes : trakt.errors.NotFoundException (404 error) #615

Closed typhoe closed 2 years ago

typhoe commented 2 years ago

The problem

When I allow PlexTraktSync to sync my Anime Series library, it crashes with this message (I'll leave the last entry before the crash):

With each restart, it also seems to "reach" the next episode (meaning, it will crash on the next episode.

INFO: Marking as watched in Trakt: <tvdb:305089/2/18:<Episode:100864:Re:ZERO--Starting-Li-s02e18>>
Processing Anime Series  74% ━━━━━━━━    125/170  [ 0:01:02 < 0:00:22 , 2 it/s ]
Traceback (most recent call last):
  File "/usr/local/lib/python3.10/runpy.py", line 196, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "/usr/local/lib/python3.10/runpy.py", line 86, in _run_code
    exec(code, run_globals)
  File "/app/plextraktsync/__main__.py", line 16, in <module>
    cli()
  File "/usr/local/lib/python3.10/site-packages/click/core.py", line 1128, in __call__
    return self.main(*args, **kwargs)
  File "/usr/local/lib/python3.10/site-packages/click/core.py", line 1053, in main
    rv = self.invoke(ctx)
  File "/usr/local/lib/python3.10/site-packages/click/core.py", line 1637, in invoke
    super().invoke(ctx)
  File "/usr/local/lib/python3.10/site-packages/click/core.py", line 1395, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/usr/local/lib/python3.10/site-packages/click/core.py", line 754, in invoke
    return __callback(*args, **kwargs)
  File "/usr/local/lib/python3.10/site-packages/click/decorators.py", line 26, in new_func
    return f(get_current_context(), *args, **kwargs)
  File "/app/plextraktsync/cli.py", line 23, in cli
    sync()
  File "/usr/local/lib/python3.10/site-packages/click/core.py", line 1128, in __call__
    return self.main(*args, **kwargs)
  File "/usr/local/lib/python3.10/site-packages/click/core.py", line 1053, in main
    rv = self.invoke(ctx)
  File "/usr/local/lib/python3.10/site-packages/click/core.py", line 1395, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/usr/local/lib/python3.10/site-packages/click/core.py", line 754, in invoke
    return __callback(*args, **kwargs)
  File "/app/plextraktsync/commands/sync.py", line 111, in sync
    runner.sync(walker=w, dry_run=config.dry_run)
  File "/app/plextraktsync/sync.py", line 80, in sync
    self.sync_watched(episode, dry_run=dry_run)
  File "/app/plextraktsync/sync.py", line 134, in sync_watched
    m.mark_watched_trakt()
  File "/app/plextraktsync/media.py", line 81, in mark_watched_trakt
    self.trakt_api.mark_watched(self.trakt, self.plex.seen_date)
  File "/app/plextraktsync/decorators/nocache.py", line 12, in inner
    return method(*args, **kwargs)
  File "/app/plextraktsync/decorators/rate_limit.py", line 23, in wrapper
    return fn(*args, **kwargs)
  File "/app/plextraktsync/decorators/time_limit.py", line 18, in wrapper
    return fn(*args, **kwargs)
  File "/app/plextraktsync/trakt_api.py", line 177, in mark_watched
    self.watched_shows.add(TVShow(m.show).trakt, m.season, m.number)
  File "/usr/local/lib/python3.10/site-packages/trakt/tv.py", line 216, in __init__
    self._get()
  File "/usr/local/lib/python3.10/site-packages/trakt/core.py", line 552, in inner
    json_data = self._handle_request('get', url)
  File "/usr/local/lib/python3.10/site-packages/trakt/core.py", line 529, in _handle_request
    raise self.error_map[response.status_code](response)
trakt.errors.NotFoundException: Not Found - method exists, but no record found

Error trace

2021-11-17 22:53:47,079 INFO[PlexTraktSync]:To be added to collection: <tvdb:305089/2/18:<Episode:100864:Re:ZERO--Starting-Li-s02e18>>
2021-11-17 22:53:47,080 DEBUG[trakt.core]:post: https://api-v2launch.trakt.tv/sync/collection
2021-11-17 22:53:47,080 DEBUG[trakt.core]:headers: {'Content-Type': 'application/json', 'trakt-api-version': '2', 'trakt-api-key': 'REDACTED', 'Authorization': 'Bearer REDACTED'}
2021-11-17 22:53:47,080 DEBUG[trakt.core]:method, url :: post, https://api-v2launch.trakt.tv/sync/collection
2021-11-17 22:53:47,388 DEBUG[urllib3.connectionpool]:https://api-v2launch.trakt.tv:443 "POST /sync/collection HTTP/1.1" 201 None
2021-11-17 22:53:47,389 DEBUG[requests_cache.session]:Pre-cache checks for response from https://api-v2launch.trakt.tv/sync/collection: {'disabled cache': True, 'disabled method': True, 'disabled status': True, 'disabled by filter': False, 'disabled by headers or expiration params': False}
2021-11-17 22:53:47,389 DEBUG[requests_cache.session]:Skipping cache write for URL: https://api-v2launch.trakt.tv/sync/collection
2021-11-17 22:53:47,389 DEBUG[trakt.core]:RESPONSE [post] (https://api-v2launch.trakt.tv/sync/collection): <Response [201]>
2021-11-17 22:53:47,389 INFO[PlexTraktSync]:Updated Trakt collection: {'added': {'episodes': 1}}
2021-11-17 22:53:47,389 DEBUG[plexapi]:Reloading Episode 'The Day Betelgeuse Laughed' for attr 'userRating'
2021-11-17 22:53:47,389 DEBUG[plexapi]:Reloading Episode 'The Day Betelgeuse Laughed' for attr 'userRating'
2021-11-17 22:53:47,389 DEBUG[plexapi]:GET https://plex.REDACTED/library/metadata/100864?checkFiles=1&includeAllConcerts=1&includeBandwidths=1&includeChapters=1&includeChildren=1&includeConcerts=1&includeExternalMedia=1&includeExtras=1&includeFields=thumbBlurHash%2CartBlurHash&includeGeolocation=1&includeLoudnessRamps=1&includeMarkers=1&includeOnDeck=1&includePopularLeaves=1&includePreferences=1&includeRelated=1&includeRelatedCount=1&includeReviews=1&includeStations=1
2021-11-17 22:53:47,389 DEBUG[plexapi]:GET https://plex.REDACTED/library/metadata/100864?checkFiles=1&includeAllConcerts=1&includeBandwidths=1&includeChapters=1&includeChildren=1&includeConcerts=1&includeExternalMedia=1&includeExtras=1&includeFields=thumbBlurHash%2CartBlurHash&includeGeolocation=1&includeLoudnessRamps=1&includeMarkers=1&includeOnDeck=1&includePopularLeaves=1&includePreferences=1&includeRelated=1&includeRelatedCount=1&includeReviews=1&includeStations=1
2021-11-17 22:53:47,409 DEBUG[urllib3.connectionpool]:https://plex.REDACTED "GET /library/metadata/100864?checkFiles=1&includeAllConcerts=1&includeBandwidths=1&includeChapters=1&includeChildren=1&includeConcerts=1&includeExternalMedia=1&includeExtras=1&includeFields=thumbBlurHash%2CartBlurHash&includeGeolocation=1&includeLoudnessRamps=1&includeMarkers=1&includeOnDeck=1&includePopularLeaves=1&includePreferences=1&includeRelated=1&includeRelatedCount=1&includeReviews=1&includeStations=1 HTTP/1.1" 200 1948
2021-11-17 22:53:47,409 DEBUG[requests_cache.session]:Pre-cache checks for response from https://plex.REDACTED/library/metadata/100864?checkFiles=1&includeAllConcerts=1&includeBandwidths=1&includeChapters=1&includeChildren=1&includeConcerts=1&includeExternalMedia=1&includeExtras=1&includeFields=thumbBlurHash%2CartBlurHash&includeGeolocation=1&includeLoudnessRamps=1&includeMarkers=1&includeOnDeck=1&includePopularLeaves=1&includePreferences=1&includeRelated=1&includeRelatedCount=1&includeReviews=1&includeStations=1: {'disabled cache': False, 'disabled method': False, 'disabled status': False, 'disabled by filter': False, 'disabled by headers or expiration params': False}
2021-11-17 22:53:47,469 INFO[PlexTraktSync]:Marking as watched in Trakt: <tvdb:305089/2/18:<Episode:100864:Re:ZERO--Starting-Li-s02e18>>
2021-11-17 22:53:47,470 DEBUG[PlexTraktSync]:Sleeping for 0.710 seconds
2021-11-17 22:53:48,180 DEBUG[trakt.core]:post: https://api-v2launch.trakt.tv/sync/history
2021-11-17 22:53:48,180 DEBUG[trakt.core]:headers: {'Content-Type': 'application/json', 'trakt-api-version': '2', 'trakt-api-key': 'REDACTED', 'Authorization': 'Bearer REDACTED'}
2021-11-17 22:53:48,180 DEBUG[trakt.core]:method, url :: post, https://api-v2launch.trakt.tv/sync/history
2021-11-17 22:53:48,410 DEBUG[urllib3.connectionpool]:https://api-v2launch.trakt.tv:443 "POST /sync/history HTTP/1.1" 201 None
2021-11-17 22:53:48,411 DEBUG[requests_cache.session]:Pre-cache checks for response from https://api-v2launch.trakt.tv/sync/history: {'disabled cache': True, 'disabled method': True, 'disabled status': True, 'disabled by filter': False, 'disabled by headers or expiration params': False}
2021-11-17 22:53:48,411 DEBUG[requests_cache.session]:Skipping cache write for URL: https://api-v2launch.trakt.tv/sync/history
2021-11-17 22:53:48,411 DEBUG[trakt.core]:RESPONSE [post] (https://api-v2launch.trakt.tv/sync/history): <Response [201]>
2021-11-17 22:53:48,411 DEBUG[trakt.core]:get: https://api-v2launch.trakt.tv/shows/re-zero-starting-life-in-another-world-?extended=full
2021-11-17 22:53:48,411 DEBUG[trakt.core]:headers: {'Content-Type': 'application/json', 'trakt-api-version': '2', 'trakt-api-key': 'REDACTED', 'Authorization': 'Bearer REDACTED'}
2021-11-17 22:53:48,411 DEBUG[trakt.core]:method, url :: get, https://api-v2launch.trakt.tv/shows/re-zero-starting-life-in-another-world-?extended=full
2021-11-17 22:53:48,774 DEBUG[urllib3.connectionpool]:https://api-v2launch.trakt.tv:443 "GET /shows/re-zero-starting-life-in-another-world-?extended=full HTTP/1.1" 404 None
2021-11-17 22:53:48,774 DEBUG[requests_cache.session]:Pre-cache checks for response from https://api-v2launch.trakt.tv/shows/re-zero-starting-life-in-another-world-?extended=full: {'disabled cache': True, 'disabled method': False, 'disabled status': True, 'disabled by filter': False, 'disabled by headers or expiration params': False}
2021-11-17 22:53:48,774 DEBUG[requests_cache.session]:Skipping cache write for URL: https://api-v2launch.trakt.tv/shows/re-zero-starting-life-in-another-world-?extended=full
2021-11-17 22:53:48,774 DEBUG[trakt.core]:RESPONSE [get] (https://api-v2launch.trakt.tv/shows/re-zero-starting-life-in-another-world-?extended=full): <Response [404]>

Expected behavior

No crash

Steps to reproduce the behavior

Don't know exactly.

For me, it's only to enable the sync on my Anime Series library. I tried to reassociate (in plex, to refresh its metadata and matching ids) the serie on which the problem occurs but it doesn't change anything.

I'm launching the sync from the latest docker version available:

docker run --rm  --name plextraktsync-dryrun  --net=media-net  -v /zfs/data/docker/plextraktsync/config:/app/config -v /etc/localtime:/etc/localtime:ro  -v /etc/timezone:/etc/timezone:ro     ghcr.io/taxel/plextraktsync

Inspect of problematic items

docker run --rm     --name plextraktsync-dryrun     --net=media-net     -v /zfs/data/docker/plextraktsync/config:/app/config     -v /etc/localtime:/etc/localtime:ro     -v /etc/timezone:/etc/timezone:ro     ghcr.io/taxel/plextraktsync

$ inspect 100864
PlexTraktSync [0.16.4]

Inspecting 100864: <tmdb:2621396:<Episode:100864:Re:ZERO--Starting-Li-s02e18>>
URL: https://app.plex.tv/desktop/#!/server/REDACTED/details?key=/library/metadata/100864
Media.Type: episode
Media.Guid: 'plex://episode/5ff9f05ac95b49002c35881b'
Media.Guids: [<Guid:imdb://tt13796590>, <Guid:tmdb://2621396>, <Guid:tvdb://8150775>]
Audio: 'stereo', '日本語 (AAC Stereo)'
Video: 'hevc'
Guids:
  Guid: tmdb://2621396, Id: 2621396, Provider: tmdb
  Guid: tvdb://8150775, Id: 8150775, Provider: tvdb
  Guid: imdb://tt13796590, Id: tt13796590, Provider: imdb
Metadata: {'collected_at': '2021-02-03:T16:00:40.000Z', 'media_type': 'digital', 'resolution': 'hd_1080p', 'audio': 'aac', 'audio_channels': '2.0'}
Trakt: https://trakt.tv/episodes/4738939
Watched on Plex: True
Watched on Trakt: True
Play history:
- 2021-02-04 13:34:38 by REDACTED with Kodi on Kodi
- 2021-02-04 13:34:38 by REDACTED with SHIELD TV on Android

Workarounds

Relaunch the sync, it seems to proceed (and crashes) to the next episode

Install method

docker-compose

Version

0.16.4

Python Version

3.10.0

Operating System and Version

Docker inside LXC privileged container on Proxmox

simonc56 commented 2 years ago

It's not a PlexTraktSync bug but a Pytrakt bug I think.

That's a very specific issue because of this show's name using - symbol : Re:ZERO -Starting Life in Another World-

The trailing dash has been removed in Trakt slug version : re-zero-starting-life-in-another-world whereas the pytrakt module does not remove it with its own slugify() function : re-zero-starting-life-in-another-world- so it doesn't match and trakt API returns 404 error.

typhoe commented 2 years ago

Oh, thank you for finding and explaining the problem!

So should I try something on my end (renaming of something?) or do I have to "restart" the sync (that will crash) until I reach the last episode and forget that problem?

Is it possible to correct the problem or is it a too specific issue to bother (and risk other pb by changing anything)?

Thank you

simonc56 commented 2 years ago

As a workaround, just mark all episodes as watched on trakt.tv website. Then run script again and tell me if it's running without crash.

typhoe commented 2 years ago

So indeed, it seems to prevent the crashes to happen and all this series Re:ZERO -Starting Life in Another World- is skipped....

But then, another one happens on that series So I’m a Spider, So What?: https://trakt.tv/shows/so-i-m-a-spider-so-what

The problem seems similar (trailing '?' in title replaced by a '-' in the naming and removed from Trakt url)

Crash:

INFO: Marking as watched in Trakt: <tvdb:377902/1/1:<Episode:100772:So-I'm-a-Spider,-So--s01e01>>
Processing Anime Series  82% ━━━━━━━━╸   139/170  [ 0:04:24 < 0:01:52 , 0 it/s ]
Traceback (most recent call last):
  File "/usr/local/lib/python3.10/runpy.py", line 196, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "/usr/local/lib/python3.10/runpy.py", line 86, in _run_code
    exec(code, run_globals)
  File "/app/plextraktsync/__main__.py", line 16, in <module>
    cli()
  File "/usr/local/lib/python3.10/site-packages/click/core.py", line 1128, in __call__
    return self.main(*args, **kwargs)
  File "/usr/local/lib/python3.10/site-packages/click/core.py", line 1053, in main
    rv = self.invoke(ctx)
  File "/usr/local/lib/python3.10/site-packages/click/core.py", line 1637, in invoke
    super().invoke(ctx)
  File "/usr/local/lib/python3.10/site-packages/click/core.py", line 1395, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/usr/local/lib/python3.10/site-packages/click/core.py", line 754, in invoke
    return __callback(*args, **kwargs)
  File "/usr/local/lib/python3.10/site-packages/click/decorators.py", line 26, in new_func
    return f(get_current_context(), *args, **kwargs)
  File "/app/plextraktsync/cli.py", line 23, in cli
    sync()
  File "/usr/local/lib/python3.10/site-packages/click/core.py", line 1128, in __call__
    return self.main(*args, **kwargs)
  File "/usr/local/lib/python3.10/site-packages/click/core.py", line 1053, in main
    rv = self.invoke(ctx)
  File "/usr/local/lib/python3.10/site-packages/click/core.py", line 1395, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/usr/local/lib/python3.10/site-packages/click/core.py", line 754, in invoke
    return __callback(*args, **kwargs)
  File "/app/plextraktsync/commands/sync.py", line 111, in sync
    runner.sync(walker=w, dry_run=config.dry_run)
  File "/app/plextraktsync/sync.py", line 80, in sync
    self.sync_watched(episode, dry_run=dry_run)
  File "/app/plextraktsync/sync.py", line 134, in sync_watched
    m.mark_watched_trakt()
  File "/app/plextraktsync/media.py", line 81, in mark_watched_trakt
    self.trakt_api.mark_watched(self.trakt, self.plex.seen_date)
  File "/app/plextraktsync/decorators/nocache.py", line 12, in inner
    return method(*args, **kwargs)
  File "/app/plextraktsync/decorators/rate_limit.py", line 23, in wrapper
    return fn(*args, **kwargs)
  File "/app/plextraktsync/decorators/time_limit.py", line 18, in wrapper
    return fn(*args, **kwargs)
  File "/app/plextraktsync/trakt_api.py", line 177, in mark_watched
    self.watched_shows.add(TVShow(m.show).trakt, m.season, m.number)
  File "/usr/local/lib/python3.10/site-packages/trakt/tv.py", line 216, in __init__
    self._get()
  File "/usr/local/lib/python3.10/site-packages/trakt/core.py", line 552, in inner
    json_data = self._handle_request('get', url)
  File "/usr/local/lib/python3.10/site-packages/trakt/core.py", line 529, in _handle_request
    raise self.error_map[response.status_code](response)
trakt.errors.NotFoundException: Not Found - method exists, but no record found

Inspect:

~# docker run --rm     --name plextraktsync-dryrun     --net=media-net     -v /zfs/data/docker/plextraktsync/config:/app/config     -v /etc/localtime:/etc/localtime:ro     -v /etc/timezone:/etc/timezone:ro     ghcr.io/taxel/plextraktsync inspect 100772
PlexTraktSync [0.16.4]

Inspecting 100772: <tvdb:377902/1/1:<Episode:100772:So-I'm-a-Spider,-So--s01e01>>
URL: https://app.plex.tv/desktop/#!/server/REDACTED/details?key=/library/metadata/100772
Media.Type: episode
Media.Guid: 'com.plexapp.agents.thetvdb://377902/1/1?lang=en'
Audio: 'stereo', '日本語 (AAC Stereo)'
Video: 'hevc'
Guids:
  Guid: com.plexapp.agents.thetvdb://377902/1/1?lang=en, Id: 377902/1/1, Provider: tvdb
Metadata: {'collected_at': '2021-01-28:T23:47:31.000Z', 'media_type': 'digital', 'resolution': 'hd_1080p', 'audio': 'aac', 'audio_channels': '2.0'}
Trakt: https://trakt.tv/episodes/4413179
Watched on Plex: True
Watched on Trakt: True
Play history:
- 2021-01-29 01:04:49 by REDACTED with Firefox on Firefox
- 2021-01-29 01:04:49 by REDACTED with Chrome on Chrome
simonc56 commented 2 years ago

The problem seems similar (trailing '?' in title replaced by a '-' in the naming and removed from Trakt url)

No it's the i'm slugified into im by PyTrakt module and into i-m in trakt database.

It's clearly a problem in slugify() function of PyTrakt module. It does not slugify exactly as official trakt.tv does. You should open an issue here with your 2 examples.

simonc56 commented 2 years ago

Note for myself : maybe this line could be improved and get show trakt_id without calling TVShow (avoid sending this request to trakt API to fetch the show id which we already have). https://github.com/Taxel/PlexTraktSync/blob/adf906d847102373ea9c3694beea39d8816e7f25/plextraktsync/trakt_api.py#L177

typhoe commented 2 years ago

You should open an issue here with your 2 examples.

Done: https://github.com/moogar0880/PyTrakt/issues/165