# Sync Trakt [![Latest release](https://img.shields.io/github/v/release/o1xhack/obsidian-sync-trakt?include_prereleases&label=release&color=7c3aed)](https://github.com/o1xhack/obsidian-sync-trakt/releases) [![Total downloads](https://img.shields.io/github/downloads/o1xhack/obsidian-sync-trakt/total?color=7c3aed)](https://github.com/o1xhack/obsidian-sync-trakt/releases) [![License](https://img.shields.io/github/license/o1xhack/obsidian-sync-trakt?color=7c3aed)](LICENSE) [![Min Obsidian version](https://img.shields.io/badge/obsidian-1.8.7%2B-7c3aed)](https://obsidian.md) [![GitHub Sponsors](https://img.shields.io/badge/sponsor-GitHub%20Sponsors-ea4aaa?logo=githubsponsors&logoColor=white)](https://github.com/sponsors/o1xhack) **Turn your [Trakt.tv](https://trakt.tv) watch history into a richly localized Markdown library โ€” with per-episode timestamps, metadata in 15+ languages, and quiet incremental sync that doesn't churn your vault.** > ๐ŸŒ **English** ยท [็ฎ€ไฝ“ไธญๆ–‡](docs/i18n/README.zh-CN.md) ยท [็น้ซ”ไธญๆ–‡](docs/i18n/README.zh-TW.md) ยท [ๆ—ฅๆœฌ่ชž](docs/i18n/README.ja.md) ยท [ํ•œ๊ตญ์–ด](docs/i18n/README.ko.md) ยท [Franรงais](docs/i18n/README.fr.md) ยท [Deutsch](docs/i18n/README.de.md) ยท [Espaรฑol](docs/i18n/README.es.md) ยท [Italiano](docs/i18n/README.it.md)

Sync Trakt movie library in Obsidian Bases

## โœจ Why? - **Detailed watch history** โ€” exactly which episode you watched at what time, including re-watches, kept in sync as you keep watching - **Metadata in 15+ languages** โ€” translate titles / overviews / taglines / genres via TMDB. Built-in presets for Chinese (CN / TW / HK), Japanese, Korean, French, German, Spanish (ES / MX), Portuguese (BR), Italian, Russian โ€” plus a custom mode for any TMDB-supported locale. **Strict primary + user-defined fallback** (e.g. zh-CN with English fallback) prevents silent zh-TW substitutions when the primary translation is missing. English originals always preserved in `*_original_*` frontmatter fields - **Filenames follow your language** โ€” switch metadata language and existing notes auto-rename on the next sync to match the new title. Internal Obsidian links update automatically. One-shot "Rename now" button in settings for manual triggers - **Note templates in 11 languages** โ€” hand-curated bundled templates (en + zh-CN + zh-TW + ja + ko + fr + de + it + es + pt-BR + ru). Pick from the template-language dropdown; switch any time without losing customizations - **Tabbed settings UI** โ€” General / Notes / Sync / Daily Notes. Last-viewed tab remembered per device - **Daily Notes integration** โ€” auto-injects per-event lines (watched / watchlist / favorited / rated) into your Daily Note on every sync, chronologically sorted, in your chosen template language. Marker-bounded region is fully isolated โ€” content outside it is **never modified**. Optional incremental mode preserves your hand-written annotations inside the marker block. Manual date-range backfill with quick presets (Last 7 days / This month / etc.). Daily Notes can also run on their own auto-sync interval without rewriting media notes. See [spec 0006](docs/specs/0006-daily-notes-integration.md) and [spec 0011](docs/specs/0011-daily-notes-auto-sync.md) - **Fast incremental sync** โ€” first sync seeds the local TMDB cache + Trakt history state; subsequent syncs only fetch what changed. Steady-state sync time drops from minutes to single-digit seconds. See [spec 0001](docs/specs/0001-incremental-sync.md) - **Quiet writes** โ€” sync only rewrites notes whose content actually changed. After watching one new episode, a 1200-item library writes one note instead of all 1200 โ€” your cross-device sync layer (Obsidian Sync / iCloud / Syncthing) stops re-uploading the entire library every run. See [spec 0002](docs/specs/0002-diff-based-write.md) - **Per-setting cloud toggle** โ€” pick which settings sync across devices and which stay local. Auto-sync interval, startup-sync toggle, UI language โ€” each can be device-local so your Mac and iPhone don't fight over them. See [spec 0003](docs/specs/0003-device-local-settings.md) ## ๐ŸŽฌ Detailed watch history When **Sync watch history (detailed)** is enabled, the plugin queries Trakt's `/sync/history` endpoint and inlines per-episode (or per-movie) timestamps into the note body โ€” and keeps that block updated as you watch new episodes: ```markdown ## Watch History - S1E1 โ€” 2024-01-15 21:30, 2024-03-22 19:00 - S1E2 โ€” 2024-01-16 22:00 - S1E3 โ€” 2024-01-17 21:45 - S2E1 โ€” 2024-04-02 20:00 ``` Re-watches are listed comma-separated; episodes sort by season then episode number. The block is wrapped in `%% trakt:watch-history %%` markers โ€” the plugin updates only what's between the markers, so any hand-written notes elsewhere in the body are never touched.

