diff --git a/apps/electron-backend/src/app/events/database.events.ts b/apps/electron-backend/src/app/events/database.events.ts index 7492f6cc0..adfe89c01 100644 --- a/apps/electron-backend/src/app/events/database.events.ts +++ b/apps/electron-backend/src/app/events/database.events.ts @@ -85,6 +85,7 @@ ipcMain.handle( username?: string; password?: string; serverUrl?: string; + lastUpdated?: string; } ) => { try { diff --git a/apps/web/src/app/xtream-tauri/search-results/search-results.component.ts b/apps/web/src/app/xtream-tauri/search-results/search-results.component.ts index fdeb50fea..b3da52c84 100644 --- a/apps/web/src/app/xtream-tauri/search-results/search-results.component.ts +++ b/apps/web/src/app/xtream-tauri/search-results/search-results.component.ts @@ -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(); }); } diff --git a/apps/web/src/app/xtream-tauri/xtream.store.ts b/apps/web/src/app/xtream-tauri/xtream.store.ts index abdbf78a9..a4e37b920 100644 --- a/apps/web/src/app/xtream-tauri/xtream.store.ts +++ b/apps/web/src/app/xtream-tauri/xtream.store.ts @@ -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( pipe( combineLatestWith(oldStore.select(selectActivePlaylist)), - switchMap(([_, playlist]) => { + switchMap(([, playlist]) => { if (!playlist) return EMPTY; return from( diff --git a/apps/web/src/assets/i18n/en.json b/apps/web/src/assets/i18n/en.json index f140a02cc..ea3f05bc9 100644 --- a/apps/web/src/assets/i18n/en.json +++ b/apps/web/src/assets/i18n/en.json @@ -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", diff --git a/libs/services/src/lib/database-electron.service.ts b/libs/services/src/lib/database-electron.service.ts index 29f66709b..a35591a8d 100644 --- a/libs/services/src/lib/database-electron.service.ts +++ b/libs/services/src/lib/database-electron.service.ts @@ -92,18 +92,24 @@ export class DatabaseService { */ async updateXtreamPlaylistDetails(playlist: { id: string; - title: string; + title?: string; username?: string; password?: string; serverUrl?: string; + updateDate?: number; }): Promise { try { - await window.electron.dbUpdatePlaylist(playlist.id, { - name: playlist.title, - username: playlist.username, - password: playlist.password, - serverUrl: playlist.serverUrl, - }); + const updates: any = {}; + if (playlist.title) updates.name = playlist.title; + if (playlist.username) updates.username = playlist.username; + if (playlist.password) updates.password = playlist.password; + if (playlist.serverUrl) updates.serverUrl = playlist.serverUrl; + if (playlist.updateDate !== undefined) + updates.lastUpdated = new Date( + playlist.updateDate + ).toISOString(); + + await window.electron.dbUpdatePlaylist(playlist.id, updates); return true; } catch (error) { console.error('Error updating playlist details:', error); diff --git a/libs/services/src/lib/playlists.service.ts b/libs/services/src/lib/playlists.service.ts index 15784339a..947e4c978 100644 --- a/libs/services/src/lib/playlists.service.ts +++ b/libs/services/src/lib/playlists.service.ts @@ -97,6 +97,9 @@ export class PlaylistsService { ...(updatedPlaylist.password !== null ? { password: updatedPlaylist.password } : {}), + ...(updatedPlaylist.updateDate !== undefined + ? { updateDate: updatedPlaylist.updateDate } + : {}), }) ) ); diff --git a/libs/ui/components/src/lib/recent-playlists/playlist-item/playlist-item.component.html b/libs/ui/components/src/lib/recent-playlists/playlist-item/playlist-item.component.html index fd5795d87..1a97d0de5 100644 --- a/libs/ui/components/src/lib/recent-playlists/playlist-item/playlist-item.component.html +++ b/libs/ui/components/src/lib/recent-playlists/playlist-item/playlist-item.component.html @@ -69,8 +69,12 @@ | {{ 'HOME.PLAYLISTS.ADDED' | translate }}: {{ item.importDate | date }} - + + + | {{ 'HOME.PLAYLISTS.UPDATED' | translate }}: + {{ item.updateDate | date: 'MMMM d, yyyy, HH:mm' }} + + @@ -84,6 +88,16 @@ > sync +