fix(xtream): switch to XtreamApiService and sendRequest

This commit is contained in:
4gray committed 2026-01-12 00:52:42 +01:00
1 parent d31605da9f
commit 09b8752a3d
6 files changed
+60 -71

No files matched your search

+2 -17
View File
@@ -12,6 +12,7 @@ import {
PLAYLIST_PARSE_BY_URL,
PLAYLIST_UPDATE,
XTREAM_RESPONSE,
XTREAM_REQUEST,
} from 'shared-interfaces';
import { AppConfig } from '../../environments/environment';
@@ -69,7 +70,7 @@ export class ElectronService extends DataService {
title: string;
}
);
} else if (type === 'XTREAM_REQUEST') {
} else if (type === XTREAM_REQUEST) {
return await this.forwardXtreamRequest(
payload as { url: string; params: Record<string, string> }
);
@@ -322,20 +323,4 @@ export class ElectronService extends DataService {
getAppEnvironment(): string {
return 'electron';
}
async fetchData(url: string, queryParams: Params) {
const urlObject = new URL(url);
Object.entries(queryParams).forEach(([key, value]) => {
urlObject.searchParams.append(key, value);
});
const response = await fetch(urlObject.toString());
if (!response.ok) {
throw new Error(
`Error: ${response.statusText} (Status: ${response.status})`
);
}
const result = await response.json();
return result;
}
}
-4
View File
@@ -285,8 +285,4 @@ export class PwaService extends DataService {
getAppEnvironment(): string {
return 'pwa';
}
fetchData(url: string, queryParams: Params) {
// not implemented
}
}
@@ -5,7 +5,7 @@ import { MatListModule } from '@angular/material/list';
import { Store } from '@ngrx/store';
import { TranslatePipe } from '@ngx-translate/core';
import { selectActivePlaylist } from 'm3u-state';
import { DataService } from 'services';
import { XtreamApiService } from '../services/xtream-api.service';
import { XtreamAccountInfo } from './account-info.interface';
@Component({
@@ -20,7 +20,7 @@ export class AccountInfoComponent {
liveStreamsCount: number;
seriesCount: number;
}>(MAT_DIALOG_DATA);
private readonly dataService = inject(DataService);
private readonly xtreamApiService = inject(XtreamApiService);
private readonly store = inject(Store);
accountInfo: XtreamAccountInfo;
@@ -44,14 +44,11 @@ export class AccountInfoComponent {
if (!playlist) return;
try {
this.accountInfo = await this.dataService.fetchData(
`${playlist.serverUrl}/player_api.php`,
{
username: playlist.username,
password: playlist.password,
action: 'get_account_info',
}
);
this.accountInfo = await this.xtreamApiService.getAccountInfo({
serverUrl: playlist.serverUrl,
username: playlist.username,
password: playlist.password,
});
if (this.accountInfo) {
this.formattedExpDate = new Date(
@@ -73,4 +70,4 @@ export class AccountInfoComponent {
get isTrial(): boolean {
return this.accountInfo?.user_info?.is_trial === '1';
}
}
}
@@ -9,6 +9,7 @@ import {
XtreamSerieItem,
XtreamVodDetails,
XtreamVodStream,
XTREAM_REQUEST,
} from 'shared-interfaces';
import { XtreamAccountInfo } from '../account-info/account-info.interface';
@@ -65,8 +66,8 @@ export class XtreamApiService {
async getAccountInfo(
credentials: XtreamCredentials
): Promise<XtreamAccountInfo> {
return this.dataService.fetchData(
`${credentials.serverUrl}/player_api.php`,
return this.sendRequest(
credentials.serverUrl,
{
username: credentials.username,
password: credentials.password,
@@ -88,8 +89,8 @@ export class XtreamApiService {
series: XtreamCodeActions.GetSeriesCategories,
};
const response = await this.dataService.fetchData(
`${credentials.serverUrl}/player_api.php`,
const response = await this.sendRequest(
credentials.serverUrl,
{
action: actionMap[type],
username: credentials.username,
@@ -106,8 +107,8 @@ export class XtreamApiService {
async getLiveStreams(
credentials: XtreamCredentials
): Promise<XtreamLiveStream[]> {
const response = await this.dataService.fetchData(
`${credentials.serverUrl}/player_api.php`,
const response = await this.sendRequest(
credentials.serverUrl,
{
action: XtreamCodeActions.GetLiveStreams,
username: credentials.username,
@@ -124,8 +125,8 @@ export class XtreamApiService {
async getVodStreams(
credentials: XtreamCredentials
): Promise<XtreamVodStream[]> {
const response = await this.dataService.fetchData(
`${credentials.serverUrl}/player_api.php`,
const response = await this.sendRequest(
credentials.serverUrl,
{
action: XtreamCodeActions.GetVodStreams,
username: credentials.username,
@@ -142,8 +143,8 @@ export class XtreamApiService {
async getSeriesStreams(
credentials: XtreamCredentials
): Promise<XtreamSerieItem[]> {
const response = await this.dataService.fetchData(
`${credentials.serverUrl}/player_api.php`,
const response = await this.sendRequest(
credentials.serverUrl,
{
action: XtreamCodeActions.GetSeries,
username: credentials.username,
@@ -178,8 +179,8 @@ export class XtreamApiService {
credentials: XtreamCredentials,
vodId: string | number
): Promise<XtreamVodDetails> {
return this.dataService.fetchData(
`${credentials.serverUrl}/player_api.php`,
return this.sendRequest(
credentials.serverUrl,
{
action: XtreamCodeActions.GetVodInfo,
username: credentials.username,
@@ -196,8 +197,8 @@ export class XtreamApiService {
credentials: XtreamCredentials,
seriesId: string | number
): Promise<XtreamSerieDetails> {
return this.dataService.fetchData(
`${credentials.serverUrl}/player_api.php`,
return this.sendRequest(
credentials.serverUrl,
{
action: XtreamCodeActions.GetSeriesInfo,
username: credentials.username,
@@ -216,8 +217,8 @@ export class XtreamApiService {
streamId: number,
limit: number = 10
): Promise<EpgItem[]> {
const response: EpgResponse = await this.dataService.fetchData(
`${credentials.serverUrl}/player_api.php`,
const response: EpgResponse = await this.sendRequest(
credentials.serverUrl,
{
action: XtreamCodeActions.GetShortEpg,
username: credentials.username,
@@ -256,4 +257,20 @@ export class XtreamApiService {
return str;
}
}
/**
* Send request via IPC to avoid CORS issues
*/
private async sendRequest(url: string, params: Record<string, string | number>): Promise<any> {
const serializedParams: Record<string, string> = {};
Object.entries(params).forEach(([key, value]) => {
serializedParams[key] = String(value);
});
const response = await this.dataService.sendIpcEvent(XTREAM_REQUEST, {
url,
params: serializedParams,
});
return response?.payload;
}
}
@@ -6,9 +6,7 @@ import {
} from '@ngrx/signals';
import { Store } from '@ngrx/store';
import { selectActivePlaylist } from 'm3u-state';
import { DataService } from 'services';
import {
XtreamCodeActions,
XtreamSerieDetails,
XtreamVodDetails,
} from 'shared-interfaces';
@@ -17,6 +15,9 @@ import {
import { withFavorites } from '../with-favorites.feature';
import { withRecentItems } from '../with-recent-items';
// Import service
import { XtreamApiService } from '../services/xtream-api.service';
// Import new feature stores
import {
withPortal,
@@ -75,8 +76,10 @@ export const XtreamStore = signalStore(
// Cross-feature methods & orchestration
withMethods((store) => {
const dataService = inject(DataService);
const xtreamApiService = inject(XtreamApiService);
const ngrxStore = inject(Store);
const searchContent = (store as any)
.searchContent as (term: string, types: string[]) => Promise<unknown>;
return {
/**
@@ -122,15 +125,11 @@ export const XtreamStore = signalStore(
if (!playlist) return;
store.setIsLoadingDetails(true);
dataService.fetchData(
`${playlist.serverUrl}/player_api.php`,
{
action: XtreamCodeActions.GetVodInfo,
username: playlist.username,
password: playlist.password,
vod_id: params.vodId,
}
).then((vodDetails: XtreamVodDetails) => {
xtreamApiService.getVodInfo({
serverUrl: playlist.serverUrl,
username: playlist.username,
password: playlist.password,
}, params.vodId).then((vodDetails: XtreamVodDetails) => {
store.setSelectedCategory(params.categoryId);
store.setSelectedItem({
...vodDetails,
@@ -154,15 +153,11 @@ export const XtreamStore = signalStore(
if (!playlist) return;
store.setIsLoadingDetails(true);
dataService.fetchData(
`${playlist.serverUrl}/player_api.php`,
{
action: XtreamCodeActions.GetSeriesInfo,
username: playlist.username,
password: playlist.password,
series_id: params.serialId,
}
).then((serialDetails: XtreamSerieDetails) => {
xtreamApiService.getSeriesInfo({
serverUrl: playlist.serverUrl,
username: playlist.username,
password: playlist.password,
}, params.serialId).then((serialDetails: XtreamSerieDetails) => {
store.setSelectedCategory(params.categoryId);
store.setSelectedItem({
...serialDetails,
@@ -221,7 +216,7 @@ export const XtreamStore = signalStore(
*/
searchContent(params: { term: string; types: string[] }): void {
// Call the underlying search method from withSearch
(store as any).searchContent(params.term, params.types);
void searchContent(params.term, params.types);
},
};
})
-1
View File
@@ -17,7 +17,6 @@ export abstract class DataService {
abstract getAppVersion(): string;
abstract sendIpcEvent(type: string, payload?: unknown): any;
abstract removeAllListeners(type: string): void;
abstract fetchData(url: string, queryParams: Params): any;
abstract listenOn(
command: string,
callback: (...args: any[]) => void