From 9e1ef0b0bd922938a9bd8202947627d21fcd73ac Mon Sep 17 00:00:00 2001 From: 4gray Date: Sun, 8 Mar 2026 15:48:37 +0100 Subject: [PATCH] refactor: enhance playlist favorites handling and introduce portal activity items - Updated the `selectFavorites` selector to filter favorites ensuring they are strings. - Added new interfaces for `PortalActivityItem`, `PortalRecentItem`, and `PortalFavoriteItem` to standardize activity item representation. - Introduced `StalkerPortalItem` interface to represent items in Stalker portals. - Created utility functions for extracting and normalizing data from Stalker portal items. - Refactored `DashboardDataService` to utilize new interfaces and utility functions for managing recent and favorite items. - Removed deprecated mapping functions and replaced them with direct usage of new interfaces. - Added navigation utilities for recent and favorite items to streamline routing logic. --- .../video-player/video-player.component.ts | 55 +- .../category-view.component.scss | 5 +- .../features/with-stalker-player.feature.ts | 24 +- .../workspace-context-panel.component.html | 12 + .../workspace-context-panel.component.scss | 16 +- .../workspace-context-panel.component.ts | 57 +- .../workspace/workspace-shell.component.html | 64 +- .../workspace/workspace-shell.component.scss | 26 +- .../workspace/workspace-shell.component.ts | 94 +-- .../category-content-view.component.html | 62 +- .../category-content-view.component.ts | 40 +- .../app/xtream-electron/with-recent-items.ts | 423 ++++++------- libs/m3u-state/src/lib/selectors.ts | 4 +- libs/shared/interfaces/src/index.ts | 7 +- .../interfaces/src/lib/playlist.interface.ts | 8 +- .../src/lib/portal-activity-item.interface.ts | 32 + .../src/lib/stalker-item.normalizer.ts | 119 ++++ .../src/lib/stalker-portal-item.interface.ts | 29 + .../src/lib/dashboard-data.service.ts | 588 ++---------------- .../data-access/src/lib/dashboard-mappers.ts | 169 +++++ .../src/lib/dashboard-navigation.utils.ts | 186 ++++++ 21 files changed, 1041 insertions(+), 979 deletions(-) create mode 100644 libs/shared/interfaces/src/lib/portal-activity-item.interface.ts create mode 100644 libs/shared/interfaces/src/lib/stalker-item.normalizer.ts create mode 100644 libs/shared/interfaces/src/lib/stalker-portal-item.interface.ts create mode 100644 libs/workspace/dashboard/data-access/src/lib/dashboard-mappers.ts create mode 100644 libs/workspace/dashboard/data-access/src/lib/dashboard-navigation.utils.ts diff --git a/apps/web/src/app/home/video-player/video-player.component.ts b/apps/web/src/app/home/video-player/video-player.component.ts index 1cc8d2b53..23ef7a52a 100644 --- a/apps/web/src/app/home/video-player/video-player.component.ts +++ b/apps/web/src/app/home/video-player/video-player.component.ts @@ -234,22 +234,17 @@ export class VideoPlayerComponent implements OnInit, OnDestroy { }) ); - if ( - playlist.favorites && - playlist.favorites.length > 0 - ) { - this.store.dispatch( - FavoritesActions.setFavorites({ - channelIds: playlist.favorites, - }) - ); - } else { - this.store.dispatch( - FavoritesActions.setFavorites({ - channelIds: [], - }) - ); - } + const stringFavs = ( + playlist.favorites ?? [] + ).filter( + (f): f is string => + typeof f === 'string' + ); + this.store.dispatch( + FavoritesActions.setFavorites({ + channelIds: stringFavs, + }) + ); }) ); } else if (params['id']) { @@ -280,23 +275,17 @@ export class VideoPlayerComponent implements OnInit, OnDestroy { ); // Load favorites from the playlist - if ( - playlist.favorites && - playlist.favorites.length > 0 - ) { - this.store.dispatch( - FavoritesActions.setFavorites({ - channelIds: playlist.favorites, - }) - ); - } else { - // Clear favorites if playlist has none - this.store.dispatch( - FavoritesActions.setFavorites({ - channelIds: [], - }) - ); - } + const stringFavs = ( + playlist.favorites ?? [] + ).filter( + (f): f is string => + typeof f === 'string' + ); + this.store.dispatch( + FavoritesActions.setFavorites({ + channelIds: stringFavs, + }) + ); }) ); } diff --git a/apps/web/src/app/shared/components/category-view/category-view.component.scss b/apps/web/src/app/shared/components/category-view/category-view.component.scss index 48653101b..6636ada5c 100644 --- a/apps/web/src/app/shared/components/category-view/category-view.component.scss +++ b/apps/web/src/app/shared/components/category-view/category-view.component.scss @@ -13,13 +13,16 @@ .category-item { cursor: pointer; width: auto; - transition: all 0.2s ease; .item-count { opacity: 0.6; font-size: 0.85em; margin-left: 4px; } + + &:hover:not(.category-item--selected) { + background: var(--app-selection-surface); + } } .category-item--selected .item-count { diff --git a/apps/web/src/app/stalker/stores/features/with-stalker-player.feature.ts b/apps/web/src/app/stalker/stores/features/with-stalker-player.feature.ts index e9ac495e2..c29fe39af 100644 --- a/apps/web/src/app/stalker/stores/features/with-stalker-player.feature.ts +++ b/apps/web/src/app/stalker/stores/features/with-stalker-player.feature.ts @@ -11,6 +11,7 @@ import { ResolvedPortalPlayback, STALKER_REQUEST, StalkerPortalActions, + StalkerPortalItem, } from 'shared-interfaces'; import { PlayerService } from '../../../services/player.service'; import { createLogger } from '../../../shared/utils/logger'; @@ -28,8 +29,7 @@ import { type StalkerContentType = 'itv' | 'vod' | 'series'; -interface StalkerPlayableItem { - id?: string | number; +interface StalkerPlayableItem extends StalkerPortalItem { cmd?: string; has_files?: unknown; } @@ -363,27 +363,15 @@ export function withStalkerPlayer() { storeState.addToRecentlyViewed({ ...item, id: item.id, - cover: - (item as { logo?: string }).logo ?? - (item as { cover?: string }).cover, - title: - (item as { o_name?: string }).o_name || - (item as { name?: string }).name || - (item as { title?: string }).title, + cover: item.logo ?? item.cover, + title: item.o_name || item.name || item.title, }); } return { streamUrl, - title: - (item as { o_name?: string }).o_name || - (item as { name?: string }).name || - (item as { title?: string }).title || - '', - thumbnail: - (item as { logo?: string }).logo ?? - (item as { cover?: string }).cover ?? - null, + title: item.o_name || item.name || item.title || '', + thumbnail: item.logo ?? item.cover ?? null, headers, userAgent: headers['User-Agent'] || diff --git a/apps/web/src/app/workspace/workspace-context-panel.component.html b/apps/web/src/app/workspace/workspace-context-panel.component.html index 338491b9c..bba262aee 100644 --- a/apps/web/src/app/workspace/workspace-context-panel.component.html +++ b/apps/web/src/app/workspace/workspace-context-panel.component.html @@ -2,6 +2,18 @@

{{ title() }}

+ @if (isXtreamCategories()) { + + }