- Stats dashboard redesign design and implementation plans - Episode detail and Anki card link design - Internal knowledge base restructure - Backlog tasks for testing, verification, and occurrence tracking
4.6 KiB
Immersion Anime Metadata Design
Problem: The immersion database is keyed around videos and sessions, which makes it awkward to present anime-centric stats such as per-anime totals, episode progress, and season breakdowns. We need first-class anime metadata without requiring migration or backfill support for existing databases.
Goals:
- Add anime-level identity that can be shared across multiple video files and rewatches.
- Persist parsed episode/season metadata so stats can group by anime, season, and episode.
- Use existing filename parsing conventions:
guessitfirst, built-in parser fallback. - Create provisional anime rows even when AniList lookup fails.
- Keep the change additive and forward-looking; do not spend time on migrations/backfill.
Non-Goals:
- Backfilling or migrating existing user databases.
- Perfect anime identity resolution across every edge case.
- Building the entire new stats UI in this design doc.
- Replacing existing
canonical_titleor current video/session APIs immediately.
Recommended Approach
Add a new imm_anime table for anime-level metadata and link each imm_videos row to one anime row through anime_id. Keep season/episode and filename-derived fields on imm_videos, because those belong to a concrete file, not the anime as a whole.
Anime rows should exist even when AniList lookup fails. In that case, use a normalized parsed-title key as provisional identity. If the same anime is resolved to AniList later, upgrade the existing anime row in place instead of creating a duplicate.
Data Model
imm_anime
One row per anime identity.
Suggested fields:
anime_id INTEGER PRIMARY KEY AUTOINCREMENTidentity_key TEXT NOT NULL UNIQUEparsed_title TEXT NOT NULLnormalized_title TEXT NOT NULLanilist_id INTEGERtitle_romaji TEXTtitle_english TEXTtitle_native TEXTepisodes_total INTEGERparser_source TEXTparser_confidence TEXTmetadata_json TEXTCREATED_DATE INTEGERLAST_UPDATE_DATE INTEGER
Identity rules:
- Resolved anime:
identity_key = anilist:<id> - Provisional anime:
identity_key = title:<normalized parsed title> - When a provisional row later gets an AniList match, update that row's
identity_keytoanilist:<id>and fill AniList metadata.
imm_videos
Keep existing video metadata. Add:
anime_id INTEGERparsed_filename TEXTparsed_title TEXTparsed_title_normalized TEXTparsed_season INTEGERparsed_episode INTEGERparsed_episode_title TEXTparser_source TEXTparser_confidence TEXTparse_metadata_json TEXT
canonical_title remains for compatibility. New fields are additive.
Parsing and Lookup Flow
During handleMediaChange(...):
- Normalize path/title with the existing tracker flow.
- Build/create the video row as today.
- Parse anime metadata:
- use
guessitagainst the basename/title when available - fallback to existing
parseMediaInfo
- use
- Use the parsed title to create/find a provisional anime row if needed.
- Attempt AniList lookup using the same guessit-first, fallback-parser approach already used elsewhere.
- If AniList lookup succeeds:
- upgrade or fill the anime row with AniList id/title metadata
- keep per-video season/episode fields on the video row
- Link the video row to
anime_idand store parsed per-video metadata.
Query Shape
Add anime-aware query functions without deleting current video/session queries:
- anime library list
- anime detail summary
- anime episode list / season breakdown
- anime sessions list
Aggregation should group by anime_id, not canonical_title, so rewatches and multiple files collapse correctly.
Edge Cases
- Multiple files for one anime: many videos may point to one anime row.
- Rewatches: same video/session history still aggregates under one anime row.
- No AniList match: keep provisional anime row keyed by normalized parsed title.
- Later AniList match: upgrade provisional row in place.
- Parser disagreement between files: season/episode remain per-video; anime identity uses AniList id or normalized parsed title.
- Remote/Jellyfin playback: use the effective title/path available to the current tracker flow and run the same parser pipeline.
Testing Strategy
Start red/green with focused DB-backed tests:
- schema test for
imm_animeand new video columns - storage test for provisional anime creation, reuse, and AniList upgrade
- service test for media-change ingest wiring
- query test for anime-level aggregation and episode breakdown
Primary verification lane for implementation: bun run test:immersion:sqlite:src, then broader repo verification as needed.