From e6a34593d4436007e28fe8a690d0caaca6d19841 Mon Sep 17 00:00:00 2001 From: 4gray Date: Thu, 26 Dec 2024 14:59:18 +0100 Subject: [PATCH] refactor(xtream): streamline fetching of VOD and serial details with metadata --- .../serial-details.component.ts | 18 +- .../vod-details/vod-details.component.ts | 17 +- src/app/xtream-tauri/xtream.store.ts | 204 +++++++++++++----- 3 files changed, 163 insertions(+), 76 deletions(-) diff --git a/src/app/xtream-tauri/serial-details/serial-details.component.ts b/src/app/xtream-tauri/serial-details/serial-details.component.ts index fe2f4642..a44dd57b 100644 --- a/src/app/xtream-tauri/serial-details/serial-details.component.ts +++ b/src/app/xtream-tauri/serial-details/serial-details.component.ts @@ -35,18 +35,14 @@ export class SerialDetailsComponent { ngOnInit(): void { const { categoryId, serialId } = this.route.snapshot.params; - this.xtreamStore.getSerialDetails(serialId).then((currentSerial) => { - this.xtreamStore.setSelectedCategory(Number(categoryId)); - this.xtreamStore.setSelectedItem({ - ...currentSerial, - series_id: serialId, - }); - - this.xtreamStore.checkFavoriteStatus( - serialId, - this.xtreamStore.currentPlaylist().id - ); + this.xtreamStore.fetchSerialDetailsWithMetadata({ + serialId, + categoryId, }); + this.xtreamStore.checkFavoriteStatus( + serialId, + this.xtreamStore.currentPlaylist().id + ); } playEpisode(episode: XtreamSerieEpisode) { diff --git a/src/app/xtream-tauri/vod-details/vod-details.component.ts b/src/app/xtream-tauri/vod-details/vod-details.component.ts index c4a81621..c5c87b0c 100644 --- a/src/app/xtream-tauri/vod-details/vod-details.component.ts +++ b/src/app/xtream-tauri/vod-details/vod-details.component.ts @@ -41,18 +41,11 @@ export class VodDetailsComponent implements OnInit, OnDestroy { ngOnInit(): void { const { categoryId, vodId } = this.route.snapshot.params; - this.xtreamStore.getVodDetails(vodId).then((currentVod) => { - this.xtreamStore.setSelectedCategory(Number(categoryId)); - this.xtreamStore.setSelectedItem({ - ...currentVod, - stream_id: vodId, - }); - // Check favorite status after setting selected item - this.xtreamStore.checkFavoriteStatus( - vodId, - this.xtreamStore.currentPlaylist().id - ); - }); + this.xtreamStore.fetchVodDetailsWithMetadata({ vodId, categoryId }); + this.xtreamStore.checkFavoriteStatus( + vodId, + this.xtreamStore.currentPlaylist().id + ); } ngOnDestroy() { diff --git a/src/app/xtream-tauri/xtream.store.ts b/src/app/xtream-tauri/xtream.store.ts index 4dc3d91d..483b2360 100644 --- a/src/app/xtream-tauri/xtream.store.ts +++ b/src/app/xtream-tauri/xtream.store.ts @@ -9,11 +9,23 @@ import { } from '@ngrx/signals'; import { rxMethod } from '@ngrx/signals/rxjs-interop'; import { Store } from '@ngrx/store'; -import { EMPTY, from, lastValueFrom, pipe, switchMap, tap } from 'rxjs'; +import { + catchError, + combineLatestWith, + EMPTY, + from, + lastValueFrom, + pipe, + switchMap, + tap, +} from 'rxjs'; import { XtreamCodeActions } from '../../../shared/xtream-code-actions'; +import { XtreamSerieDetails } from '../../../shared/xtream-serie-details.interface'; +import { XtreamVodDetails } from '../../../shared/xtream-vod-details.interface'; import { DataService } from '../services/data.service'; import { DatabaseService } from '../services/database.service'; import { selectActivePlaylist } from '../state/selectors'; +import { XtreamAccountInfo } from './account-info/account-info.interface'; import { withFavorites } from './with-favorites.feature'; import { withRecentItems } from './with-recent-items'; import { XtreamState } from './xtream-state'; @@ -40,6 +52,7 @@ const initialState: XtreamState = { epgItems: [], hideExternalInfoDialog: localStorage.getItem('hideExternalInfoDialog') === 'true', + portalStatus: 'unavailable', }; /** to decode epg */ @@ -436,7 +449,6 @@ export const XtreamStore = signalStore( const setPage = (page: number) => patchState(store, { page }); const setLimit = (limit: number) => patchState(store, { limit }); const setSelectedCategory = (categoryId: number) => { - console.log(categoryId); patchState(store, { selectedCategoryId: Number(categoryId), page: 1, @@ -459,56 +471,77 @@ export const XtreamStore = signalStore( ) ) ); - const getVodDetails = async (vodId: string) => { - const currentPlaylist = store.currentPlaylist(); - - const password = currentPlaylist?.password; - const url = `${currentPlaylist?.serverUrl}/player_api.php`; - const username = currentPlaylist?.username; - console.log('Fetching VOD details...', password, url, username); - - const queryParams = { - action: XtreamCodeActions.GetVodInfo, - username, - password, - vod_id: vodId, - }; - - const remoteData = await dataService.fetchData( - url, - queryParams - ); - - return remoteData; - }; - - const getSerialDetails = async (serialId: string) => { - const currentPlaylist = store.currentPlaylist(); - - const password = currentPlaylist?.password; - const url = `${currentPlaylist?.serverUrl}/player_api.php`; - const username = currentPlaylist?.username; - console.log( - 'Fetching Series details...', - password, - url, - username - ); - - const queryParams = { - action: XtreamCodeActions.GetSeriesInfo, - username, - password, - series_id: serialId, - }; - - const remoteData = await dataService.fetchData( - url, - queryParams - ); + const fetchVodDetailsWithMetadata = rxMethod<{ + vodId: string; + categoryId: number; + }>( + pipe( + combineLatestWith(oldStore.select(selectActivePlaylist)), + switchMap(([{ vodId, categoryId }, playlist]) => { + if (!playlist) return EMPTY; + + return from( + dataService.fetchData( + `${playlist.serverUrl}/player_api.php`, + { + action: XtreamCodeActions.GetVodInfo, + username: playlist.username, + password: playlist.password, + vod_id: vodId, + } + ) + ).pipe( + tap((currentVod: XtreamVodDetails) => { + patchState(store, { + selectedCategoryId: Number(categoryId), + }); + patchState(store, { + selectedItem: { + ...currentVod, + stream_id: vodId, + }, + }); + }) + ); + }) + ) + ); - return remoteData; - }; + const fetchSerialDetailsWithMetadata = rxMethod<{ + serialId: string; + categoryId: number; + }>( + pipe( + combineLatestWith(oldStore.select(selectActivePlaylist)), + switchMap(([{ serialId, categoryId }, playlist]) => { + if (!playlist) return EMPTY; + + return from( + dataService.fetchData( + `${playlist.serverUrl}/player_api.php`, + { + action: XtreamCodeActions.GetSeriesInfo, + username: playlist.username, + password: playlist.password, + series_id: serialId, + } + ) + ).pipe( + tap((currentSerial: XtreamSerieDetails) => { + patchState(store, { + selectedCategoryId: Number(categoryId), + }); + patchState(store, { + selectedItem: { + ...currentSerial, + series_id: serialId, + }, + }); + }) + ); + }) + ) + ); const initializeContent = async () => { patchState(store, { isImporting: true }); @@ -571,6 +604,70 @@ export const XtreamStore = signalStore( } }; + const checkPortalStatus = rxMethod( + pipe( + combineLatestWith(oldStore.select(selectActivePlaylist)), + switchMap(([_, playlist]) => { + if (!playlist) return EMPTY; + + return from( + dataService.fetchData( + `${playlist.serverUrl}/player_api.php`, + { + username: playlist.username, + password: playlist.password, + action: 'get_account_info', + } + ) + ).pipe( + tap((response: XtreamAccountInfo) => { + console.log( + 'Portal status response:', + response + ); + + if (!response?.user_info?.status) { + patchState(store, { + portalStatus: 'unavailable', + }); + return; + } + + if (response.user_info.status === 'Active') { + const expDate = new Date( + parseInt(response.user_info.exp_date) * + 1000 + ); + if (expDate < new Date()) { + patchState(store, { + portalStatus: 'expired', + }); + } else { + patchState(store, { + portalStatus: 'active', + }); + } + } else { + patchState(store, { + portalStatus: 'inactive', + }); + } + }), + catchError((error) => { + console.error( + 'Error checking portal status:', + error + ); + patchState(store, { + portalStatus: 'unavailable', + }); + return EMPTY; + }) + ); + }) + ) + ); + return { fetchXtreamPlaylist, fetchLiveCategories, @@ -585,8 +682,8 @@ export const XtreamStore = signalStore( setSelectedContentType, setSelectedItem, searchContent: searchContentMethod, - getVodDetails, - getSerialDetails, + fetchVodDetailsWithMetadata, + fetchSerialDetailsWithMetadata, initializeContent, updatePlaylist(playlist: any) { patchState(store, { @@ -643,6 +740,7 @@ export const XtreamStore = signalStore( ); patchState(store, { hideExternalInfoDialog }); }, + checkPortalStatus, }; } )