Detailed episode watch history in an Obsidian note

## ๐ŸŒ Metadata localization Set **Metadata language** to your preference and synced notes get title, overview, tagline, and genres translated via TMDB (with Trakt's translation endpoint as a fallback when no TMDB key is configured). English originals stay in `trakt_original_*` frontmatter fields: ```yaml trakt_title: ้ป‘ๆš—้ช‘ๅฃซ trakt_original_title: The Dark Knight trakt_genres: - ๅŠจไฝœ - ็Šฏ็ฝช - ๅ‰งๆƒ… trakt_original_genres: - Action - Crime - Drama trakt_metadata_language: zh-CN ``` Tags and tag-note paths always stay in English โ€” your existing Dataview queries keep working unchanged.

Localized Trakt metadata stored as Obsidian note properties

## ๐ŸŒ Plugin UI + note templates Metadata localization above is one axis; the plugin's own surfaces are separate axes: - **Settings tab, command palette, notice popups** speak **English** and **็ฎ€ไฝ“ไธญๆ–‡**. More UI languages on demand โ€” [open an issue](https://github.com/o1xhack/obsidian-sync-trakt/issues) if you want to volunteer one. - **Bundled note templates** in 11 languages โ€” English, Simplified Chinese (zh-CN), Traditional Chinese (zh-TW / zh-HK), Japanese, Korean, French, German, Italian, Spanish, Portuguese (BR), Russian. Hand-curated, not machine-translated; section headings, bullet labels, and punctuation follow each language's conventions (full-width colons in Japanese, spaced colons in French, etc.). The template-language dropdown lists exactly these 11; locales outside the list fall back to English (rather than silently picking a sibling locale).

Tabbed Sync Trakt settings with sync source controls

