Changelog
v0.4.8 (2026-02-24)
New Features
Bug Fixes
- Fixed incremental Plex history scan failing silently: The
mindateparameter passed to PlexAPI'shistory()was a string instead of adatetimeobject, causing'str' object has no attribute 'timestamp'errors that were silently caught. All 5history()calls inplex_utils.pynow properly convert the string to adatetimebefore use. - Fixed watched status not detected for
markPlayed()items: Items marked as watched viamarkPlayed()updatelastViewedAtbut notupdatedAt. The history fallback logic now useslastViewedAtas the primary fallback timestamp instead ofupdatedAt. - Removed 748 lines of triplicate function definitions: Three duplicate definitions each of
get_trakt_history_basic,update_trakt, andupdate_simkl(plus one extra standaloneupdate_simkl) were removed fromapp.py. The app now correctly uses the imported versions fromtrakt_utils.pyandsimkl_utils.py. - Fixed safety check blocking incremental bidirectional sync: The safety condition that prevents syncing when no items are found now only applies to full syncs, not incremental ones where returning few items is expected behavior.
- Fixed Trakt items missed due to minute-level timestamp truncation: Trakt truncates
watched_atto the nearest minute. A 2-minute safety margin is now applied to thestart_atfilter when fetching incremental Trakt history, preventing recently added items from being skipped. - Fixed show title substring matching returning wrong show:
get_show_from_library()used Plex'ssec.get(title)which does substring matching — searching for "Evil" returned "Ash vs. Evil Dead". Now prefers exact title matches and falls back to search with exact-match preference. This affected both Trakt and Simkl sync. - Removed 232 lines of duplicate Simkl functions from
app.py:simkl_request,simkl_search_ids,simkl_movie_key, andget_simkl_historywere all redefined locally inapp.py, overriding imports fromsimkl_utils.py. The enhancedget_simkl_history(with/sync/all-itemsaugmentation for completed movies and episodes) was moved tosimkl_utils.pyand the duplicates removed. - Fixed Simkl episode sync re-sending episodes every cycle: Plex episode keys are episode-level GUIDs (e.g.,
"imdb://tt10864014"), while Simkl episode keys from/sync/all-itemsare show-level tuples (e.g.,("imdb://tt9055008", "S01E03")). The set difference comparison never matched because strings ≠ tuples. Added a secondary lookup by(show_title, episode_code)to correctly detect already-synced episodes in both sync directions.