An Xtream activity row is built from its `content` row, and the catalog
endpoints that create those rows carry only a title and a poster. So the
dashboard hero and the recommendations rail rebuilt their TMDB query from the
display title alone, while the detail view had searched with the original
title, the release date and often a TMDB id. Without a year
`pickConfidentMatch` requires a globally unique exact title, which common
titles never satisfy — "Inside Out" matches several films and resolves to
nothing, every time.
Three `content` columns close that gap next to the existing `backdrop_url`:
`tmdb_id`, `release_year`, `original_title`. The detail views back-fill them
from what is on screen, the activity SELECTs project them, and
`buildDashboardTmdbAttempts` reads them back. Stalker keeps stating the same
facts through its stored entry, and rows with neither keep the title-only
fallback.
Measured against a real profile before building: of 58 distinct Xtream
movie/series activity rows, 16 (28%) produce a year-less key — the cohort
where a miss is guaranteed rather than likely.
Contracts worth preserving:
- Per-column, never overwrite. Enrichment supplies the pieces at different
times, so a row-level guard would let the first arrival block every later
one forever.
- `release_year` is the year the PROVIDER stated. The TMDB merge fills the
date field when the provider left it empty, so it marks its own
substitution with `tmdb_supplied_release_date` and the extractor skips
those — making contamination structurally impossible rather than avoided.
- The id is stored unvetted: every consumer re-gates it through
`assessProviderId`, which re-decides per lookup where a write-time verdict
would be permanent.
- No media-type column — for Xtream the catalog files movies and series
apart, so `content.type` already is the media type.
Worker requests now await `getDatabase()` before dispatching. The renderer
loads before `initDatabase()` and the worker opens the database file without
running migrations, so a query issued during startup on an upgraded install
could otherwise hit a schema whose new columns do not exist yet.
Not covered: the PWA, whose catalog cache is rebuilt from the API on every
load, so a stored id would never outlive the detail view that resolved it.
Clearing all recents of a given content type fired N concurrent IPC calls,
each opening its own implicit transaction in the recently_viewed table.
For users with hundreds of recently-watched VOD/series rows this added
real overhead even though the UI updates optimistically.
Add a new DB_REMOVE_RECENT_ITEMS_BATCH path end-to-end:
- removeRecentItemsBatch() Drizzle op: one transaction, one prepared
statement reused per row
- Wire through worker → IPC handler → preload → window.electron typings
→ DatabaseService
- UnifiedRecentDataService.removeRecentItemsBatch() groups items by
source. Xtream items go through the new batch IPC. M3U/Stalker items
still go per-playlist because they update a JSON column on the
playlist row, not the recently_viewed table — but they now run in
parallel with the Xtream batch via a single Promise.all.
- Single call site updated: unified-collection-page "Clear all of type"
confirmation handler.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 4bfb62f988b7
- Added suppressErrorLog option to EPG API calls in withEpg feature.
- Introduced resolvePortalStatus function to streamline portal status checks in withPortal feature.
- Updated checkPortalStatus to return PortalStatusType instead of void.
- Enhanced XtreamStore to preserve cancelled content initialization block.
- Expanded XtreamState to include contentInitBlockReason for better state management.
- Added XtreamContentGateComponent to manage content initialization states.
- Implemented tests for XtreamContentGateComponent to ensure correct rendering based on contentInitBlockReason.
- Created PlaylistRefreshService to handle playlist refresh operations and events.
- Introduced new IPC commands for playlist refresh functionality.
- Added interfaces for playlist refresh events and payloads to improve type safety.
feat(recent-view): implement search term filtering for recent items
fix(dashboard-data): update return type for navigation state methods
chore(jest): add jest configuration for workspace shell feature
refactor(global-favorites): migrate global favorites list to shared UI
refactor(global-favorites): remove global favorites page component and its styles
refactor(global-favorites): update unified favorite channel interface to use shared util
test(workspace-shell): setup test environment for workspace shell feature
Entire-Checkpoint: 0e4488af6c76
Add the ability to hide irrelevant or empty categories in Xtream playlists.
Users can now manage category visibility through a dialog accessible from
the sidebar header in both VOD/Series and Live TV views.
Features:
- New category management dialog with search filter and select/deselect all
- Visibility settings persisted to database per playlist
- Hidden categories are filtered from sidebar navigation
- New categories added during playlist refresh default to visible
- Database migration for existing installations
Files changed:
- Database: schema.ts, connection.ts (hidden column + migration)
- Backend: category.events.ts, main.preload.ts (IPC handlers)
- Frontend: new dialog component, store method, UI integration
- Translations: en.json
- Documentation: docs/architecture/category-management.md
Save and restore favorited and recently viewed Xtream items when
deleting and re-importing playlist content.
- Return favoritedXtreamIds and recentlyViewedXtreamIds from
deleteXtreamPlaylistContent so callers can capture user data before
.
- Add restoreXtreamUserData to the database service to allow restoring
favorites and recently viewed entries after a refresh.
- Query and collect xtreamIds and timestamps for favorites and recently
viewed items in the backend before deleting content.
- Persist the captured user data to localStorage in the recent playlists
component so it can be used to restore state after re-importing the
playlist.
- Keep existing playlist metadata update flow intact.
This prevents loss of user-specific favorites and recent history when
refreshing Xtream playlists.
a dedicated refresh button and workflow for Xtream in the
recent playlists UI. Show a refresh icon only when the playlist has a
serverUrl. For Xtream playlists, prompt the user with a confirmation
dialog, delete locally cached categories and streams, show a toast that
the refresh started, and navigate to the playlist to trigger re-import.
Keep existing refresh IPC logic for non-Xtream (M3U/local) playlists.
Also add English translations for the Xtream refresh tooltip and dialog
messages, and surface errors via snackbar on failure.
This enables safe re-importing of remote Xtream playlists while preserving
favorites and recent items.