Optionally ignore missing chapter matches during bulk migration
This commit is contained in:
@@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|||||||
### Added
|
### Added
|
||||||
|
|
||||||
- (**Migration**) Add a search option to ignore outdated matches
|
- (**Migration**) Add a search option to ignore outdated matches
|
||||||
|
- (**Migration**) Add a search option to ignore matches with missing chapters
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ export const MangaCard = memo((props: MangaCardProps) => {
|
|||||||
if (isMigrateSelectMode) {
|
if (isMigrateSelectMode) {
|
||||||
const isBulkMigrationManualSearch = !!onMigrateSelect;
|
const isBulkMigrationManualSearch = !!onMigrateSelect;
|
||||||
if (isBulkMigrationManualSearch) {
|
if (isBulkMigrationManualSearch) {
|
||||||
onMigrateSelect(manga);
|
onMigrateSelect({ ...manga, missingChapters: undefined });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ export interface MigrationBulkSearchSettings {
|
|||||||
selectHighestChapterNumberSource: boolean;
|
selectHighestChapterNumberSource: boolean;
|
||||||
ignoreOutdatedMatches: boolean;
|
ignoreOutdatedMatches: boolean;
|
||||||
requireAdditionalChapters: boolean;
|
requireAdditionalChapters: boolean;
|
||||||
|
ignoreWithMissingChapters: boolean;
|
||||||
performAdvancedSearch: boolean;
|
performAdvancedSearch: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,6 +103,7 @@ export interface MigrationMatch
|
|||||||
extends MangaIdInfo, MangaTitleInfo, MangaThumbnailInfo, MangaSourceIdInfo, MangaArtistInfo, MangaAuthorInfo {
|
extends MangaIdInfo, MangaTitleInfo, MangaThumbnailInfo, MangaSourceIdInfo, MangaArtistInfo, MangaAuthorInfo {
|
||||||
sourceTitle: SourceDisplayNameInfo['displayName'] | undefined;
|
sourceTitle: SourceDisplayNameInfo['displayName'] | undefined;
|
||||||
latestChapterNumber: ChapterNumberInfo['chapterNumber'] | undefined;
|
latestChapterNumber: ChapterNumberInfo['chapterNumber'] | undefined;
|
||||||
|
missingChapters: number | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TMigrationEntry {
|
export interface TMigrationEntry {
|
||||||
@@ -110,6 +112,7 @@ export interface TMigrationEntry {
|
|||||||
mangaArtist: MangaArtistInfo['artist'];
|
mangaArtist: MangaArtistInfo['artist'];
|
||||||
mangaAuthor: MangaAuthorInfo['author'];
|
mangaAuthor: MangaAuthorInfo['author'];
|
||||||
latestChapterNumber: ChapterNumberInfo['chapterNumber'] | undefined;
|
latestChapterNumber: ChapterNumberInfo['chapterNumber'] | undefined;
|
||||||
|
missingChapters: number | undefined;
|
||||||
mangaThumbnailUrl: MangaThumbnailInfo['thumbnailUrl'] | undefined;
|
mangaThumbnailUrl: MangaThumbnailInfo['thumbnailUrl'] | undefined;
|
||||||
sourceId: SourceIdInfo['id'];
|
sourceId: SourceIdInfo['id'];
|
||||||
sourceTitle: SourceDisplayNameInfo['displayName'] | undefined;
|
sourceTitle: SourceDisplayNameInfo['displayName'] | undefined;
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import {
|
|||||||
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
||||||
import { GET_MIGRATION_SOURCE_MANGAS_FETCH } from '@/lib/graphql/source/SourceMutation.ts';
|
import { GET_MIGRATION_SOURCE_MANGAS_FETCH } from '@/lib/graphql/source/SourceMutation.ts';
|
||||||
import type {
|
import type {
|
||||||
|
ChapterListFieldsFragment,
|
||||||
GetMigrationSourceMangasFetchMutation,
|
GetMigrationSourceMangasFetchMutation,
|
||||||
GetMigrationSourceMangasFetchMutationVariables,
|
GetMigrationSourceMangasFetchMutationVariables,
|
||||||
GetServerSettingsQuery,
|
GetServerSettingsQuery,
|
||||||
@@ -67,6 +68,7 @@ import { getErrorMessage } from '@/lib/HelperFunctions.ts';
|
|||||||
import isEqual from 'lodash/fp/isEqual';
|
import isEqual from 'lodash/fp/isEqual';
|
||||||
import uniqBy from 'lodash/fp/uniqBy';
|
import uniqBy from 'lodash/fp/uniqBy';
|
||||||
import { MigrationEntries } from '@/features/migration/MigrationEntries.ts';
|
import { MigrationEntries } from '@/features/migration/MigrationEntries.ts';
|
||||||
|
import { Chapters } from '@/features/chapter/services/Chapters.ts';
|
||||||
|
|
||||||
const RESUMABLE_PHASES: readonly MigrationPhase[] = [MigrationPhase.SEARCHING, MigrationPhase.MIGRATING];
|
const RESUMABLE_PHASES: readonly MigrationPhase[] = [MigrationPhase.SEARCHING, MigrationPhase.MIGRATING];
|
||||||
|
|
||||||
@@ -246,6 +248,7 @@ export class MigrationManager {
|
|||||||
author: cachedEntry?.author ?? searchMatch.author,
|
author: cachedEntry?.author ?? searchMatch.author,
|
||||||
sourceTitle: cachedEntry?.source?.displayName ?? searchMatch.sourceTitle,
|
sourceTitle: cachedEntry?.source?.displayName ?? searchMatch.sourceTitle,
|
||||||
latestChapterNumber: cachedEntry?.highestNumberedChapter?.chapterNumber ?? searchMatch.latestChapterNumber,
|
latestChapterNumber: cachedEntry?.highestNumberedChapter?.chapterNumber ?? searchMatch.latestChapterNumber,
|
||||||
|
missingChapters: searchMatch.missingChapters,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -262,6 +265,7 @@ export class MigrationManager {
|
|||||||
mangaArtist: cachedEntry?.artist ?? entry.mangaArtist,
|
mangaArtist: cachedEntry?.artist ?? entry.mangaArtist,
|
||||||
mangaAuthor: cachedEntry?.author ?? entry.mangaAuthor,
|
mangaAuthor: cachedEntry?.author ?? entry.mangaAuthor,
|
||||||
latestChapterNumber: cachedEntry?.highestNumberedChapter?.chapterNumber ?? entry.latestChapterNumber,
|
latestChapterNumber: cachedEntry?.highestNumberedChapter?.chapterNumber ?? entry.latestChapterNumber,
|
||||||
|
missingChapters: entry.missingChapters,
|
||||||
mangaThumbnailUrl: cachedEntry?.thumbnailUrl ?? entry.mangaThumbnailUrl,
|
mangaThumbnailUrl: cachedEntry?.thumbnailUrl ?? entry.mangaThumbnailUrl,
|
||||||
sourceId: cachedEntry?.sourceId ?? entry.sourceId,
|
sourceId: cachedEntry?.sourceId ?? entry.sourceId,
|
||||||
sourceTitle: cachedEntry?.source?.displayName ?? entry.sourceTitle,
|
sourceTitle: cachedEntry?.source?.displayName ?? entry.sourceTitle,
|
||||||
@@ -336,6 +340,7 @@ export class MigrationManager {
|
|||||||
mangaArtist: manga.artist,
|
mangaArtist: manga.artist,
|
||||||
mangaAuthor: manga.author,
|
mangaAuthor: manga.author,
|
||||||
latestChapterNumber: manga.highestNumberedChapter?.chapterNumber,
|
latestChapterNumber: manga.highestNumberedChapter?.chapterNumber,
|
||||||
|
missingChapters: undefined,
|
||||||
mangaThumbnailUrl: manga.thumbnailUrl,
|
mangaThumbnailUrl: manga.thumbnailUrl,
|
||||||
sourceId: manga.sourceId,
|
sourceId: manga.sourceId,
|
||||||
sourceTitle: manga.source?.displayName,
|
sourceTitle: manga.source?.displayName,
|
||||||
@@ -710,7 +715,7 @@ export class MigrationManager {
|
|||||||
sourceId: SourceIdInfo['id'],
|
sourceId: SourceIdInfo['id'],
|
||||||
signal: AbortSignal,
|
signal: AbortSignal,
|
||||||
{ selectHighestChapterNumberSource, performAdvancedSearch }: MigrationBulkSearchSettings,
|
{ selectHighestChapterNumberSource, performAdvancedSearch }: MigrationBulkSearchSettings,
|
||||||
): Promise<MangaMigrationFieldsFragment[]> {
|
): Promise<{ manga: MangaMigrationFieldsFragment; chapters: ChapterListFieldsFragment[] | null }[]> {
|
||||||
if (signal.aborted) {
|
if (signal.aborted) {
|
||||||
throw new Error(signal.reason);
|
throw new Error(signal.reason);
|
||||||
}
|
}
|
||||||
@@ -781,12 +786,20 @@ export class MigrationManager {
|
|||||||
}).response,
|
}).response,
|
||||||
);
|
);
|
||||||
|
|
||||||
return updatedMatch.data?.fetchManga?.manga ?? match;
|
if (updatedMatch.data?.fetchManga?.manga) {
|
||||||
|
return {
|
||||||
|
manga: updatedMatch.data.fetchManga.manga,
|
||||||
|
chapters: updatedMatch.data.fetchChapters?.chapters ?? null,
|
||||||
|
};
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// ignore
|
// ignore
|
||||||
}
|
}
|
||||||
|
|
||||||
return match;
|
return {
|
||||||
|
manga: match,
|
||||||
|
chapters: null,
|
||||||
|
};
|
||||||
})();
|
})();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -801,7 +814,12 @@ export class MigrationManager {
|
|||||||
mainSignal: AbortSignal,
|
mainSignal: AbortSignal,
|
||||||
options: MigrationBulkSearchSettings,
|
options: MigrationBulkSearchSettings,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const { selectHighestChapterNumberSource, ignoreOutdatedMatches, requireAdditionalChapters } = options;
|
const {
|
||||||
|
selectHighestChapterNumberSource,
|
||||||
|
ignoreOutdatedMatches,
|
||||||
|
requireAdditionalChapters,
|
||||||
|
ignoreWithMissingChapters,
|
||||||
|
} = options;
|
||||||
|
|
||||||
const state = MigrationManager.getState();
|
const state = MigrationManager.getState();
|
||||||
const entry = state.entries[mangaId];
|
const entry = state.entries[mangaId];
|
||||||
@@ -873,9 +891,11 @@ export class MigrationManager {
|
|||||||
: null;
|
: null;
|
||||||
|
|
||||||
const newMatches = foundMatches.filter((newMatch) =>
|
const newMatches = foundMatches.filter((newMatch) =>
|
||||||
draftEntry.searchMatches.every((existingMatch) => newMatch.id !== existingMatch.id),
|
draftEntry.searchMatches.every(
|
||||||
|
(existingMatch) => newMatch.manga.id !== existingMatch.id,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
const matches = newMatches.map((manga) => ({
|
const matches = newMatches.map(({ manga, chapters }) => ({
|
||||||
id: manga.id,
|
id: manga.id,
|
||||||
title: manga.title,
|
title: manga.title,
|
||||||
artist: manga.artist,
|
artist: manga.artist,
|
||||||
@@ -884,6 +904,7 @@ export class MigrationManager {
|
|||||||
thumbnailUrl: manga.thumbnailUrl,
|
thumbnailUrl: manga.thumbnailUrl,
|
||||||
sourceId: manga.sourceId,
|
sourceId: manga.sourceId,
|
||||||
sourceTitle: manga.source?.displayName,
|
sourceTitle: manga.source?.displayName,
|
||||||
|
missingChapters: chapters ? Chapters.getMissingCount(chapters) : undefined,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
draftEntry.destSourceIdToSearchState[destSourceId] = true;
|
draftEntry.destSourceIdToSearchState[destSourceId] = true;
|
||||||
@@ -921,6 +942,8 @@ export class MigrationManager {
|
|||||||
|
|
||||||
const ignoreOutdatedMatch = ignoreOutdatedMatches && isOutdated;
|
const ignoreOutdatedMatch = ignoreOutdatedMatches && isOutdated;
|
||||||
const satisfiesRequireAdditionalChapters = !requireAdditionalChapters || hasNewerChapter;
|
const satisfiesRequireAdditionalChapters = !requireAdditionalChapters || hasNewerChapter;
|
||||||
|
const ignoreBecauseMissingChapters =
|
||||||
|
ignoreWithMissingChapters && !!bestMatch.missingChapters;
|
||||||
const isPreferredSourcePriorityMatch =
|
const isPreferredSourcePriorityMatch =
|
||||||
hasHigherSourcePriority && !selectHighestChapterNumberSource;
|
hasHigherSourcePriority && !selectHighestChapterNumberSource;
|
||||||
const isPreferredChapterNumberMatch =
|
const isPreferredChapterNumberMatch =
|
||||||
@@ -933,6 +956,7 @@ export class MigrationManager {
|
|||||||
!draftEntry.isManualSelection &&
|
!draftEntry.isManualSelection &&
|
||||||
!ignoreOutdatedMatch &&
|
!ignoreOutdatedMatch &&
|
||||||
satisfiesRequireAdditionalChapters &&
|
satisfiesRequireAdditionalChapters &&
|
||||||
|
!ignoreBecauseMissingChapters &&
|
||||||
(isPreferredSourcePriorityMatch || isPreferredChapterNumberMatch);
|
(isPreferredSourcePriorityMatch || isPreferredChapterNumberMatch);
|
||||||
if (isPreferredMatch) {
|
if (isPreferredMatch) {
|
||||||
draftEntry.selectedMatchMangaId = bestMatch.id;
|
draftEntry.selectedMatchMangaId = bestMatch.id;
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ export const MigrationBulkSearchOptionsDialog = ({
|
|||||||
|
|
||||||
const [selectHighestChapterNumberSource, setSelectHighestChapterNumberSource] = useState(false);
|
const [selectHighestChapterNumberSource, setSelectHighestChapterNumberSource] = useState(false);
|
||||||
const [ignoreOutdatedMatches, setIgnoreOutdatedMatches] = useState(false);
|
const [ignoreOutdatedMatches, setIgnoreOutdatedMatches] = useState(false);
|
||||||
|
const [ignoreWithMissingChapters, setIgnoreWithMissingChapters] = useState(false);
|
||||||
const [requireAdditionalChapters, setRequireAdditionalChapters] = useState(false);
|
const [requireAdditionalChapters, setRequireAdditionalChapters] = useState(false);
|
||||||
const [performAdvancedSearch, setPerformAdvancedSearch] = useState(false);
|
const [performAdvancedSearch, setPerformAdvancedSearch] = useState(false);
|
||||||
|
|
||||||
@@ -49,7 +50,7 @@ export const MigrationBulkSearchOptionsDialog = ({
|
|||||||
<Typography
|
<Typography
|
||||||
variant="body2"
|
variant="body2"
|
||||||
color="textSecondary"
|
color="textSecondary"
|
||||||
>{t`Only automatically select matches if they have at least the same latest chapter. They will still be shown in the found matches`}</Typography>
|
>{t`Automatically select matches if they have at least the same latest chapter`}</Typography>
|
||||||
</Stack>
|
</Stack>
|
||||||
}
|
}
|
||||||
sx={{
|
sx={{
|
||||||
@@ -70,7 +71,7 @@ export const MigrationBulkSearchOptionsDialog = ({
|
|||||||
<Typography
|
<Typography
|
||||||
variant="body2"
|
variant="body2"
|
||||||
color="textSecondary"
|
color="textSecondary"
|
||||||
>{t`Only automatically select matches if they have additional chapters. They will still be shown in the found matches`}</Typography>
|
>{t`Automatically select matches if they have additional chapters`}</Typography>
|
||||||
</Stack>
|
</Stack>
|
||||||
}
|
}
|
||||||
sx={{
|
sx={{
|
||||||
@@ -79,6 +80,27 @@ export const MigrationBulkSearchOptionsDialog = ({
|
|||||||
checked={requireAdditionalChapters}
|
checked={requireAdditionalChapters}
|
||||||
onChange={(_, checked) => setRequireAdditionalChapters(checked)}
|
onChange={(_, checked) => setRequireAdditionalChapters(checked)}
|
||||||
/>
|
/>
|
||||||
|
<CheckboxInput
|
||||||
|
label={
|
||||||
|
<Stack
|
||||||
|
sx={{
|
||||||
|
// Padding comes from the MUI Checkbox component
|
||||||
|
pt: '9px',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography>{t`Ignore matches with missing chapters`}</Typography>
|
||||||
|
<Typography
|
||||||
|
variant="body2"
|
||||||
|
color="textSecondary"
|
||||||
|
>{t`Automatically select matches if they have no missing chapters`}</Typography>
|
||||||
|
</Stack>
|
||||||
|
}
|
||||||
|
sx={{
|
||||||
|
alignItems: 'start',
|
||||||
|
}}
|
||||||
|
checked={ignoreWithMissingChapters}
|
||||||
|
onChange={(_, checked) => setIgnoreWithMissingChapters(checked)}
|
||||||
|
/>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogContent dividers>
|
<DialogContent dividers>
|
||||||
<Stack
|
<Stack
|
||||||
@@ -152,6 +174,7 @@ export const MigrationBulkSearchOptionsDialog = ({
|
|||||||
selectHighestChapterNumberSource,
|
selectHighestChapterNumberSource,
|
||||||
ignoreOutdatedMatches,
|
ignoreOutdatedMatches,
|
||||||
requireAdditionalChapters,
|
requireAdditionalChapters,
|
||||||
|
ignoreWithMissingChapters,
|
||||||
performAdvancedSearch,
|
performAdvancedSearch,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,22 +11,44 @@ import Typography from '@mui/material/Typography';
|
|||||||
import { useLingui } from '@lingui/react/macro';
|
import { useLingui } from '@lingui/react/macro';
|
||||||
|
|
||||||
export const MigrationEntryMetadataText = (
|
export const MigrationEntryMetadataText = (
|
||||||
entry: Pick<MigrationMatch, 'artist' | 'author' | 'latestChapterNumber'>,
|
entry: Pick<MigrationMatch, 'artist' | 'author' | 'latestChapterNumber' | 'missingChapters'>,
|
||||||
) => {
|
) => {
|
||||||
const { t } = useLingui();
|
const { t } = useLingui();
|
||||||
|
|
||||||
const latestChapterNumber = (entry.latestChapterNumber ?? 0) > 1 ? entry.latestChapterNumber : t`Unknown`;
|
const latestChapterNumber = (entry.latestChapterNumber ?? 0) > 1 ? entry.latestChapterNumber : t`Unknown`;
|
||||||
const latestChapter = t`Latest: ${latestChapterNumber}`;
|
const isSameArtistAuthor = entry.artist === entry.author;
|
||||||
|
|
||||||
const artist = entry.artist ? `${entry.artist} - ` : '';
|
const nodes = [
|
||||||
const author = entry.author ? `${entry.author} - ` : '';
|
entry.author && (
|
||||||
const isSameArtistAuthor = artist === author;
|
<Typography sx={{ display: 'inline-flex' }} key="author" variant="inherit">
|
||||||
const artistAuthor = isSameArtistAuthor ? artist : `${artist}${author}`;
|
{entry.author}
|
||||||
|
</Typography>
|
||||||
|
),
|
||||||
|
!isSameArtistAuthor && entry.artist ? (
|
||||||
|
<Typography sx={{ display: 'inline-flex' }} key="artist" variant="inherit">
|
||||||
|
{entry.artist}
|
||||||
|
</Typography>
|
||||||
|
) : null,
|
||||||
|
<Typography sx={{ display: 'inline-flex' }} key="latest-chapter-number" variant="inherit">
|
||||||
|
{t`Latest: ${latestChapterNumber}`}
|
||||||
|
</Typography>,
|
||||||
|
entry.missingChapters ? (
|
||||||
|
<Typography sx={{ display: 'inline-flex' }} key="missing-chapters" variant="inherit" color="warning">
|
||||||
|
{t`Missing: ${entry.missingChapters}`}
|
||||||
|
</Typography>
|
||||||
|
) : null,
|
||||||
|
]
|
||||||
|
.filter((node) => node !== null)
|
||||||
|
.map((node, index, array) => (
|
||||||
|
<>
|
||||||
|
{node}
|
||||||
|
{index < array.length - 1 && ' - '}
|
||||||
|
</>
|
||||||
|
));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Typography variant="body2" color="textSecondary">
|
<Typography variant="body2" color="textSecondary">
|
||||||
{artistAuthor}
|
{nodes}
|
||||||
{latestChapter}
|
|
||||||
</Typography>
|
</Typography>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ export const MigrationSourceEntry = memo((entry: TMigrationEntry) => {
|
|||||||
mangaArtist,
|
mangaArtist,
|
||||||
mangaAuthor,
|
mangaAuthor,
|
||||||
latestChapterNumber,
|
latestChapterNumber,
|
||||||
|
missingChapters,
|
||||||
searchMatches,
|
searchMatches,
|
||||||
status,
|
status,
|
||||||
} = entry;
|
} = entry;
|
||||||
@@ -50,6 +51,7 @@ export const MigrationSourceEntry = memo((entry: TMigrationEntry) => {
|
|||||||
artist={mangaArtist}
|
artist={mangaArtist}
|
||||||
author={mangaAuthor}
|
author={mangaAuthor}
|
||||||
latestChapterNumber={latestChapterNumber}
|
latestChapterNumber={latestChapterNumber}
|
||||||
|
missingChapters={missingChapters}
|
||||||
/>
|
/>
|
||||||
</Stack>
|
</Stack>
|
||||||
<Box sx={{ display: 'flex', gap: 4, alignItems: 'center' }}>
|
<Box sx={{ display: 'flex', gap: 4, alignItems: 'center' }}>
|
||||||
@@ -91,6 +93,7 @@ export const MigrationSourceEntry = memo((entry: TMigrationEntry) => {
|
|||||||
artist={mangaArtist}
|
artist={mangaArtist}
|
||||||
author={mangaAuthor}
|
author={mangaAuthor}
|
||||||
latestChapterNumber={latestChapterNumber}
|
latestChapterNumber={latestChapterNumber}
|
||||||
|
missingChapters={missingChapters}
|
||||||
/>
|
/>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -518,6 +518,18 @@ msgstr "Automatically mark chapters as read when you download them."
|
|||||||
msgid "Automatically refresh metadata"
|
msgid "Automatically refresh metadata"
|
||||||
msgstr "Automatically refresh metadata"
|
msgstr "Automatically refresh metadata"
|
||||||
|
|
||||||
|
#: src/features/migration/components/MigrationBulkSearchOptionsDialog.tsx
|
||||||
|
msgid "Automatically select matches if they have additional chapters"
|
||||||
|
msgstr "Automatically select matches if they have additional chapters"
|
||||||
|
|
||||||
|
#: src/features/migration/components/MigrationBulkSearchOptionsDialog.tsx
|
||||||
|
msgid "Automatically select matches if they have at least the same latest chapter"
|
||||||
|
msgstr "Automatically select matches if they have at least the same latest chapter"
|
||||||
|
|
||||||
|
#: src/features/migration/components/MigrationBulkSearchOptionsDialog.tsx
|
||||||
|
msgid "Automatically select matches if they have no missing chapters"
|
||||||
|
msgstr "Automatically select matches if they have no missing chapters"
|
||||||
|
|
||||||
#: src/features/reader/settings/behaviour/ReaderBehaviourSettings.tsx
|
#: src/features/reader/settings/behaviour/ReaderBehaviourSettings.tsx
|
||||||
msgid "Automatically use webtoon mode for entries that are detected to likely use the long strip format"
|
msgid "Automatically use webtoon mode for entries that are detected to likely use the long strip format"
|
||||||
msgstr "Automatically use webtoon mode for entries that are detected to likely use the long strip format"
|
msgstr "Automatically use webtoon mode for entries that are detected to likely use the long strip format"
|
||||||
@@ -1845,6 +1857,10 @@ msgstr "Ignore filters when searching"
|
|||||||
msgid "Ignore matches that are behind in chapters"
|
msgid "Ignore matches that are behind in chapters"
|
||||||
msgstr "Ignore matches that are behind in chapters"
|
msgstr "Ignore matches that are behind in chapters"
|
||||||
|
|
||||||
|
#: src/features/migration/components/MigrationBulkSearchOptionsDialog.tsx
|
||||||
|
msgid "Ignore matches with missing chapters"
|
||||||
|
msgstr "Ignore matches with missing chapters"
|
||||||
|
|
||||||
#: src/features/migration/components/MigrationBulkSearchOptionsDialog.tsx
|
#: src/features/migration/components/MigrationBulkSearchOptionsDialog.tsx
|
||||||
msgid "Ignore matches without newer chapters"
|
msgid "Ignore matches without newer chapters"
|
||||||
msgstr "Ignore matches without newer chapters"
|
msgstr "Ignore matches without newer chapters"
|
||||||
@@ -2375,6 +2391,11 @@ msgstr "Minute"
|
|||||||
msgid "Misc"
|
msgid "Misc"
|
||||||
msgstr "Misc"
|
msgstr "Misc"
|
||||||
|
|
||||||
|
#. placeholder {0}: entry.missingChapters
|
||||||
|
#: src/features/migration/components/migration-entry/MigrationEntryMetadataText.tsx
|
||||||
|
msgid "Missing: {0}"
|
||||||
|
msgstr "Missing: {0}"
|
||||||
|
|
||||||
#: src/features/reader/overlay/settings/ReaderSettingOverlayMode.tsx
|
#: src/features/reader/overlay/settings/ReaderSettingOverlayMode.tsx
|
||||||
msgid "Mobile"
|
msgid "Mobile"
|
||||||
msgstr "Mobile"
|
msgstr "Mobile"
|
||||||
@@ -2558,14 +2579,6 @@ msgstr "Oneshot"
|
|||||||
msgid "Ongoing"
|
msgid "Ongoing"
|
||||||
msgstr "Ongoing"
|
msgstr "Ongoing"
|
||||||
|
|
||||||
#: src/features/migration/components/MigrationBulkSearchOptionsDialog.tsx
|
|
||||||
msgid "Only automatically select matches if they have additional chapters. They will still be shown in the found matches"
|
|
||||||
msgstr "Only automatically select matches if they have additional chapters. They will still be shown in the found matches"
|
|
||||||
|
|
||||||
#: src/features/migration/components/MigrationBulkSearchOptionsDialog.tsx
|
|
||||||
msgid "Only automatically select matches if they have at least the same latest chapter. They will still be shown in the found matches"
|
|
||||||
msgstr "Only automatically select matches if they have at least the same latest chapter. They will still be shown in the found matches"
|
|
||||||
|
|
||||||
#: src/features/migration/Migration.constants.ts
|
#: src/features/migration/Migration.constants.ts
|
||||||
msgid "Only outdated matches found"
|
msgid "Only outdated matches found"
|
||||||
msgstr "Only outdated matches found"
|
msgstr "Only outdated matches found"
|
||||||
|
|||||||
Reference in New Issue
Block a user