Fix missing manga action execution failure messages

The manga actions to
- download
- delete downloads
- mark as read
- mark as unread
did not show an error message in case the request to get relevant chapter ids failed.
This commit is contained in:
schroda
2026-05-20 14:52:27 +02:00
parent 4394dbe957
commit 3ae4d8d752

View File

@@ -55,6 +55,8 @@ import type {
UpdateMangaCategoriesPatchInput, UpdateMangaCategoriesPatchInput,
} from '@/lib/graphql/generated/graphql-base.types.ts'; } from '@/lib/graphql/generated/graphql-base.types.ts';
const I18N_PLURAL = 9999;
type DownloadChaptersOptions = { type DownloadChaptersOptions = {
size?: number; size?: number;
onlyUnread?: boolean; onlyUnread?: boolean;
@@ -190,67 +192,96 @@ export class Mangas {
{ size, onlyUnread, downloadAhead = false }: DownloadChaptersOptions = {}, { size, onlyUnread, downloadAhead = false }: DownloadChaptersOptions = {},
disableConfirmation?: boolean, disableConfirmation?: boolean,
): Promise<void> { ): Promise<void> {
const [chaptersToConsider, unReadDownloadedChapters] = await Promise.all([ return Mangas.executeAction(
Mangas.getChapterIdsWithState(mangaIds, { 'download',
isRead: onlyUnread ? false : undefined, I18N_PLURAL,
isDownloaded: false, async () => {
}), const [chaptersToConsider, unReadDownloadedChapters] = await Promise.all([
downloadAhead ? Mangas.getChapterIdsWithState(mangaIds, { isRead: false, isDownloaded: true }) : [], Mangas.getChapterIdsWithState(mangaIds, {
]); isRead: onlyUnread ? false : undefined,
isDownloaded: false,
}),
downloadAhead ? Mangas.getChapterIdsWithState(mangaIds, { isRead: false, isDownloaded: true }) : [],
]);
type MangaIdToDownloadSize = [MangaId: string, DownloadSize: number | undefined]; type MangaIdToDownloadSize = [MangaId: string, DownloadSize: number | undefined];
const mangaIdToDefaultDownloadSize = mangaIds.map((mangaId) => [ const mangaIdToDefaultDownloadSize = mangaIds.map((mangaId) => [
String(mangaId), String(mangaId),
size, size,
]) satisfies MangaIdToDownloadSize[]; ]) satisfies MangaIdToDownloadSize[];
const mangaIdToChaptersToConsider = Object.groupBy(chaptersToConsider, ({ mangaId }) => mangaId); const mangaIdToChaptersToConsider = Object.groupBy(chaptersToConsider, ({ mangaId }) => mangaId);
const mangaIdToUnReadDownloadedChapters = Object.groupBy(unReadDownloadedChapters, ({ mangaId }) => mangaId); const mangaIdToUnReadDownloadedChapters = Object.groupBy(
unReadDownloadedChapters,
({ mangaId }) => mangaId,
);
const mangaIdToDownloadSize = Object.entries(mangaIdToUnReadDownloadedChapters).map( const mangaIdToDownloadSize = Object.entries(mangaIdToUnReadDownloadedChapters).map(
([mangaId, downloadedChapters = []]) => { ([mangaId, downloadedChapters = []]) => {
const downloadAheadSize = Math.max(0, (size ?? downloadedChapters.length) - downloadedChapters.length); const downloadAheadSize = Math.max(
const actualSize = downloadAhead ? downloadAheadSize : size; 0,
(size ?? downloadedChapters.length) - downloadedChapters.length,
);
const actualSize = downloadAhead ? downloadAheadSize : size;
return [mangaId, actualSize]; return [mangaId, actualSize];
},
) satisfies MangaIdToDownloadSize[];
const mangaIdToActualDownloadSize = Object.entries(
Object.fromEntries([...mangaIdToDefaultDownloadSize, ...mangaIdToDownloadSize]),
) satisfies MangaIdToDownloadSize[];
const chaptersToDownload = mangaIdToActualDownloadSize
.flatMap(([mangaId, actualSize]) => {
const mangaChapters = mangaIdToChaptersToConsider[Number(mangaId)] ?? [];
if (!mangaChapters.length) {
return [];
}
const shouldDownloadAll = actualSize === undefined;
if (shouldDownloadAll) {
return mangaChapters;
}
const uniqueMangaChapters = Chapters.removeDuplicates(mangaChapters[0], mangaChapters);
const uniqueMangaChaptersToDownload = uniqueMangaChapters.slice(0, actualSize);
return Chapters.addDuplicates(uniqueMangaChaptersToDownload, mangaChapters);
})
.filter(Chapters.isDownloadable);
if (!chaptersToDownload.length) {
return Promise.resolve();
}
try {
await Chapters.download(Chapters.getIds(chaptersToDownload), disableConfirmation);
} catch (e) {
// Ignore - Error gets handled in Chapters
}
}, },
) satisfies MangaIdToDownloadSize[]; true,
);
const mangaIdToActualDownloadSize = Object.entries(
Object.fromEntries([...mangaIdToDefaultDownloadSize, ...mangaIdToDownloadSize]),
) satisfies MangaIdToDownloadSize[];
const chaptersToDownload = mangaIdToActualDownloadSize
.flatMap(([mangaId, actualSize]) => {
const mangaChapters = mangaIdToChaptersToConsider[Number(mangaId)] ?? [];
if (!mangaChapters.length) {
return [];
}
const shouldDownloadAll = actualSize === undefined;
if (shouldDownloadAll) {
return mangaChapters;
}
const uniqueMangaChapters = Chapters.removeDuplicates(mangaChapters[0], mangaChapters);
const uniqueMangaChaptersToDownload = uniqueMangaChapters.slice(0, actualSize);
return Chapters.addDuplicates(uniqueMangaChaptersToDownload, mangaChapters);
})
.filter(Chapters.isDownloadable);
if (!chaptersToDownload.length) {
return Promise.resolve();
}
return Chapters.download(Chapters.getIds(chaptersToDownload), disableConfirmation);
} }
static async deleteChapters(mangaIds: number[], disableConfirmation?: boolean): Promise<void> { static async deleteChapters(mangaIds: number[], disableConfirmation?: boolean): Promise<void> {
const chapters = await Mangas.getChapterIdsWithState(mangaIds, { isDownloaded: true }); return Mangas.executeAction(
return Chapters.delete(Chapters.getIds(chapters), disableConfirmation); 'delete',
I18N_PLURAL,
async () => {
const chapters = await Mangas.getChapterIdsWithState(mangaIds, { isDownloaded: true });
try {
await Chapters.delete(Chapters.getIds(chapters), disableConfirmation);
} catch (e) {
// Ignore - Error gets handled in Chapters
}
},
true,
);
} }
static async markAsRead( static async markAsRead(
@@ -258,18 +289,42 @@ export class Mangas {
wasManuallyMarkedAsRead: boolean = false, wasManuallyMarkedAsRead: boolean = false,
disableConfirmation?: boolean, disableConfirmation?: boolean,
): Promise<void> { ): Promise<void> {
const chapters = await Mangas.getChapterIdsWithState(mangaIds, { isRead: false }); return Mangas.executeAction(
return Chapters.markAsRead( 'mark_as_read',
chapters, I18N_PLURAL,
wasManuallyMarkedAsRead, async () => {
mangaIds.length === 1 ? mangaIds[0] : undefined, const chapters = await Mangas.getChapterIdsWithState(mangaIds, { isRead: false });
disableConfirmation,
try {
await Chapters.markAsRead(
chapters,
wasManuallyMarkedAsRead,
mangaIds.length === 1 ? mangaIds[0] : undefined,
disableConfirmation,
);
} catch (e) {
// Ignore - Error gets handled in Chapters
}
},
true,
); );
} }
static async markAsUnread(mangaIds: number[], disableConfirmation?: boolean): Promise<void> { static async markAsUnread(mangaIds: number[], disableConfirmation?: boolean): Promise<void> {
const chapters = await Mangas.getChapterIdsWithState(mangaIds, { isRead: true }); return Mangas.executeAction(
return Chapters.markAsUnread(Chapters.getIds(chapters), disableConfirmation); 'mark_as_unread',
I18N_PLURAL,
async () => {
const chapters = await Mangas.getChapterIdsWithState(mangaIds, { isRead: true });
try {
await Chapters.markAsUnread(Chapters.getIds(chapters), disableConfirmation);
} catch (e) {
// Ignore - Error gets handled in Chapters
}
},
true,
);
} }
static async removeFromLibrary(mangaIds: number[], disableConfirmation?: boolean): Promise<void> { static async removeFromLibrary(mangaIds: number[], disableConfirmation?: boolean): Promise<void> {