import { fetchLibraryMangas, fetchMangaChapters, updateMetadata, } from '~/lib/komga.ts'; const getChapterSort = (chapter: any) => { const volumeNumber = /vol(?:ume)?.?([0-9]+)/i.exec(chapter.name)?.[1] || '1'; const chapterNumber = /ch(?:apter)?.?([0-9.]+)/i.exec(chapter.name)?.[1] || ''; const chapterFloat = Number.parseFloat(chapterNumber); if (!chapterNumber || Number.isNaN(chapterFloat)) { throw new Error( `Ch. ${chapterNumber} cannot be parsed from ${chapter.name}` ); } return { title: `Ch. ${chapterNumber} - Vol. ${volumeNumber}`, numberSort: chapterFloat, }; }; const sanitiseMetadata = (chapter: any, chaptersSeen: Set) => { const data = getChapterSort(chapter); const isDuplicate = chaptersSeen.has(data.numberSort); if (isDuplicate) { console.log(`⚠️ Ch. ${data.numberSort} already seen, marking as duplicate`); } chaptersSeen.add(data.numberSort); return { ...data, numberSortLock: true, tags: isDuplicate ? [...chapter.metadata.tags, 'oxy.DUPLICATE'] : chapter.metadata.tags.filter((tag: string) => tag !== 'oxy.DUPLICATE'), }; }; // Main console.log( `== Sorting library ${Deno.env.get('LIBRARY_ID')} (${new Date().toISOString()}) ==` ); for (const manga of await fetchLibraryMangas(Deno.env.get('LIBRARY_ID'))) { console.log(`Sorting ${manga.name} (${manga.booksCount} chapters)...`); console.group(); const chapters = await fetchMangaChapters(manga.id); const chaptersSeen = new Set(); const metadata = new Map( chapters.map((chap) => [chap.id, sanitiseMetadata(chap, chaptersSeen)]) ); const updates = [...metadata].toSorted( ([, a], [, b]) => a.numberSort - b.numberSort ); let updateCount = 0; for (const [id, metadata] of updates) { await updateMetadata(id, { ...metadata, number: updateCount, }); updateCount += 1; } console.log(`✔ Updated ${updateCount} chapters !`); console.groupEnd(); }