Extract migration source search into function
This commit is contained in:
@@ -891,10 +891,12 @@ export class MigrationManager {
|
|||||||
return updatedMatches;
|
return updatedMatches;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async searchForManga(
|
private static async searchForMangaInSource(
|
||||||
|
sourceId: SourceIdInfo['id'],
|
||||||
mangaId: MangaIdInfo['id'],
|
mangaId: MangaIdInfo['id'],
|
||||||
mangaTitle: string,
|
mangaTitle: string,
|
||||||
mainSignal: AbortSignal,
|
signal: AbortSignal,
|
||||||
|
searchController: AbortController,
|
||||||
options: MigrationBulkSearchSettings,
|
options: MigrationBulkSearchSettings,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const {
|
const {
|
||||||
@@ -904,6 +906,125 @@ export class MigrationManager {
|
|||||||
ignoreWithMissingChapters,
|
ignoreWithMissingChapters,
|
||||||
} = options;
|
} = options;
|
||||||
|
|
||||||
|
signal.throwIfAborted();
|
||||||
|
|
||||||
|
if (!selectHighestChapterNumberSource && MigrationManager.hasHigherSourcePriorityMatch(mangaId, sourceId)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const foundMatches = await (async () => {
|
||||||
|
try {
|
||||||
|
return await MigrationManager.findMatchesForMangaInSource(
|
||||||
|
mangaId,
|
||||||
|
mangaTitle,
|
||||||
|
sourceId,
|
||||||
|
signal,
|
||||||
|
options,
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
MigrationManager.updateState((draft) => {
|
||||||
|
const draftEntry = draft.entries[mangaId];
|
||||||
|
|
||||||
|
draftEntry.destSourceIdToSearchState[sourceId] = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
|
if (!foundMatches.length) {
|
||||||
|
MigrationManager.updateState((draft) => {
|
||||||
|
const draftEntry = draft.entries[mangaId];
|
||||||
|
|
||||||
|
draftEntry.destSourceIdToSearchState[sourceId] = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MigrationManager.updateState((draft) => {
|
||||||
|
const draftEntry = draft.entries[mangaId];
|
||||||
|
const draftMatchEntry = draftEntry.selectedMatchMangaId
|
||||||
|
? draft.entries[draftEntry.selectedMatchMangaId]
|
||||||
|
: null;
|
||||||
|
|
||||||
|
const newMatches = foundMatches.filter((newMatch) =>
|
||||||
|
draftEntry.searchMatches.every((existingMatch) => newMatch.manga.id !== existingMatch.id),
|
||||||
|
);
|
||||||
|
const matches = newMatches.map(({ manga, chapters }) => ({
|
||||||
|
id: manga.id,
|
||||||
|
title: manga.title,
|
||||||
|
artist: manga.artist,
|
||||||
|
author: manga.author,
|
||||||
|
latestChapterNumber: manga.highestNumberedChapter?.chapterNumber,
|
||||||
|
thumbnailUrl: manga.thumbnailUrl,
|
||||||
|
sourceId: manga.sourceId,
|
||||||
|
sourceTitle: manga.source?.displayName,
|
||||||
|
missingChapters: chapters ? Chapters.getMissingCount(chapters) : undefined,
|
||||||
|
inLibrary: manga.inLibrary,
|
||||||
|
}));
|
||||||
|
|
||||||
|
draftEntry.destSourceIdToSearchState[sourceId] = true;
|
||||||
|
draftEntry.searchMatches = [...draftEntry.searchMatches, ...matches];
|
||||||
|
|
||||||
|
const matchesByChapterNumber = Object.groupBy(matches, (match) => match.latestChapterNumber ?? -1);
|
||||||
|
const latestChapterNumber = Math.max(
|
||||||
|
...Object.keys(matchesByChapterNumber).map((chapterNumber) => Number(chapterNumber)),
|
||||||
|
);
|
||||||
|
const bestMatch = matchesByChapterNumber[latestChapterNumber]?.[0];
|
||||||
|
|
||||||
|
assertIsDefined(bestMatch);
|
||||||
|
|
||||||
|
const entryLatestChapterNumber = draftEntry.latestChapterNumber ?? Number.MIN_SAFE_INTEGER;
|
||||||
|
const selectedMatchLatestChapterNumber = draftMatchEntry?.latestChapterNumber ?? Number.MIN_SAFE_INTEGER;
|
||||||
|
|
||||||
|
const hasNewerChapterVsEntry = latestChapterNumber > entryLatestChapterNumber;
|
||||||
|
const hasNewerChapterVsSelectedMatch = latestChapterNumber > selectedMatchLatestChapterNumber;
|
||||||
|
const hasNewerChapter = hasNewerChapterVsEntry && hasNewerChapterVsSelectedMatch;
|
||||||
|
|
||||||
|
const isOutdated = latestChapterNumber < entryLatestChapterNumber;
|
||||||
|
|
||||||
|
const hasSameLatestChapterAsSelectedMatch =
|
||||||
|
!!draftMatchEntry && selectedMatchLatestChapterNumber === latestChapterNumber;
|
||||||
|
|
||||||
|
const hasHigherSourcePriority = !MigrationManager.hasHigherSourcePriorityMatch(mangaId, sourceId);
|
||||||
|
|
||||||
|
const ignoreOutdatedMatch = ignoreOutdatedMatches && isOutdated;
|
||||||
|
const satisfiesRequireAdditionalChapters = !requireAdditionalChapters || hasNewerChapter;
|
||||||
|
const ignoreBecauseMissingChapters = ignoreWithMissingChapters && !!bestMatch.missingChapters;
|
||||||
|
const isPreferredSourcePriorityMatch = hasHigherSourcePriority && !selectHighestChapterNumberSource;
|
||||||
|
const isPreferredChapterNumberMatch =
|
||||||
|
selectHighestChapterNumberSource &&
|
||||||
|
(hasNewerChapter ||
|
||||||
|
(hasHigherSourcePriority && hasSameLatestChapterAsSelectedMatch) ||
|
||||||
|
!draftMatchEntry);
|
||||||
|
|
||||||
|
const isPreferredMatch =
|
||||||
|
!draftEntry.isManualSelection &&
|
||||||
|
!ignoreOutdatedMatch &&
|
||||||
|
satisfiesRequireAdditionalChapters &&
|
||||||
|
!ignoreBecauseMissingChapters &&
|
||||||
|
(isPreferredSourcePriorityMatch || isPreferredChapterNumberMatch);
|
||||||
|
if (isPreferredMatch) {
|
||||||
|
draftEntry.selectedMatchMangaId = bestMatch.id;
|
||||||
|
draftEntry.selectedMatchSourceId = sourceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
!selectHighestChapterNumberSource &&
|
||||||
|
!MigrationManager.isHigherPrioritySourceUnsettled(mangaId, sourceId)
|
||||||
|
) {
|
||||||
|
searchController.abort(`Found best match in source "${sourceId}"`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async searchForManga(
|
||||||
|
mangaId: MangaIdInfo['id'],
|
||||||
|
mangaTitle: string,
|
||||||
|
mainSignal: AbortSignal,
|
||||||
|
options: MigrationBulkSearchSettings,
|
||||||
|
): Promise<void> {
|
||||||
const state = MigrationManager.getState();
|
const state = MigrationManager.getState();
|
||||||
const entry = state.entries[mangaId];
|
const entry = state.entries[mangaId];
|
||||||
|
|
||||||
@@ -935,136 +1056,16 @@ export class MigrationManager {
|
|||||||
const searchPromises = MigrationManager.getDestinationSourceIds(entry.sourceId)
|
const searchPromises = MigrationManager.getDestinationSourceIds(entry.sourceId)
|
||||||
.filter((destSourceId) => !entry.destSourceIdToSearchState[destSourceId])
|
.filter((destSourceId) => !entry.destSourceIdToSearchState[destSourceId])
|
||||||
.map((destSourceId) =>
|
.map((destSourceId) =>
|
||||||
MigrationManager.getParallelSourceQueue()(async () => {
|
MigrationManager.getParallelSourceQueue()(async () =>
|
||||||
if (signal.aborted) {
|
MigrationManager.searchForMangaInSource(
|
||||||
throw new Error(signal.reason);
|
destSourceId,
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
!selectHighestChapterNumberSource &&
|
|
||||||
MigrationManager.hasHigherSourcePriorityMatch(mangaId, destSourceId)
|
|
||||||
) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const foundMatches = await (async () => {
|
|
||||||
try {
|
|
||||||
return await MigrationManager.findMatchesForMangaInSource(
|
|
||||||
mangaId,
|
mangaId,
|
||||||
mangaTitle,
|
mangaTitle,
|
||||||
destSourceId,
|
|
||||||
signal,
|
signal,
|
||||||
|
searchController,
|
||||||
options,
|
options,
|
||||||
);
|
|
||||||
} catch (e) {
|
|
||||||
MigrationManager.updateState((draft) => {
|
|
||||||
const draftEntry = draft.entries[mangaId];
|
|
||||||
|
|
||||||
draftEntry.destSourceIdToSearchState[destSourceId] = false;
|
|
||||||
});
|
|
||||||
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
|
|
||||||
if (!foundMatches.length) {
|
|
||||||
MigrationManager.updateState((draft) => {
|
|
||||||
const draftEntry = draft.entries[mangaId];
|
|
||||||
|
|
||||||
draftEntry.destSourceIdToSearchState[destSourceId] = false;
|
|
||||||
});
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
MigrationManager.updateState((draft) => {
|
|
||||||
const draftEntry = draft.entries[mangaId];
|
|
||||||
const draftMatchEntry = draftEntry.selectedMatchMangaId
|
|
||||||
? draft.entries[draftEntry.selectedMatchMangaId]
|
|
||||||
: null;
|
|
||||||
|
|
||||||
const newMatches = foundMatches.filter((newMatch) =>
|
|
||||||
draftEntry.searchMatches.every(
|
|
||||||
(existingMatch) => newMatch.manga.id !== existingMatch.id,
|
|
||||||
),
|
),
|
||||||
);
|
),
|
||||||
const matches = newMatches.map(({ manga, chapters }) => ({
|
|
||||||
id: manga.id,
|
|
||||||
title: manga.title,
|
|
||||||
artist: manga.artist,
|
|
||||||
author: manga.author,
|
|
||||||
latestChapterNumber: manga.highestNumberedChapter?.chapterNumber,
|
|
||||||
thumbnailUrl: manga.thumbnailUrl,
|
|
||||||
sourceId: manga.sourceId,
|
|
||||||
sourceTitle: manga.source?.displayName,
|
|
||||||
missingChapters: chapters ? Chapters.getMissingCount(chapters) : undefined,
|
|
||||||
inLibrary: manga.inLibrary,
|
|
||||||
}));
|
|
||||||
|
|
||||||
draftEntry.destSourceIdToSearchState[destSourceId] = true;
|
|
||||||
draftEntry.searchMatches = [...draftEntry.searchMatches, ...matches];
|
|
||||||
|
|
||||||
const matchesByChapterNumber = Object.groupBy(
|
|
||||||
matches,
|
|
||||||
(match) => match.latestChapterNumber ?? -1,
|
|
||||||
);
|
|
||||||
const latestChapterNumber = Math.max(
|
|
||||||
...Object.keys(matchesByChapterNumber).map((chapterNumber) => Number(chapterNumber)),
|
|
||||||
);
|
|
||||||
const bestMatch = matchesByChapterNumber[latestChapterNumber]?.[0];
|
|
||||||
|
|
||||||
assertIsDefined(bestMatch);
|
|
||||||
|
|
||||||
const entryLatestChapterNumber = draftEntry.latestChapterNumber ?? Number.MIN_SAFE_INTEGER;
|
|
||||||
const selectedMatchLatestChapterNumber =
|
|
||||||
draftMatchEntry?.latestChapterNumber ?? Number.MIN_SAFE_INTEGER;
|
|
||||||
|
|
||||||
const hasNewerChapterVsEntry = latestChapterNumber > entryLatestChapterNumber;
|
|
||||||
const hasNewerChapterVsSelectedMatch =
|
|
||||||
latestChapterNumber > selectedMatchLatestChapterNumber;
|
|
||||||
const hasNewerChapter = hasNewerChapterVsEntry && hasNewerChapterVsSelectedMatch;
|
|
||||||
|
|
||||||
const isOutdated = latestChapterNumber < entryLatestChapterNumber;
|
|
||||||
|
|
||||||
const hasSameLatestChapterAsSelectedMatch =
|
|
||||||
!!draftMatchEntry && selectedMatchLatestChapterNumber === latestChapterNumber;
|
|
||||||
|
|
||||||
const hasHigherSourcePriority = !MigrationManager.hasHigherSourcePriorityMatch(
|
|
||||||
mangaId,
|
|
||||||
destSourceId,
|
|
||||||
);
|
|
||||||
|
|
||||||
const ignoreOutdatedMatch = ignoreOutdatedMatches && isOutdated;
|
|
||||||
const satisfiesRequireAdditionalChapters = !requireAdditionalChapters || hasNewerChapter;
|
|
||||||
const ignoreBecauseMissingChapters =
|
|
||||||
ignoreWithMissingChapters && !!bestMatch.missingChapters;
|
|
||||||
const isPreferredSourcePriorityMatch =
|
|
||||||
hasHigherSourcePriority && !selectHighestChapterNumberSource;
|
|
||||||
const isPreferredChapterNumberMatch =
|
|
||||||
selectHighestChapterNumberSource &&
|
|
||||||
(hasNewerChapter ||
|
|
||||||
(hasHigherSourcePriority && hasSameLatestChapterAsSelectedMatch) ||
|
|
||||||
!draftMatchEntry);
|
|
||||||
|
|
||||||
const isPreferredMatch =
|
|
||||||
!draftEntry.isManualSelection &&
|
|
||||||
!ignoreOutdatedMatch &&
|
|
||||||
satisfiesRequireAdditionalChapters &&
|
|
||||||
!ignoreBecauseMissingChapters &&
|
|
||||||
(isPreferredSourcePriorityMatch || isPreferredChapterNumberMatch);
|
|
||||||
if (isPreferredMatch) {
|
|
||||||
draftEntry.selectedMatchMangaId = bestMatch.id;
|
|
||||||
draftEntry.selectedMatchSourceId = destSourceId;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
!selectHighestChapterNumberSource &&
|
|
||||||
!MigrationManager.isHigherPrioritySourceUnsettled(mangaId, destSourceId)
|
|
||||||
) {
|
|
||||||
searchController.abort(`Found best match in source "${destSourceId}"`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const searchMatchPromises = await Promise.allSettled(searchPromises);
|
const searchMatchPromises = await Promise.allSettled(searchPromises);
|
||||||
|
|||||||
Reference in New Issue
Block a user