## ๐Ÿ“… Daily Notes integration Auto-inserts per-event lines into your Daily Note for every sync โ€” chronologically sorted, in your chosen template language. Covers watched episodes, watchlist additions, favorites, and ratings: ```markdown %% trakt:daily:start %% 10:00 โ€” ็œ‹ไบ† ไฝŽๆ™บๅ•†็Šฏ็ฝช (2026) S1E16, S1E17 14:30 โ€” ๅŠ ๅ…ฅๆƒณ็œ‹ ้ป‘ๆš—้ช‘ๅฃซ (2008) 21:30 โ€” ๆ‰“ๅˆ† 9/10 ้‡็”Ÿ (2020) %% trakt:daily:end %% ``` Each event type is gated by its corresponding sync source toggle โ€” if `Sync favorites` is off, favorite events won't appear in Daily Notes either. Verbs (`watched` / `็œ‹ไบ†` / `่ฆ–่ด` / `์‹œ์ฒญ` / `a regardรฉ`โ€ฆ) follow your **template language** setting across all 11 bundled languages. **Safety contract**: the marker region is fully isolated โ€” content outside it is **never modified**. Past days are add-only by default (existing markers preserved); today is overwritten so newer events appear on later syncs. An **incremental mode** opt-in changes today's behavior to append-only too, so any annotations you write inside the marker block survive every sync. **Manual backfill** uses a date-range picker with quick presets (Last 7 days / Last 30 days / This month / Last month). Live count shows how many Daily Notes actually exist in the picked range before you confirm. Configure folder + filename format (Moment.js syntax like `YYYY-MM-DD` or `YYYY/YYYY.MM.DD`) in **Settings โ†’ Daily Notes**. See [spec 0006](docs/specs/0006-daily-notes-integration.md). **Daily Notes-only auto-sync** can be enabled separately from full media auto-sync. It refreshes the Trakt/TMDB data needed for Daily Notes and updates existing Daily Note files, but it does not create, rename, delete, or rewrite media notes. The Daily-only timer and the full sync timer share one lock, so if they fire together, one run skips instead of writing concurrently.

Daily Notes populated with Trakt watch activity

## ๐Ÿ”„ Cross-device sync Auth state โ€” Trakt tokens, TMDB key, all settings โ€” lives in `/.obsidian/plugins/sync-trakt/data.json` and follows your vault-sync layer. Configure auth once on Mac, share with iPhone via Obsidian Sync (with `Plugin data` enabled), Syncthing, iCloud + Advanced Data Protection, or Cryptomator. The plugin doesn't store anything on a server. Large rebuildable runtime caches, including TMDB metadata and detailed watch-history aggregates, live outside the vault in each device's local Obsidian app storage. They are not uploaded to Obsidian Sync, and each device can rebuild them from Trakt/TMDB if cleared. A small synced full-refresh coordinator keeps devices from writing detailed history from an older local cache after another device has detected Trakt-side deletions. **Any individual setting can opt out of cross-device sync** via a small cloud icon next to it (currently exposed for `Sync on startup` / `Auto-sync` / `Auto-sync interval` / `Daily Notes auto-sync` / `Daily Notes auto-sync interval` / `Plugin UI language`). Useful when, e.g., you want media-note sync every few hours on Mac, Daily Notes every 15 minutes on Mac, and no automatic timers on iPhone. ## ๐Ÿ“Š View your library in Obsidian Bases The `trakt_poster_url` frontmatter field works out-of-the-box with [Obsidian Bases](https://help.obsidian.md/bases) (Obsidian 1.9.3+). Build a database view of your sync folder and display posters as thumbnails: - **Card view**: open Display settings โ†’ set **Image property** to `trakt_poster_url` - **Table view** (1.9.4+): add a formula column with `image(note.trakt_poster_url)` Filter by `trakt_type = "movie"` / `"show"`, sort by `trakt_year` / `trakt_rating` / `trakt_my_rating`, group by `trakt_genres`. The same frontmatter properties that power Dataview queries also power Bases views โ€” no extra setup.

Obsidian Bases card view for synced Trakt movies and shows

