mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-08 17:06:15 -08:00
refactor(xtream): introduce silent actions and improve error handling for Xtream requests
This commit is contained in:
1 parent
d6f5561e6b
commit
61ef8e2553
4 files changed
+151
-24
No files matched your search
@@ -11,6 +11,7 @@ import {
|
||||
Playlist,
|
||||
PLAYLIST_PARSE_BY_URL,
|
||||
PLAYLIST_UPDATE,
|
||||
XtreamCodeActions,
|
||||
XTREAM_RESPONSE,
|
||||
XTREAM_REQUEST,
|
||||
} from 'shared-interfaces';
|
||||
@@ -24,6 +25,12 @@ export class ElectronService extends DataService {
|
||||
private readonly snackBar = inject(MatSnackBar);
|
||||
private readonly store = inject(Store);
|
||||
private readonly translateService = inject(TranslateService);
|
||||
private readonly silentXtreamActions = new Set<string>([
|
||||
XtreamCodeActions.GetAccountInfo,
|
||||
XtreamCodeActions.GetLiveCategories,
|
||||
XtreamCodeActions.GetVodCategories,
|
||||
XtreamCodeActions.GetSeriesCategories,
|
||||
]);
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
@@ -263,24 +270,26 @@ export class ElectronService extends DataService {
|
||||
window.postMessage(result);
|
||||
return result;
|
||||
} catch (error: any) {
|
||||
const isStatusCheck = payload.params?.action === 'get_account_info';
|
||||
const action = payload.params?.action;
|
||||
const isSilentAction = action
|
||||
? this.silentXtreamActions.has(action)
|
||||
: false;
|
||||
const normalizedMessage = this.getReadableXtreamErrorMessage(error);
|
||||
|
||||
// Log error to console
|
||||
if (isStatusCheck) {
|
||||
if (isSilentAction) {
|
||||
console.log(
|
||||
'Portal status check failed - portal may be unavailable:',
|
||||
error.message || error
|
||||
`Background Xtream action failed (${action ?? 'unknown'}):`,
|
||||
normalizedMessage
|
||||
);
|
||||
} else {
|
||||
console.error('Xtream request error:', error.message);
|
||||
console.error('Xtream request error:', normalizedMessage);
|
||||
}
|
||||
|
||||
// Only show snackbar for non-status-check requests
|
||||
if (!isStatusCheck) {
|
||||
// Only show snackbar for user-triggered Xtream requests
|
||||
if (!isSilentAction) {
|
||||
this.snackBar.open(
|
||||
`Error: ${error.message ?? 'Failed to connect to Xtream server'}, status: ${
|
||||
error.status ?? 500
|
||||
}`,
|
||||
`Xtream request failed: ${normalizedMessage}`,
|
||||
'Close',
|
||||
{
|
||||
duration: 5000,
|
||||
@@ -291,11 +300,54 @@ export class ElectronService extends DataService {
|
||||
return {
|
||||
type: ERROR,
|
||||
status: error.status ?? 500,
|
||||
message: error.message ?? 'Failed to connect to Xtream server',
|
||||
message: normalizedMessage,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private getReadableXtreamErrorMessage(error: unknown): string {
|
||||
const fallback = 'Failed to connect to Xtream server';
|
||||
if (!error) {
|
||||
return fallback;
|
||||
}
|
||||
|
||||
const maybeError = error as {
|
||||
message?: unknown;
|
||||
statusText?: unknown;
|
||||
status?: unknown;
|
||||
error?: unknown;
|
||||
};
|
||||
|
||||
if (typeof maybeError.message === 'string') {
|
||||
if (maybeError.message.includes('[object Object]')) {
|
||||
if (typeof maybeError.error === 'string') {
|
||||
return maybeError.error;
|
||||
}
|
||||
if (
|
||||
maybeError.error &&
|
||||
typeof maybeError.error === 'object' &&
|
||||
'message' in (maybeError.error as Record<string, unknown>) &&
|
||||
typeof (maybeError.error as Record<string, unknown>).message ===
|
||||
'string'
|
||||
) {
|
||||
return (maybeError.error as Record<string, string>).message;
|
||||
}
|
||||
return fallback;
|
||||
}
|
||||
return maybeError.message;
|
||||
}
|
||||
|
||||
if (typeof maybeError.statusText === 'string') {
|
||||
return maybeError.statusText;
|
||||
}
|
||||
|
||||
if (typeof error === 'string') {
|
||||
return error;
|
||||
}
|
||||
|
||||
return fallback;
|
||||
}
|
||||
|
||||
removeAllListeners(type: string): void {
|
||||
if (type === 'all') {
|
||||
// Unsubscribe from all event listeners
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
PLAYLIST_PARSE_BY_URL,
|
||||
PLAYLIST_UPDATE,
|
||||
STALKER_REQUEST,
|
||||
XtreamCodeActions,
|
||||
XTREAM_REQUEST,
|
||||
XTREAM_RESPONSE,
|
||||
} from 'shared-interfaces';
|
||||
@@ -28,6 +29,12 @@ export class PwaService extends DataService {
|
||||
private readonly store = inject(Store);
|
||||
private readonly swUpdate = inject(SwUpdate);
|
||||
private readonly translateService = inject(TranslateService);
|
||||
private readonly silentXtreamActions = new Set<string>([
|
||||
XtreamCodeActions.GetAccountInfo,
|
||||
XtreamCodeActions.GetLiveCategories,
|
||||
XtreamCodeActions.GetVodCategories,
|
||||
XtreamCodeActions.GetSeriesCategories,
|
||||
]);
|
||||
|
||||
/** Proxy URL to avoid CORS issues */
|
||||
corsProxyUrl = AppConfig.BACKEND_URL;
|
||||
@@ -186,15 +193,28 @@ export class PwaService extends DataService {
|
||||
);
|
||||
|
||||
if (!(response as any).payload) {
|
||||
if (payload.params.action === 'get_account_info') {
|
||||
console.log('Portal status check failed - portal may be unavailable:', (response as any).message || 'No payload received');
|
||||
return;
|
||||
const action = payload.params.action;
|
||||
const isSilentAction = this.silentXtreamActions.has(action);
|
||||
const normalizedMessage = this.getReadableXtreamErrorMessage(
|
||||
response
|
||||
);
|
||||
|
||||
if (isSilentAction) {
|
||||
console.log(
|
||||
`Background Xtream action failed (${action ?? 'unknown'}):`,
|
||||
normalizedMessage
|
||||
);
|
||||
return {
|
||||
type: ERROR,
|
||||
status: (response as any).status ?? 500,
|
||||
message: normalizedMessage,
|
||||
};
|
||||
}
|
||||
|
||||
result = {
|
||||
type: ERROR,
|
||||
status: (response as any).status,
|
||||
message: (response as any).message ?? 'Unknown error',
|
||||
message: normalizedMessage,
|
||||
};
|
||||
window.postMessage(result);
|
||||
} else {
|
||||
@@ -207,27 +227,81 @@ export class PwaService extends DataService {
|
||||
}
|
||||
return result;
|
||||
} catch (error: any) {
|
||||
const isStatusCheck = payload.params.action === 'get_account_info';
|
||||
const action = payload.params.action;
|
||||
const isSilentAction = this.silentXtreamActions.has(action);
|
||||
const normalizedMessage = this.getReadableXtreamErrorMessage(error);
|
||||
|
||||
// Log error to console
|
||||
if (isStatusCheck) {
|
||||
console.log('Portal status check failed - portal may be unavailable:', error.message || error);
|
||||
return;
|
||||
if (isSilentAction) {
|
||||
console.log(
|
||||
`Background Xtream action failed (${action ?? 'unknown'}):`,
|
||||
normalizedMessage
|
||||
);
|
||||
return {
|
||||
type: ERROR,
|
||||
status: error.status ?? 500,
|
||||
message: normalizedMessage,
|
||||
};
|
||||
}
|
||||
|
||||
console.error('Xtream request error:', error.message);
|
||||
console.error('Xtream request error:', normalizedMessage);
|
||||
this.snackBar.open(
|
||||
`Error: ${error.message ?? ' Unknown error'}, status: ${
|
||||
error.status ?? 500
|
||||
}`,
|
||||
`Xtream request failed: ${normalizedMessage}`,
|
||||
'Close',
|
||||
{
|
||||
duration: 5000,
|
||||
}
|
||||
);
|
||||
return {
|
||||
type: ERROR,
|
||||
status: error.status ?? 500,
|
||||
message: normalizedMessage,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private getReadableXtreamErrorMessage(error: unknown): string {
|
||||
const fallback = 'Failed to connect to Xtream server';
|
||||
if (!error) {
|
||||
return fallback;
|
||||
}
|
||||
|
||||
const maybeError = error as {
|
||||
message?: unknown;
|
||||
statusText?: unknown;
|
||||
error?: unknown;
|
||||
};
|
||||
|
||||
if (typeof maybeError.message === 'string') {
|
||||
if (maybeError.message.includes('[object Object]')) {
|
||||
if (typeof maybeError.error === 'string') {
|
||||
return maybeError.error;
|
||||
}
|
||||
if (
|
||||
maybeError.error &&
|
||||
typeof maybeError.error === 'object' &&
|
||||
'message' in (maybeError.error as Record<string, unknown>) &&
|
||||
typeof (maybeError.error as Record<string, unknown>).message ===
|
||||
'string'
|
||||
) {
|
||||
return (maybeError.error as Record<string, string>).message;
|
||||
}
|
||||
return fallback;
|
||||
}
|
||||
return maybeError.message;
|
||||
}
|
||||
|
||||
if (typeof maybeError.statusText === 'string') {
|
||||
return maybeError.statusText;
|
||||
}
|
||||
|
||||
if (typeof error === 'string') {
|
||||
return error;
|
||||
}
|
||||
|
||||
return fallback;
|
||||
}
|
||||
|
||||
async forwardStalkerRequest(payload: {
|
||||
url: string;
|
||||
params: Record<string, string>;
|
||||
|
||||
@@ -71,7 +71,7 @@ export class XtreamApiService {
|
||||
{
|
||||
username: credentials.username,
|
||||
password: credentials.password,
|
||||
action: 'get_account_info',
|
||||
action: XtreamCodeActions.GetAccountInfo,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export enum XtreamCodeActions {
|
||||
GetAccountInfo = 'get_account_info',
|
||||
GetLiveStreams = 'get_live_streams',
|
||||
GetLiveCategories = 'get_live_categories',
|
||||
GetSeries = 'get_series',
|
||||
|
||||
Reference in new issue
Block a user