seriesPrimaryAction now accepts watchedKeys and synthesizes watched records
for episodes resolved via anime videoId fallback. This fixes next-up showing
S1E1 when entering via franchise parent MAL ID (e.g. mal:60636) while all
episodes are correctly shown as watched in the UI.
When reconcileSeriesWatchedState removes the series-level watched marker,
it calls delete() with a WatchedItem without season/episode. This was being
sent to Simkl as a show-level removal, which deleted the entire entry from
the user's library. Now we filter out items without season/episode — those
are local-only reconciliation markers.
Write path:
- resolveAnimeEpisodeForSimkl() overrides IDs from video ID (Path B)
- Only the anime-specific ID from videoId is sent (no shared IDs)
- videoId flows through WatchedItem → push/delete → Simkl API
Read path:
- animeAlternateWatchedKeys() emits extra watched keys under alternate IDs
- Observer on Simkl snapshot keeps watchedKeys reactive
- SimklAnimeWatchedFallback handles franchise-parent content IDs
- Optimistic removals prevent stale fallback reads
Bootstrap:
- full_anime_seasons + episode_tvdb_id + language=en for both bootstrap and changes
Library:
- Anime entries use type 'anime' and supportedContentTypes includes 'anime'
Infrastructure:
- WatchedItem.videoId field for episode video ID propagation
- WatchedSyncAdapter.observeExtraWatchedKeys() for reactive extra keys
- WatchedRepository observes provider extra keys and re-publishes
The Cloud view only had provider and type filters, so finding a specific
release in a large debrid account meant scrolling the whole list, even
though the item names and file names are already loaded on the client.
Adds a local search field under the toolbar that narrows the already
loaded items. It matches the item name or any of its file names, since
the useful identifier is often in the filename rather than the title,
and it stacks on top of the existing provider and type filters.