Skip to content

feat: Trakt.tv integration — watched history overlay & hide-watched filter (#70)#71

Merged
sdblepas merged 4 commits intomainfrom
feature/trakt-integration
Apr 27, 2026
Merged

feat: Trakt.tv integration — watched history overlay & hide-watched filter (#70)#71
sdblepas merged 4 commits intomainfrom
feature/trakt-integration

Conversation

@sdblepas
Copy link
Copy Markdown
Owner

Summary

  • Device Code OAuth: No redirect URI needed — user visits trakt.tv/activate, enters the displayed code, and CinePlete polls until authorised. Tokens + username saved automatically; access token auto-refreshes on expiry.
  • Watched overlay: A red 👁 Watched badge appears on movie cards in the recommendation grids for any film in your Trakt watch history. Watched cards are dimmed (55% opacity, full on hover).
  • Hide-watched filter: New TRAKT_HIDE_WATCHED toggle in config hides watched movies from all grids except Wishlist (where the filter is intentionally skipped).

New endpoints

Method Path Purpose
POST /api/trakt/device/code Start device-code flow
POST /api/trakt/device/poll Poll for authorisation; saves tokens on success
POST /api/trakt/disconnect Clear stored tokens
GET /api/trakt/watched TMDB IDs of watched movies (1 h cache, auto-refresh on 401)
GET /api/trakt/status Connection state for config UI

Test plan

  • Run pytest tests/test_trakt.py — all 26 tests pass
  • Run E2E (npx playwright test e2e/tests/trakt.spec.js) — config UI and card overlay tests pass
  • In the running app: go to Config → Trakt, enter real Client ID/Secret, click Connect, enter user code at trakt.tv/activate, confirm ✓ Connected as @username appears
  • Navigate to Classics/Suggestions — confirm watched movies show 👁 Watched badge
  • Enable TRAKT_HIDE_WATCHED in config, save — confirm watched movies disappear from grids
  • Confirm watched movies still appear in Wishlist when hide-watched is on
  • Click Disconnect — badge disappears, connect form restored

🤖 Generated with Claude Code

…ay (#70)

- Backend: new router `app/routers/trakt.py` with 5 endpoints
  - POST /api/trakt/device/code  — start device-code flow
  - POST /api/trakt/device/poll  — poll for token, saves on success
  - POST /api/trakt/disconnect   — revoke and clear stored tokens
  - GET  /api/trakt/watched      — TMDB IDs of watched movies (1h cache)
  - GET  /api/trakt/status       — connection state for config UI
  - Auto-refreshes access token on 401 via stored refresh token
- Config UI: Trakt section with device-code connect flow
  - Shows live user code + countdown during authorisation
  - Switches to "Connected as @username + Disconnect" on success
  - TRAKT_HIDE_WATCHED toggle to filter watched movies from all grids
- Cards: watched badge and dim overlay (👁 Watched) on watched movies
- Filters: applyFilters() respects TRAKT_HIDE_WATCHED; wishlist tab exempt
- 26 unit tests + E2E tests covering connect flow, badge, hide-watched

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@sdblepas sdblepas linked an issue Apr 27, 2026 that may be closed by this pull request
benjamin-elharrar and others added 3 commits April 27, 2026 18:36
1. Save config wiped OAuth tokens — saveConfig() now preserves
   TRAKT_ACCESS_TOKEN / REFRESH_TOKEN / USERNAME / ENABLED from
   in-memory CONFIG; falls back to CONFIG values when connect form
   fields are hidden (connected state)

2. Watched badges missing after browser refresh — _fetchTraktWatched()
   now triggers a render() on completion so the initial tab reflects
   the watched overlay without requiring a sidebar navigation

3. Hide-watched had no effect on Franchises / Directors / Actors —
   the grouped renderer bypasses applyFilters(); added the same
   _traktWatchedIds guard inline after genre/rating filters

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Backend: POST /api/trakt/watched/refresh — zeros the 1-hour cache
  timestamp so the next GET re-fetches live from Trakt
- Config UI: "⟳ Refresh history" button next to Disconnect in the
  connected state (both initial render and after device-code connect)
- Shows "✓ N watched movies" confirmation for 4s after refresh
- Re-renders the current tab so badges/hide-watched update immediately

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The previous disconnect path called save_config(full_config) which goes
through the _deep_merge pipeline. Replacing it with a direct YAML
read→patch→write guarantees the four token fields are wiped in the file
regardless of in-memory config state.

- Backend: trakt_disconnect reads raw YAML, patches TRAKT section, writes
  back — bypasses save_config merge entirely
- Backend: also clears _watched_cache data (not just ts) on disconnect
- Frontend: traktDisconnect() now clears TRAKT_REFRESH_TOKEN from
  in-memory CONFIG too (was previously missed)
- Test: updated to use tmp_path and verify the YAML file is actually
  patched on disk, not just that save_config was called

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@sdblepas sdblepas merged commit c4d6d8c into main Apr 27, 2026
7 checks passed
@sdblepas sdblepas deleted the feature/trakt-integration branch April 27, 2026 16:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add Trakt integration to identify already watched movies

1 participant