Read chapter download status from cache
Instead of getting the whole download status, which contains all queued/active downloads, the download status should be read from the cache for only the required chapters
This commit is contained in:
@@ -87,6 +87,8 @@ const ScrollToTop = () => {
|
|||||||
* and thus, data of existing chapters/mangas in the cache get outdated
|
* and thus, data of existing chapters/mangas in the cache get outdated
|
||||||
*/
|
*/
|
||||||
const BackgroundSubscriptions = () => {
|
const BackgroundSubscriptions = () => {
|
||||||
|
// load the full download status once on startup to fill the cache
|
||||||
|
requestManager.useGetDownloadStatus({ nextFetchPolicy: 'standby' });
|
||||||
requestManager.useDownloadSubscription();
|
requestManager.useDownloadSubscription();
|
||||||
requestManager.useUpdaterSubscription();
|
requestManager.useUpdaterSubscription();
|
||||||
requestManager.useWebUIUpdateSubscription();
|
requestManager.useWebUIUpdateSubscription();
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
import gql from 'graphql-tag';
|
import gql from 'graphql-tag';
|
||||||
|
|
||||||
const DOWNLOAD_TYPE_FIELDS = gql`
|
export const DOWNLOAD_TYPE_FIELDS = gql`
|
||||||
fragment DOWNLOAD_TYPE_FIELDS on DownloadType {
|
fragment DOWNLOAD_TYPE_FIELDS on DownloadType {
|
||||||
chapter {
|
chapter {
|
||||||
id
|
id
|
||||||
|
|||||||
@@ -100,8 +100,7 @@ export const ChapterList = ({
|
|||||||
|
|
||||||
const scrollbarWidth = MediaQuery.useGetScrollbarSize('width');
|
const scrollbarWidth = MediaQuery.useGetScrollbarSize('width');
|
||||||
|
|
||||||
const { data: downloaderData } = requestManager.useGetDownloadStatus();
|
const downloadSubscription = requestManager.useDownloadSubscription();
|
||||||
const queue = downloaderData?.downloadStatus.queue ?? [];
|
|
||||||
|
|
||||||
const [options, dispatch] = useChapterOptions(manga.id);
|
const [options, dispatch] = useChapterOptions(manga.id);
|
||||||
const {
|
const {
|
||||||
@@ -132,15 +131,14 @@ export const ChapterList = ({
|
|||||||
const chaptersWithMeta: IChapterWithMeta[] = useMemo(
|
const chaptersWithMeta: IChapterWithMeta[] = useMemo(
|
||||||
() =>
|
() =>
|
||||||
visibleChapters.map((chapter) => {
|
visibleChapters.map((chapter) => {
|
||||||
const downloadChapter = queue?.find((cd) => cd.chapter.id === chapter.id);
|
|
||||||
const selected = !areNoItemsSelected ? selectedItemIds.includes(chapter.id) : null;
|
const selected = !areNoItemsSelected ? selectedItemIds.includes(chapter.id) : null;
|
||||||
return {
|
return {
|
||||||
chapter,
|
chapter,
|
||||||
downloadChapter,
|
downloadChapter: Chapters.getDownloadStatusFromCache(chapter.id),
|
||||||
selected,
|
selected,
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
[queue, selectedItemIds, visibleChapters],
|
[downloadSubscription.data?.downloadStatusChanged, selectedItemIds, visibleChapters],
|
||||||
);
|
);
|
||||||
|
|
||||||
const chapterListFAB = useMemo(() => {
|
const chapterListFAB = useMemo(() => {
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ import { TypographyMaxLines } from '@/modules/core/components/TypographyMaxLines
|
|||||||
import {
|
import {
|
||||||
ChapterBookmarkInfo,
|
ChapterBookmarkInfo,
|
||||||
ChapterDownloadInfo,
|
ChapterDownloadInfo,
|
||||||
ChapterDownloadStatus,
|
|
||||||
ChapterIdInfo,
|
ChapterIdInfo,
|
||||||
ChapterMangaInfo,
|
ChapterMangaInfo,
|
||||||
ChapterNumberInfo,
|
ChapterNumberInfo,
|
||||||
@@ -39,7 +38,7 @@ import {
|
|||||||
Chapters,
|
Chapters,
|
||||||
ChapterScanlatorInfo,
|
ChapterScanlatorInfo,
|
||||||
} from '@/modules/chapter/services/Chapters.ts';
|
} from '@/modules/chapter/services/Chapters.ts';
|
||||||
import { ChaptersWithMeta } from '@/modules/chapter/services/ChaptersWithMeta.ts';
|
import { ChaptersWithMeta, ChapterWithMetaType } from '@/modules/chapter/services/ChaptersWithMeta.ts';
|
||||||
|
|
||||||
type TChapter = ChapterIdInfo &
|
type TChapter = ChapterIdInfo &
|
||||||
ChapterMangaInfo &
|
ChapterMangaInfo &
|
||||||
@@ -54,7 +53,7 @@ interface IProps {
|
|||||||
mode?: 'manga.page' | 'reader';
|
mode?: 'manga.page' | 'reader';
|
||||||
chapter: TChapter;
|
chapter: TChapter;
|
||||||
allChapters: TChapter[];
|
allChapters: TChapter[];
|
||||||
downloadChapter: ChapterDownloadStatus | undefined;
|
downloadChapter: ChapterWithMetaType['downloadChapter'];
|
||||||
showChapterNumber: boolean;
|
showChapterNumber: boolean;
|
||||||
onSelect: (selected: boolean, isShiftKey?: boolean) => void;
|
onSelect: (selected: boolean, isShiftKey?: boolean) => void;
|
||||||
selected: boolean | null;
|
selected: boolean | null;
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import {
|
|||||||
ChapterListFieldsFragment,
|
ChapterListFieldsFragment,
|
||||||
ChapterType,
|
ChapterType,
|
||||||
DownloadStatusFieldsFragment,
|
DownloadStatusFieldsFragment,
|
||||||
|
DownloadTypeFieldsFragment,
|
||||||
} from '@/lib/graphql/generated/graphql.ts';
|
} from '@/lib/graphql/generated/graphql.ts';
|
||||||
import { CHAPTER_LIST_FIELDS } from '@/lib/graphql/fragments/ChapterFragments.ts';
|
import { CHAPTER_LIST_FIELDS } from '@/lib/graphql/fragments/ChapterFragments.ts';
|
||||||
|
|
||||||
@@ -24,6 +25,7 @@ import { MangaIdInfo } from '@/modules/manga/Manga.types.ts';
|
|||||||
import { ReaderResumeMode } from '@/modules/reader/types/Reader.types.ts';
|
import { ReaderResumeMode } from '@/modules/reader/types/Reader.types.ts';
|
||||||
import { AppRoutes } from '@/modules/core/AppRoute.constants.ts';
|
import { AppRoutes } from '@/modules/core/AppRoute.constants.ts';
|
||||||
import { getErrorMessage } from '@/lib/HelperFunctions.ts';
|
import { getErrorMessage } from '@/lib/HelperFunctions.ts';
|
||||||
|
import { DOWNLOAD_TYPE_FIELDS } from '@/lib/graphql/fragments/DownloadFragments.ts';
|
||||||
|
|
||||||
export type ChapterAction = 'download' | 'delete' | 'bookmark' | 'unbookmark' | 'mark_as_read' | 'mark_as_unread';
|
export type ChapterAction = 'download' | 'delete' | 'bookmark' | 'unbookmark' | 'mark_as_read' | 'mark_as_unread';
|
||||||
|
|
||||||
@@ -119,6 +121,23 @@ export class Chapters {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static getDownloadStatusFromCache<T = DownloadTypeFieldsFragment>(
|
||||||
|
id: number,
|
||||||
|
fragment: DocumentNode = DOWNLOAD_TYPE_FIELDS,
|
||||||
|
fragmentName: string = 'DOWNLOAD_TYPE_FIELDS',
|
||||||
|
): Unmasked<T> | null {
|
||||||
|
return requestManager.graphQLClient.client.cache.readFragment<T>({
|
||||||
|
id: requestManager.graphQLClient.client.cache.identify({
|
||||||
|
__typename: 'DownloadType',
|
||||||
|
chapter: {
|
||||||
|
__ref: requestManager.graphQLClient.client.cache.identify({ __typename: 'ChapterType', id }),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
fragment,
|
||||||
|
fragmentName,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
static getReaderUrl<Chapter extends ChapterMangaInfo & ChapterSourceOrderInfo>(chapter: Chapter): string {
|
static getReaderUrl<Chapter extends ChapterMangaInfo & ChapterSourceOrderInfo>(chapter: Chapter): string {
|
||||||
return AppRoutes.reader.path(chapter.mangaId, chapter.sourceOrder);
|
return AppRoutes.reader.path(chapter.mangaId, chapter.sourceOrder);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ export type ChapterWithMetaType<
|
|||||||
ChapterBookmarkInfo,
|
ChapterBookmarkInfo,
|
||||||
> = {
|
> = {
|
||||||
chapter: Chapter;
|
chapter: Chapter;
|
||||||
downloadChapter: ChapterDownloadStatus | undefined;
|
downloadChapter: ChapterDownloadStatus | undefined | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
export class ChaptersWithMeta {
|
export class ChaptersWithMeta {
|
||||||
|
|||||||
@@ -12,14 +12,14 @@ import { IChapterWithMeta } from '@/modules/chapter/components/ChapterList.tsx';
|
|||||||
import { ChapterCard } from '@/modules/chapter/components/cards/ChapterCard.tsx';
|
import { ChapterCard } from '@/modules/chapter/components/cards/ChapterCard.tsx';
|
||||||
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
||||||
import { ReaderStateChapters } from '@/modules/reader/types/Reader.types.ts';
|
import { ReaderStateChapters } from '@/modules/reader/types/Reader.types.ts';
|
||||||
|
import { Chapters } from '@/modules/chapter/services/Chapters';
|
||||||
|
|
||||||
export const ReaderChapterList = ({
|
export const ReaderChapterList = ({
|
||||||
currentChapter,
|
currentChapter,
|
||||||
chapters,
|
chapters,
|
||||||
style,
|
style,
|
||||||
}: Pick<ReaderStateChapters, 'chapters' | 'currentChapter'> & Pick<VirtuosoProps<any, any>, 'style'>) => {
|
}: Pick<ReaderStateChapters, 'chapters' | 'currentChapter'> & Pick<VirtuosoProps<any, any>, 'style'>) => {
|
||||||
const { data: downloaderData } = requestManager.useGetDownloadStatus();
|
const downloadSubscription = requestManager.useDownloadSubscription();
|
||||||
const queue = downloaderData?.downloadStatus.queue ?? [];
|
|
||||||
|
|
||||||
const currentChapterIndex = useMemo(
|
const currentChapterIndex = useMemo(
|
||||||
() => currentChapter && chapters.findIndex((chapter) => chapter.id === currentChapter.id),
|
() => currentChapter && chapters.findIndex((chapter) => chapter.id === currentChapter.id),
|
||||||
@@ -29,7 +29,7 @@ export const ReaderChapterList = ({
|
|||||||
const chaptersWithMeta: IChapterWithMeta[] = useMemo(
|
const chaptersWithMeta: IChapterWithMeta[] = useMemo(
|
||||||
() =>
|
() =>
|
||||||
chapters.map((chapter) => {
|
chapters.map((chapter) => {
|
||||||
const downloadChapter = queue?.find((cd) => cd.chapter.id === chapter.id);
|
const downloadChapter = Chapters.getDownloadStatusFromCache(chapter.id);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
chapter,
|
chapter,
|
||||||
@@ -37,7 +37,7 @@ export const ReaderChapterList = ({
|
|||||||
selected: null,
|
selected: null,
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
[queue, chapters],
|
[downloadSubscription.data?.downloadStatusChanged, chapters],
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -21,18 +21,16 @@ import { actionToTranslationKey, ChapterAction, Chapters } from '@/modules/chapt
|
|||||||
import { ReaderStateChapters } from '@/modules/reader/types/Reader.types.ts';
|
import { ReaderStateChapters } from '@/modules/reader/types/Reader.types.ts';
|
||||||
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
||||||
import { DownloadStateIndicator } from '@/modules/core/components/DownloadStateIndicator.tsx';
|
import { DownloadStateIndicator } from '@/modules/core/components/DownloadStateIndicator.tsx';
|
||||||
import { DownloadStatusFieldsFragment } from '@/lib/graphql/generated/graphql.ts';
|
|
||||||
import { ReaderStatePages } from '@/modules/reader/types/ReaderProgressBar.types.ts';
|
import { ReaderStatePages } from '@/modules/reader/types/ReaderProgressBar.types.ts';
|
||||||
import { withPropsFrom } from '@/modules/core/hoc/withPropsFrom.tsx';
|
import { withPropsFrom } from '@/modules/core/hoc/withPropsFrom.tsx';
|
||||||
import { useReaderStateChaptersContext } from '@/modules/reader/contexts/state/ReaderStateChaptersContext.tsx';
|
import { useReaderStateChaptersContext } from '@/modules/reader/contexts/state/ReaderStateChaptersContext.tsx';
|
||||||
import { userReaderStatePagesContext } from '@/modules/reader/contexts/state/ReaderStatePagesContext.tsx';
|
import { userReaderStatePagesContext } from '@/modules/reader/contexts/state/ReaderStatePagesContext.tsx';
|
||||||
|
import { ChapterWithMetaType } from '@/modules/chapter/services/ChaptersWithMeta.ts';
|
||||||
|
|
||||||
const DownloadButton = ({
|
const DownloadButton = ({
|
||||||
currentChapter,
|
currentChapter,
|
||||||
downloadChapter,
|
downloadChapter,
|
||||||
}: Required<Pick<ReaderStateChapters, 'currentChapter'>> & {
|
}: Required<Pick<ReaderStateChapters, 'currentChapter'>> & Pick<ChapterWithMetaType, 'downloadChapter'>) => {
|
||||||
downloadChapter?: DownloadStatusFieldsFragment['queue'][number];
|
|
||||||
}) => {
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
if (currentChapter && Chapters.isDownloaded(currentChapter)) {
|
if (currentChapter && Chapters.isDownloaded(currentChapter)) {
|
||||||
@@ -76,13 +74,15 @@ const BaseReaderNavBarDesktopActions = memo(
|
|||||||
|
|
||||||
const pageRetryKeyPrefix = useRef<number>(0);
|
const pageRetryKeyPrefix = useRef<number>(0);
|
||||||
|
|
||||||
const { data: downloaderData } = requestManager.useGetDownloadStatus();
|
const downloadSubscription = requestManager.useDownloadSubscription();
|
||||||
const queue = downloaderData?.downloadStatus.queue ?? [];
|
|
||||||
|
|
||||||
const downloadChapter = useMemo(
|
const downloadChapter = useMemo(() => {
|
||||||
() => queue.find((queueItem) => queueItem.chapter.id === currentChapter?.id),
|
if (!currentChapter) {
|
||||||
[queue, id],
|
return null;
|
||||||
);
|
}
|
||||||
|
|
||||||
|
return Chapters.getDownloadStatusFromCache(currentChapter?.id);
|
||||||
|
}, [downloadSubscription.data?.downloadStatusChanged, id]);
|
||||||
|
|
||||||
const haveSomePagesFailedToLoad = useMemo(
|
const haveSomePagesFailedToLoad = useMemo(
|
||||||
() => pageLoadStates.some((pageLoadState) => pageLoadState.error),
|
() => pageLoadStates.some((pageLoadState) => pageLoadState.error),
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ import { SpinnerImage } from '@/modules/core/components/SpinnerImage.tsx';
|
|||||||
import { dateTimeFormatter, epochToDate, getDateString } from '@/util/DateHelper.ts';
|
import { dateTimeFormatter, epochToDate, getDateString } from '@/util/DateHelper.ts';
|
||||||
import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts';
|
import { defaultPromiseErrorHandler } from '@/lib/DefaultPromiseErrorHandler.ts';
|
||||||
import { TypographyMaxLines } from '@/modules/core/components/TypographyMaxLines.tsx';
|
import { TypographyMaxLines } from '@/modules/core/components/TypographyMaxLines.tsx';
|
||||||
import { ChapterIdInfo, ChapterMangaInfo } from '@/modules/chapter/services/Chapters.ts';
|
import { ChapterIdInfo, Chapters } from '@/modules/chapter/services/Chapters.ts';
|
||||||
import { makeToast } from '@/modules/core/utils/Toast.ts';
|
import { makeToast } from '@/modules/core/utils/Toast.ts';
|
||||||
import { VirtuosoUtil } from '@/lib/virtuoso/Virtuoso.util.tsx';
|
import { VirtuosoUtil } from '@/lib/virtuoso/Virtuoso.util.tsx';
|
||||||
import { AppRoutes } from '@/modules/core/AppRoute.constants.ts';
|
import { AppRoutes } from '@/modules/core/AppRoute.constants.ts';
|
||||||
@@ -74,8 +74,8 @@ export const Updates: React.FC = () => {
|
|||||||
const updateEntries = chapterUpdateData?.chapters.nodes ?? [];
|
const updateEntries = chapterUpdateData?.chapters.nodes ?? [];
|
||||||
const groupedUpdates = useMemo(() => groupByDate(updateEntries), [updateEntries]);
|
const groupedUpdates = useMemo(() => groupByDate(updateEntries), [updateEntries]);
|
||||||
const groupCounts: number[] = useMemo(() => groupedUpdates.map((group) => group[1]), [groupedUpdates]);
|
const groupCounts: number[] = useMemo(() => groupedUpdates.map((group) => group[1]), [groupedUpdates]);
|
||||||
const { data: downloaderData } = requestManager.useGetDownloadStatus();
|
|
||||||
const queue = downloaderData?.downloadStatus.queue ?? [];
|
requestManager.useDownloadSubscription();
|
||||||
|
|
||||||
const computeItemKey = VirtuosoUtil.useCreateGroupedComputeItemKey(
|
const computeItemKey = VirtuosoUtil.useCreateGroupedComputeItemKey(
|
||||||
groupCounts,
|
groupCounts,
|
||||||
@@ -107,11 +107,6 @@ export const Updates: React.FC = () => {
|
|||||||
};
|
};
|
||||||
}, [t, lastUpdateTimestamp]);
|
}, [t, lastUpdateTimestamp]);
|
||||||
|
|
||||||
const downloadForChapter = (chapter: Pick<ChapterType, 'sourceOrder'> & ChapterMangaInfo) => {
|
|
||||||
const { sourceOrder, mangaId } = chapter;
|
|
||||||
return queue.find((q) => sourceOrder === q.chapter.sourceOrder && mangaId === q.manga.id);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleRetry = async (chapter: ChapterIdInfo) => {
|
const handleRetry = async (chapter: ChapterIdInfo) => {
|
||||||
try {
|
try {
|
||||||
await requestManager.addChapterToDownloadQueue(chapter.id).response;
|
await requestManager.addChapterToDownloadQueue(chapter.id).response;
|
||||||
@@ -186,7 +181,7 @@ export const Updates: React.FC = () => {
|
|||||||
itemContent={(index) => {
|
itemContent={(index) => {
|
||||||
const chapter = updateEntries[index];
|
const chapter = updateEntries[index];
|
||||||
const { manga } = chapter;
|
const { manga } = chapter;
|
||||||
const download = downloadForChapter(chapter);
|
const download = Chapters.getDownloadStatusFromCache(chapter.id);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledGroupItemWrapper>
|
<StyledGroupItemWrapper>
|
||||||
|
|||||||
Reference in New Issue
Block a user