feat(xtream): Xtream playlist refresh workflow

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.
This commit is contained in:
4gray committed 2025-10-18 21:55:48 +02:00
1 parent 0a934d2ac6
commit 461e2e2e7e
8 files changed
+160 -60

No files matched your search

@@ -3,7 +3,6 @@ import {
AfterViewInit,
Component,
effect,
ElementRef,
inject,
Inject,
Optional,
@@ -55,7 +54,7 @@ interface SearchResultsData {
styleUrls: ['./search-results.component.scss'],
})
export class SearchResultsComponent implements AfterViewInit {
@ViewChild('searchInput') searchInput!: ElementRef;
@ViewChild(SearchFormComponent) searchFormComponent!: SearchFormComponent;
readonly xtreamStore = inject(XtreamStore);
readonly router = inject(Router);
readonly activatedRoute = inject(ActivatedRoute);
@@ -105,7 +104,7 @@ export class SearchResultsComponent implements AfterViewInit {
ngAfterViewInit() {
this.xtreamStore.setSelectedContentType(undefined);
setTimeout(() => {
this.searchInput.nativeElement.focus();
this.searchFormComponent?.focusSearchInput();
});
}
+50 -44
View File
@@ -568,51 +568,57 @@ export const XtreamStore = signalStore(
try {
console.log('Starting content initialization...');
console.log('Fetching live categories...');
await lastValueFrom(
fetchCategories(
XtreamCodeActions.GetLiveCategories,
'liveCategories',
'live'
)
);
await lastValueFrom(
fetchCategories(
XtreamCodeActions.GetVodCategories,
'vodCategories',
'movies'
)
);
await lastValueFrom(
fetchCategories(
XtreamCodeActions.GetSeriesCategories,
'serialCategories',
'series'
)
);
// Fetch all categories in parallel
console.log('Fetching categories...');
await Promise.all([
lastValueFrom(
fetchCategories(
XtreamCodeActions.GetLiveCategories,
'liveCategories',
'live'
)
),
lastValueFrom(
fetchCategories(
XtreamCodeActions.GetVodCategories,
'vodCategories',
'movies'
)
),
lastValueFrom(
fetchCategories(
XtreamCodeActions.GetSeriesCategories,
'serialCategories',
'series'
)
),
]);
// Fetch all content in parallel
console.log('Fetching content...');
await lastValueFrom(
fetchStreams(
XtreamCodeActions.GetLiveStreams,
'liveStreams',
'live'
)
);
await lastValueFrom(
fetchStreams(
XtreamCodeActions.GetVodStreams,
'vodStreams',
'movie'
)
);
await lastValueFrom(
fetchStreams(
XtreamCodeActions.GetSeries,
'serialStreams',
'series'
)
);
await Promise.all([
lastValueFrom(
fetchStreams(
XtreamCodeActions.GetLiveStreams,
'liveStreams',
'live'
)
),
lastValueFrom(
fetchStreams(
XtreamCodeActions.GetVodStreams,
'vodStreams',
'movie'
)
),
lastValueFrom(
fetchStreams(
XtreamCodeActions.GetSeries,
'serialStreams',
'series'
)
),
]);
console.log('Content initialization completed');
} catch (error) {
console.error(
@@ -627,7 +633,7 @@ export const XtreamStore = signalStore(
const checkPortalStatus = rxMethod<void>(
pipe(
combineLatestWith(oldStore.select(selectActivePlaylist)),
switchMap(([_, playlist]) => {
switchMap(([, playlist]) => {
if (!playlist) return EMPTY;
return from(
+7
View File
@@ -54,6 +54,13 @@
},
"UPDATED": "Updated",
"REFRESH": "Refresh playlist",
"REFRESH_XTREAM": "Refresh Xtream playlist from remote",
"REFRESH_XTREAM_DIALOG": {
"TITLE": "Refresh Xtream Playlist",
"MESSAGE": "This will delete locally cached categories and streams and re-import everything from the remote server. Your favorites and recently viewed items will be preserved. Are you sure you want to continue?",
"STARTED": "Refresh started. Navigating to playlist...",
"ERROR": "Failed to refresh playlist. Please try again."
},
"GLOBAL_FAVORITES": "Global favorites",
"GLOBAL_FAVORITES_DESCRIPTION": "Auto-generated playlist with aggregated favorites from all playlists",
"MY_PLAYLISTS": "My playlists",