Taxel / PlexTraktSync

A python script that syncs the movies, shows and ratings between trakt and Plex (without needing a PlexPass or Trakt VIP subscription)

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Error 'NoneType' object has no attribute 'plex' when syncing ratings from Trakt to Plex

DevYukine opened this issue · comments

Confirmation

  • I have read the README.md on the project homepage
  • I have checked if identical issue already exists
  • I have tried downgrading to find version that can be used as a workaround

The problem

I'm running plextraktsync inside docker with a scheduler in a loop, i recently started to receive the error while syncing, i have a 2 way sync enabled.

Error trace / logs

plextraktsync  | ERROR    'NoneType' object has no attribute 'plex'                              
plextraktsync  |          ╭───────────────── Traceback (most recent call last) ─────────────────╮
plextraktsync  |          │ /app/plextraktsync/cli.py:26 in wrap                                │
plextraktsync  |          │                                                                     │
plextraktsync  |          │    23 │   │   │   cmd = getattr(module, name)                       │
plextraktsync  |          │    24 │   │   │                                                     │
plextraktsync  |          │    25 │   │   │   try:                                              │
plextraktsync  |          │ ❱  26 │   │   │   │   cmd(*args, **kwargs)                          │
plextraktsync  |          │    27 │   │   │   except ClickException as e:                       │
plextraktsync  |          │    28 │   │   │   │   from plextraktsync.factory import logger      │
plextraktsync  |          │    29 │   │   │   │   logger.fatal(f"Error running {name} command:  │
plextraktsync  |          │                                                                     │
plextraktsync  |          │ /app/plextraktsync/commands/sync.py:68 in sync                      │
plextraktsync  |          │                                                                     │
plextraktsync  |          │   65 │   │   │   w.print_plan(print=logger.info)                    │
plextraktsync  |          │   66 │   │   if dry_run:                                            │
plextraktsync  |          │   67 │   │   │   logger.info("Enabled dry-run mode: not making actu │
plextraktsync  |          │ ❱ 68 │   │   runner.sync(walker=w, dry_run=config.dry_run)          │
plextraktsync  |          │   69                                                                │
plextraktsync  |          │                                                                     │
plextraktsync  |          │ /app/plextraktsync/sync.py:81 in sync                               │
plextraktsync  |          │                                                                     │
plextraktsync  |          │    78 │   │   │   episode_trakt_ids = set()                         │
plextraktsync  |          │    79 │   │   │   for episode in walker.find_episodes():            │
plextraktsync  |          │    80 │   │   │   │   self.sync_collection(episode, dry_run=dry_run │
plextraktsync  |          │ ❱  81 │   │   │   │   self.sync_ratings(episode, dry_run=dry_run)   │
plextraktsync  |          │    82 │   │   │   │   self.sync_watched(episode, dry_run=dry_run)   │
plextraktsync  |          │    83 │   │   │   │   if not is_partial:                            │
plextraktsync  |          │    84 │   │   │   │   │   trakt_lists.add_to_lists(episode)         │
plextraktsync  |          │                                                                     │
plextraktsync  |          │ /app/plextraktsync/sync.py:135 in sync_ratings                      │
plextraktsync  |          │                                                                     │
plextraktsync  |          │   132 │   │   if not self.config.sync_ratings:                      │
plextraktsync  |          │   133 │   │   │   return                                            │
plextraktsync  |          │   134 │   │                                                         │
plextraktsync  |          │ ❱ 135 │   │   if m.plex_rating is m.trakt_rating:                   │
plextraktsync  |          │   136 │   │   │   return                                            │
plextraktsync  |          │   137 │   │                                                         │
plextraktsync  |          │   138 │   │   rating_priority = self.config["rating_priority"]      │
plextraktsync  |          │                                                                     │
plextraktsync  |          │ /usr/local/lib/python3.12/functools.py:995 in __get__               │
plextraktsync  |          │                                                                     │
plextraktsync  |          │    992 │   │   │   raise TypeError(msg) from None                   │
plextraktsync  |          │    993 │   │   val = cache.get(self.attrname, _NOT_FOUND)           │
plextraktsync  |          │    994 │   │   if val is _NOT_FOUND:                                │
plextraktsync  |          │ ❱  995 │   │   │   val = self.func(instance)                        │
plextraktsync  |          │    996 │   │   │   try:                                             │
plextraktsync  |          │    997 │   │   │   │   cache[self.attrname] = val                   │
plextraktsync  |          │    998 │   │   │   except TypeError:                                │
plextraktsync  |          │                                                                     │
plextraktsync  |          │ /app/plextraktsync/media.py:222 in plex_rating                      │
plextraktsync  |          │                                                                     │
plextraktsync  |          │   219 │                                                             │
plextraktsync  |          │   220 │   @cached_property                                          │
plextraktsync  |          │   221 │   def plex_rating(self):                                    │
plextraktsync  |          │ ❱ 222 │   │   show_id = self.show.plex.item.ratingKey if self.media │
plextraktsync  |          │       self.plex.is_discover else None                               │
plextraktsync  |          │   223 │   │   return self.plex.rating(show_id)                      │
plextraktsync  |          │   224 │                                                             │
plextraktsync  |          │   225 │   def trakt_rate(self):                                     │
plextraktsync  |          ╰─────────────────────────────────────────────────────────────────────╯
plextraktsync  |          AttributeError: 'NoneType' object has no attribute 'plex'              
plextraktsync  | Error: Error running sync command: 'NoneType' object has no attribute 'plex'

Expected behavior

It should sync as usual and not error while syncing

Steps to reproduce the behavior

  1. enable trakt_to_plex rating sync
  2. start sync
  3. error happens

Inspect of problematic items

No response

Workarounds

It seems that when i disable trakt_to_plex ratings then it does sync without erroring so i assume it has something to do with that.

Install method

docker-compose

Config file contents

cache:
  path: $PTS_CACHE_DIR/trakt_cache

excluded-libraries:
  - Private
  - Family Holidays

config:
  dotenv_override: true

plex:
  timeout: 30

logging:
  append: true
  # Whether to show timestamps in console messages
  console_time: false
  debug: false
  filename: plextraktsync.log
  # Additional logger names to apply filtering
  filter_loggers:
#    - plexapi
#    - requests_cache.backends
#    - requests_cache.backends.base
#    - requests_cache.backends.sqlite
#    - requests_cache.policy.actions
#    - requests_cache.session
#    - trakt.core
#    - urllib3.connectionpool
  filter:
#    # Filter out all messages with level WARNING
#    - level: WARNING
#    # Filter out message with level WARNING and containing a text
#    - level: WARNING
#      message: "not found on Trakt"
#    - message: "because provider local has no external Id"
#    - message: "because provider none has no external Id"
#    - message: "Retry using search for specific Plex Episode"
#    # Filter out messages by requests_cache
#    - name: requests_cache.backends
#    - name: requests_cache.backends.base
#    - name: requests_cache.backends.sqlite
#    - name: requests_cache.policy.actions
#    - name: requests_cache.session

# settings for 'sync' command (default)
sync:
  plex_to_trakt:
    collection: true
    # Clear collected state of items not present in Plex
    clear_collected: true
    ratings: true
    watched_status: true
    # If plex_to_trakt watchlist=false and trakt_to_plex watchlist=true
    # the Plex watchlist will be overwritten by Trakt watchlist
    watchlist: true
  trakt_to_plex:
    liked_lists: true
    ratings: true
    watched_status: true
    # If trakt_to_plex watchlist=false and plex_to_trakt watchlist=true
    # the Trakt watchlist will be overwritten by Plex watchlist
    watchlist: true
    # If you prefer to fetch trakt watchlist as a playlist instead of
    # plex watchlist, toggle this to true (is read only if watchlist=true)
    watchlist_as_playlist: false
  # Setting for whether ratings from one platform should have priority.
  # Valid values are trakt, plex or none. (default: plex)
  # none - No rating priority. Existing ratings are not overwritten.
  # trakt - Trakt ratings have priority. Existing Plex ratings are overwritten.
  # plex - Plex ratings have priority. Existing Trakt ratings are overwritten.
  rating_priority: plex

# settings for 'watch' command
watch:
  add_collection: false
  remove_collection: false
  # what video watched percentage (0 to 100) triggers the watched status
  scrobble_threshold: 90
  # true to scrobble only what's watched by you, false for all your PMS users
  username_filter: true
  # Show the progress bar of played media in terminal
  media_progressbar: true

xbmc-providers:
  movies: imdb
  shows: tvdb

##### Advanced settings below this line, don't edit unless you know what you're doing #####
#http_cache:
  # https://requests-cache.readthedocs.io/en/main/user_guide/expiration.html#url-patterns
  # https://requests-cache.readthedocs.io/en/main/user_guide/expiration.html#expiration-values
  #
  # The value is seconds to cache.
  # Or one of the following special values:
  # - DO_NOT_CACHE: Skip both reading from and writing to the cache
  # - EXPIRE_IMMEDIATELY: Consider the response already expired, but potentially usable
  # - NEVER_EXPIRE: Store responses indefinitely
  #
  # The value can be also suffixed with a time unit:
  # - 5m, 1h, 3d
  # See full documentation at:
  # - https://github.com/wroberts/pytimeparse#pytimeparse-time-expression-parser
  #
  # NOTE: If there is more than one match, the first match will be used in the order they are defined
#  policy:
#    "*.trakt.tv/users/me": 1d
#    "*.trakt.tv/users/likes/lists": DO_NOT_CACHE

# vim:ts=2:sw=2:et

Version

0.28.7

Python Version

3.12.1

Plex Server Version

1.32.8.7639-fb6452ebf

Operating System and Version

alpine 3.19

Try downgrade, and give the exact version it got broken.

The code in trace doesn't match version you reported:

plextraktsync  |          │ /app/plextraktsync/media.py:222 in plex_rating                      │
plextraktsync  |          │                                                                     │
plextraktsync  |          │   219 │                                                             │
plextraktsync  |          │   220 │   @cached_property                                          │
plextraktsync  |          │   221 │   def plex_rating(self):                                    │
plextraktsync  |          │ ❱ 222 │   │   show_id = self.show.plex.item.ratingKey if self.media │
plextraktsync  |          │       self.plex.is_discover else None                               │
plextraktsync  |          │   223 │   │   return self.plex.rating(show_id)    

but the code at that version is:

try to. find out the id of problematic item. put try/catch around m.plex_rating and log m

--- a/plextraktsync/sync.py
+++ b/plextraktsync/sync.py
@@ -122,7 +122,11 @@ def sync_ratings(self, m: Media, dry_run=False):
         if not self.config.sync_ratings:
             return
 
-        if m.plex_rating is m.trakt_rating:
+        try:
+            if m.plex_rating is m.trakt_rating:
+                return
+        except AttributeError as e:
+            logger.error(f"{e} of {m}")
             return
 
         rating_priority = self.config["rating_priority"]

and when you have the id, do plextraktsync inspect on it

I'm guessing this happens when the episode has no match in trakt. but I can't reproduce this.

yet another user who reported something, and disappeared to dust if extra questions are asked or debugging aid given.

closing as per: c1311ca