## ๐Ÿš€ Quick start 1. Settings โ†’ Community plugins โ†’ **Browse** โ†’ search for **Sync Trakt** โ†’ **Install** โ†’ **Enable** 2. Settings โ†’ **Sync Trakt** โ†’ fill your Trakt + TMDB API keys ([SETUP guide](docs/SETUP.md)) 3. Command palette โ†’ **Sync Trakt: Sync** ## ๐Ÿ”‘ API keys: what each one unlocks The plugin uses two APIs. **Trakt is mandatory** โ€” without it, the plugin can't sync anything. **TMDB is optional** but unlocks most of what makes the plugin worth installing. Here's the breakdown: | Feature | Trakt API
_(required)_ | TMDB API
_(recommended)_ | |---|:---:|:---:| | Sync your Trakt library (watchlist, watched, favorites, ratings) | โœ… | โ€” | | Per-episode watch timestamps | โœ… | โ€” | | Title / overview / tagline in your language | โœ… basic | โœ… higher quality | | **Genres in your language** | โŒ | โœ… | | **Poster images embedded in notes** | โŒ | โœ… | If you only want English content and no posters, you can leave TMDB blank โ€” Trakt alone is enough. If you want any non-English localization beyond title/overview/tagline, **add a TMDB key** ([free signup](https://www.themoviedb.org/settings/api)). After pasting your key, click the **Test** button next to the field to confirm it works before your first sync. โ†’ [Full walkthrough for both keys](docs/SETUP.md) ## ๐Ÿ“ฆ Install
Obsidian Community Plugins (recommended) 1. Settings โ†’ Community plugins โ†’ **Browse** 2. Search for **Sync Trakt** 3. Click **Install** โ†’ **Enable** Directory page: https://community.obsidian.md/plugins/sync-trakt
Development (build from source) ```bash git clone https://github.com/o1xhack/obsidian-sync-trakt.git cd obsidian-sync-trakt npm install npm run build # produces main.js npm run lint npm run test:i18n # smoke tests ``` Then copy `main.js`, `manifest.json`, `styles.css` to `/.obsidian/plugins/sync-trakt/`.
Local test (manual install) 1. Download `main.js`, `manifest.json`, `styles.css` from the [latest release](https://github.com/o1xhack/obsidian-sync-trakt/releases/latest) 2. Place all three files in `/.obsidian/plugins/sync-trakt/` 3. Settings โ†’ Community plugins โ†’ enable **Sync Trakt**
## ๐Ÿ“š Documentation | Doc | Purpose | |---|---| | [SETUP](docs/SETUP.md) | Trakt + TMDB API key creation, first-time configuration, troubleshooting | | [MANUAL](docs/MANUAL.md) | Full settings reference, frontmatter fields, template variables, sync behavior | | [DEVELOPER](docs/DEVELOPER.md) | Architecture overview, data flow, how to extend (English only) | | [docs/i18n/](docs/i18n/) | Translations of README / SETUP / MANUAL into 8 additional languages | ## ๐Ÿ—บ๏ธ Roadmap Major versions since the fork (chronological): - [x] **0.1** โ€” Initial fork. Detailed watch history with per-episode timestamps, metadata localization via TMDB + Trakt fallback chain, bilingual UI (en + zh-CN), translated note templates (en + zh-CN + zh-TW), distinct plugin id from upstream so both can coexist. - [x] **0.2** โ€” Incremental sync. Persistent TMDB cache (stale-while-revalidate, 90-day TTL with jitter) + Trakt history-state cursor. Steady-state sync drops from minutes to single-digit seconds. โ†’ [spec 0001](docs/specs/0001-incremental-sync.md) - [x] **0.3** โ€” Diff-based writes. Only rewrite notes whose frontmatter or managed body section actually changed; cross-device sync layers stop shuffling 1200 files per sync. 0.3.x also added: TMDB API key Test button + warning banner when metadata language is set without a key, and two-tier filename disambiguation for localized-title collisions (e.g. 5 shows all called "้‡็”Ÿ" no longer fight for the same filename). โ†’ [spec 0002](docs/specs/0002-diff-based-write.md) - [x] **0.4** โ€” Directory submission preparation. Plugin id renamed `obsidian-sync-trakt` โ†’ `sync-trakt` (Obsidian directory bot rejects ids containing "obsidian"), `minAppVersion` tightened to 1.6.6, and transparent automatic data migration from the legacy folder on first launch. โ†’ [spec 0004](docs/specs/0004-obsidian-directory-submission.md) - [x] **0.5** โ€” Device-local settings + automatic cleanup. Per-setting cloud-icon toggle so each setting can opt out of cross-device sync; auto-cleanup of the legacy folder's binary files (keeping data.json as a safety net) so users don't see two duplicate plugin entries in their settings. โ†’ [spec 0003](docs/specs/0003-device-local-settings.md) - [x] **0.6** โ€” Tabbed settings UI + 11 bundled note template languages. Settings page reorganized into 4 tabs (General / Notes / Sync / Daily Notes). Note templates expanded from 3 to 11 hand-curated languages (+ ja, ko, fr, de, it, es, pt-BR, ru). Template-language dropdown filtered to only show bundled languages. โ†’ [spec 0005](docs/specs/0005-settings-ui-tabs.md) + [spec 0007](docs/specs/0007-template-language-expansion.md) - [x] **0.7** โ€” Daily Notes integration. Auto-inserts per-event lines (watched / watchlist / favorited / rated) into your Daily Note for every sync, chronologically sorted, in your chosen template language. Add-only safety for past days; today is overwritten as the day progresses. โ†’ [spec 0006](docs/specs/0006-daily-notes-integration.md) - [x] **0.8** โ€” Daily Notes **incremental sync mode**. Opt-in mode where today's marker region is append-only (instead of full-replace), so any annotations you write inside survive every sync. โ†’ [spec 0008](docs/specs/0008-metadata-language-fallback.md) intro discusses the trade-off; the actual mode lives in spec 0006. - [x] **0.9** โ€” **Metadata language fallback**. Adds a "fallback language" dropdown under Metadata language. When set, the primary becomes a strict match (no silent zh-TW substitution for zh-CN) and falls through to the user-chosen fallback before keeping the English original. โ†’ [spec 0008](docs/specs/0008-metadata-language-fallback.md) - [x] **1.0** โ€” **Filename auto-rename + persistent What's-new modal + date-range backfill**. Changing metadata language now auto-renames existing notes on the next sync (Obsidian internal links auto-update). Every new release pops a one-shot "What's new" modal showing version history since last seen. Manual backfill replaced with a date-range picker (start/end + quick presets). โ†’ [spec 0009](docs/specs/0009-filename-rename.md) - [x] **1.1** โ€” **Vault-slim runtime cache architecture**. Large TMDB and detailed-history caches moved outside the vault, keeping `data.json` small for Obsidian Sync while preserving multi-device rebuild behavior. โ†’ [spec 0010](docs/specs/0010-local-runtime-cache.md) - [x] **1.2** โ€” **Daily Notes-only auto-sync**. Daily Notes can refresh on their own interval without media-note writes, sharing the same Trakt/TMDB data path and sync lock as full sync. โ†’ [spec 0011](docs/specs/0011-daily-notes-auto-sync.md) - [ ] **Future** โ€” More plugin UI translations (currently en + zh-CN) on demand; additional bundled template languages on request. ## ๐Ÿค Acknowledgements This plugin was originally inspired by [sarimabbas/traktr](https://github.com/sarimabbas/traktr) (MIT licensed), which provided the initial Trakt OAuth scaffolding. Substantial subsequent work โ€” detailed watch-history aggregation, metadata localization with translation-fallback chains, bilingual UI, bounded-concurrency fetching with live progress reporting, machine-managed body sections, the translation-aware template renderer, multi-language docs โ€” has reshaped most of the codebase into a fundamentally different architecture. Thanks to [Sarim Abbas](https://github.com/sarimabbas) for the starting point. The original work's MIT copyright notice is preserved verbatim in [LICENSE](LICENSE) alongside this project's own. ## ๐Ÿ“„ License MIT โ€” see [LICENSE](LICENSE). --- Author: [o1xhack](https://github.com/o1xhack)