Every dashboard title carried a "Xtream · Series" / "Stalker · Movie" subtitle. Provider kind and content kind are the app's own taxonomy, not a property of the title, and they are identical on every card in a rail — so the one line that could tell two cards apart said nothing. The hero now shows the source name alone, through `playlistDisplayLabel` (a stored playlist name is routinely the pasted URL with credentials, or a MAC). Continue Watching cards show what actually varies: the "S1·E5" chip plus "12 min left". Favorites keep the title alone, Recently Added keeps the source name, and a meta row with nothing in it is no longer rendered. Stalker shows filed under Movies had no badge, no progress and no resume. An embedded-VOD row announces its episodes through a `series[]` array and carries no `is_series` flag, so `extractStalkerItemType` reports `movie` on purpose — the item must keep routing to the VOD catalog — while its progress is a set of episode positions keyed by the parent id, which the dashboard was looking up as a single `vod` row and never finding. Split the two questions: `PortalActivityItem.watch_kind` records the progress model when it differs from the routing type, and every reader that has to choose goes through `resolvePortalActivityWatchKind` instead of `type`. That makes the resume handoff reachable for Stalker, so wire it through `STALKER_SERIES_RESUME_TARGET`: consumed once after the series positions are read, hydrating a lazy Ministra season first with a bounded two-attempt retry, and playing nothing at all when the position read failed rather than restarting the episode from zero. Also fixes the global-recent route template, which bound `[seriesResume]` only on its Xtream branch. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Workspace Dashboard Feature
This library owns the workspace dashboard rails UI. The dashboard is a read-only surface over existing playlist, recent, favorites, EPG, and Xtream catalog data; it should not introduce Electron IPC, SQLite schema, or route contracts on its own.
Dashboard Surfaces
The dashboard renders a surface only when the matching setting is enabled. Data rails also require the underlying data slice to have at least one item.
heroshows the large top banner for the most recent global item. When that item is a live TV channel, the hero looks up the current XMLTV programme and displays the programme title, time range, and EPG progress bar when data is available.continueWatchingshows recent movies and series fromDashboardDataService.globalRecentVodItems()using cover cards with playback progress when a saved resume position is available.liveFavoritesshows favorited live TV channels fromDashboardDataService.globalFavoriteLiveItems()using the channel layout with EPG title, time range, and progress when XMLTV data is available.recentlyWatchedLiveshows recently watched live TV channels fromDashboardDataService.globalRecentLiveItems()using the same channel layout.favoriteMoviesAndSeriesshows favorited movies and series fromDashboardDataService.globalFavoriteItems(), excluding live favorites, using cover cards.recentSourcesshows recently used playlist/source entries.xtreamRecentlyAddedshows recently added Xtream catalog items.tmdbRecommendationsshows "Because you watched X" — TMDB recommendations seeded from recently watched movies/series, kept to titles that exist in an imported Xtream library. Needs the TMDB opt-in and the Electron DB worker (hidden in the PWA), and hides itself below five matched cards. Data:DashboardRecommendationsServiceinworkspace/dashboard/data-access.tmdbTrendingshows TMDB's weekly trending titles, matched against the imported Xtream libraries. Same TMDB/Electron gating; unmatched cards open the global search prefilled. Data:DashboardTrendingService.
Settings
Per-surface visibility lives on Settings.dashboardRails as a
DashboardRailsSettings object. Every surface defaults to enabled. Stored
settings are deep-merged with DEFAULT_DASHBOARD_RAILS_SETTINGS by
SettingsStore, so existing users and older partial settings keep newly added
surfaces visible unless they explicitly turn them off.
The global showDashboard flag remains a top-level Settings property because
workspace startup and route guards already depend on that contract. The Settings
UI groups showDashboard and the per-surface checkboxes in the Dashboard
section. When showDashboard is off, the per-surface checkboxes are disabled
because the dashboard route itself is hidden.
Navigation
Rail cards use the navigation state provided by DashboardDataService for the
underlying item. Rail "See all" links may also pass router state:
- live rails open the relevant collection on Live TV.
- cover rails for movies/series open Global Recent or Global Favorites on Movies when movie items are present, otherwise on Series.
This keeps the global collection pages from defaulting to Live TV when a dashboard rail is clearly about movies or series.