refactor: enhance error handling for playlist updates and add missing i18n strings

This commit is contained in:
4gray committed 2026-03-10 08:52:38 +01:00
1 parent 0012fcfa7b
commit 188ebb6fd9
3 files changed
+144 -45

No files matched your search

+79 -21
View File
@@ -313,27 +313,26 @@ export class ElectronService extends DataService {
filePath?: string;
title: string;
}) {
let methodToCall = null;
if (data.url && !data.filePath) {
// fetch from url
methodToCall = window.electron.fetchPlaylistByUrl(
data.url,
data.title
);
} else if (data.filePath && !data.url) {
// update from file path
methodToCall = window.electron.updatePlaylistFromFilePath(
data.filePath,
data.title
);
} else {
console.error(
'Either url or filePath must be provided, but not both.'
);
return;
}
try {
let playlistObject: Playlist;
if (data.url && !data.filePath) {
playlistObject = await window.electron.fetchPlaylistByUrl(
data.url,
data.title
);
} else if (data.filePath && !data.url) {
playlistObject =
await window.electron.updatePlaylistFromFilePath(
data.filePath,
data.title
);
} else {
console.error(
'Either url or filePath must be provided, but not both.'
);
return;
}
methodToCall.then((playlistObject) => {
this.store.dispatch(
PlaylistActions.updatePlaylist({
playlist: {
@@ -351,7 +350,66 @@ export class ElectronService extends DataService {
null,
{ duration: 2000 }
);
});
} catch (error: unknown) {
console.error('Playlist refresh error:', error);
this.snackBar.open(
this.getPlaylistRefreshErrorMessage(error, data),
this.translateService.instant('CLOSE'),
{ duration: 5000 }
);
}
}
private getPlaylistRefreshErrorMessage(
error: unknown,
data: { url?: string; filePath?: string }
): string {
if (data.filePath) {
const errorMessage = String(
this.getErrorDetails(error)?.message ?? error ?? ''
);
if (
/(ENOENT|no such file or directory|not found)/i.test(
errorMessage
)
) {
return this.translateWithFallback(
'HOME.PLAYLISTS.PLAYLIST_UPDATE_FILE_NOT_FOUND',
'Playlist refresh failed. The local file is no longer available. Check the file path or re-import the playlist.'
);
}
if (/(EACCES|EPERM|permission denied)/i.test(errorMessage)) {
return this.translateWithFallback(
'HOME.PLAYLISTS.PLAYLIST_UPDATE_FILE_ACCESS_ERROR',
'Playlist refresh failed. The app can no longer access the local file.'
);
}
return this.translateService.instant(
'HOME.PLAYLISTS.PLAYLIST_UPDATE_ERROR'
);
}
const statusCode = this.extractHttpStatusCode(error);
if (statusCode === 404) {
return this.translateService.instant('HOME.URL_UPLOAD.ERROR_404');
}
if (statusCode === 403) {
return this.translateService.instant('HOME.URL_UPLOAD.ERROR_403');
}
if (statusCode === 401) {
return this.translateService.instant('HOME.URL_UPLOAD.ERROR_401');
}
return this.translateService.instant(
'HOME.URL_UPLOAD.ERROR_FETCH_FAILED'
);
}
private translateWithFallback(key: string, fallback: string): string {
const translated = this.translateService.instant(key);
return translated === key ? fallback : translated;
}
/* private getErrorMessageByStatusCode(status: number) {
+63 -24
View File
@@ -131,10 +131,8 @@ export class PwaService extends DataService {
.pipe(
catchError((error) => {
this.snackBar.open(
`Error: ${error.message ?? 'Unknown error'}, status: ${
error.status ?? 500
}`,
'Close',
this.getPlaylistRefreshErrorMessage(error),
this.translateService.instant('CLOSE'),
{
duration: 5000,
}
@@ -160,6 +158,25 @@ export class PwaService extends DataService {
});
}
private getPlaylistRefreshErrorMessage(error: unknown): string {
const statusCode =
this.getErrorDetails(error)?.status ??
this.extractHttpStatusCode(error);
if (statusCode === 404) {
return this.translateService.instant('HOME.URL_UPLOAD.ERROR_404');
}
if (statusCode === 403) {
return this.translateService.instant('HOME.URL_UPLOAD.ERROR_403');
}
if (statusCode === 401) {
return this.translateService.instant('HOME.URL_UPLOAD.ERROR_401');
}
return this.translateService.instant(
'HOME.URL_UPLOAD.ERROR_FETCH_FAILED'
);
}
/**
* Fetches playlist from the specified url
* @param payload playlist payload
@@ -189,19 +206,38 @@ export class PwaService extends DataService {
}
getErrorMessageByStatusCode(status: number) {
let message = 'Something went wrong';
let messageKey = 'HOME.URL_UPLOAD.ERROR_FETCH_FAILED';
switch (status) {
case 0:
message = 'The backend is not reachable';
break;
case 413:
message =
'This file is too big. Use standalone or self-hosted version of the app.';
return 'This file is too big. Use standalone or self-hosted version of the app.';
case 403:
messageKey = 'HOME.URL_UPLOAD.ERROR_403';
break;
case 404:
messageKey = 'HOME.URL_UPLOAD.ERROR_404';
break;
case 401:
messageKey = 'HOME.URL_UPLOAD.ERROR_401';
break;
default:
break;
}
return message;
return this.translateService.instant(messageKey);
}
private extractHttpStatusCode(error: unknown): number | null {
if (
error &&
typeof error === 'object' &&
'status' in error &&
typeof error.status === 'number'
) {
return error.status;
}
const msg = String((error as { message?: string })?.message ?? error);
const match = msg.match(/status code (\d{3})/);
return match ? parseInt(match[1], 10) : null;
}
async forwardXtreamRequest(payload: {
@@ -242,21 +278,23 @@ export class PwaService extends DataService {
try {
let result: PwaErrorResult | PwaXtreamResult;
const response = (await firstValueFrom(
this.http.get<PwaXtreamResponse>(`${this.corsProxyUrl}/xtream`, {
params: {
url: payload.url,
...payload.params,
},
...headers,
})
this.http.get<PwaXtreamResponse>(
`${this.corsProxyUrl}/xtream`,
{
params: {
url: payload.url,
...payload.params,
},
...headers,
}
)
)) as PwaXtreamResponse;
if (!response.payload) {
const action = payload.params.action;
const isSilentAction = this.silentXtreamActions.has(action);
const normalizedMessage = this.getReadableXtreamErrorMessage(
response
);
const normalizedMessage =
this.getReadableXtreamErrorMessage(response);
logPortalDebugEvent(
createPortalDebugErrorEvent(context, response)
);
@@ -347,9 +385,10 @@ export class PwaService extends DataService {
if (
maybeError.error &&
typeof maybeError.error === 'object' &&
'message' in (maybeError.error as Record<string, unknown>) &&
typeof (maybeError.error as Record<string, unknown>).message ===
'string'
'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;
}
+2
View File
@@ -77,6 +77,8 @@
"MY_PLAYLISTS_SUBTITLE": "all available playlists",
"PLAYLIST_UPDATE_SUCCESS": "Success! The playlist was successfully updated.",
"PLAYLIST_UPDATE_ERROR": "Error updating playlist details.",
"PLAYLIST_UPDATE_FILE_NOT_FOUND": "Playlist refresh failed. The local file is no longer available. Check the file path or re-import the playlist.",
"PLAYLIST_UPDATE_FILE_ACCESS_ERROR": "Playlist refresh failed. The app can no longer access the local file.",
"AUTO_REFRESH_UPDATE_SUCCESS": "Success! The playlists were successfully updated",
"AUTO_REFRESH_ENABLED": "Auto-refresh enabled"
},