feat(sync): aggregate books with metadata hash for progress and annotation sync (#2062)

This commit is contained in:
Huang Xin
2025-09-18 20:05:16 +08:00
committed by GitHub
parent e0c5acf4c8
commit 91a5454b46
24 changed files with 284 additions and 101 deletions
@@ -185,7 +185,6 @@ const BooksGrid: React.FC<BooksGridProps> = ({ bookKeys, onCloseBook }) => {
{showFooter && (
<ProgressInfoView
bookKey={bookKey}
bookFormat={book.format}
section={section}
pageinfo={pageinfo}
timeinfo={timeinfo}
@@ -5,11 +5,11 @@ import { PageInfo, TimeInfo } from '@/types/book';
import { useEnv } from '@/context/EnvContext';
import { useReaderStore } from '@/store/readerStore';
import { useTranslation } from '@/hooks/useTranslation';
import { useBookDataStore } from '@/store/bookDataStore';
import { formatReadingProgress } from '@/utils/progress';
interface PageInfoProps {
bookKey: string;
bookFormat: string;
section?: PageInfo;
pageinfo?: PageInfo;
timeinfo?: TimeInfo;
@@ -20,7 +20,6 @@ interface PageInfoProps {
const ProgressInfoView: React.FC<PageInfoProps> = ({
bookKey,
bookFormat,
section,
pageinfo,
timeinfo,
@@ -30,8 +29,10 @@ const ProgressInfoView: React.FC<PageInfoProps> = ({
}) => {
const _ = useTranslation();
const { appService } = useEnv();
const { getBookData } = useBookDataStore();
const { getView, getViewSettings } = useReaderStore();
const view = getView(bookKey);
const bookData = getBookData(bookKey);
const viewSettings = getViewSettings(bookKey)!;
const showDoubleBorder = viewSettings.vertical && viewSettings.doubleBorder;
@@ -46,8 +47,8 @@ const ProgressInfoView: React.FC<PageInfoProps> = ({
: '{current} / {total}'
: '{percent}%';
const pageProgress = ['PDF', 'CBZ'].includes(bookFormat) ? section : pageinfo;
const progressInfo = ['PDF', 'CBZ'].includes(bookFormat)
const pageProgress = bookData?.isFixedLayout ? section : pageinfo;
const progressInfo = bookData?.isFixedLayout
? formatReadingProgress(pageProgress?.current, pageProgress?.total, formatTemplate)
: formatReadingProgress(pageProgress?.current, pageProgress?.total, formatTemplate);
@@ -41,10 +41,11 @@ const ViewMenu: React.FC<ViewMenuProps> = ({
const { user } = useAuth();
const { envConfig, appService } = useEnv();
const { getConfig, getBookData } = useBookDataStore();
const { getView, getViewSettings, setViewSettings } = useReaderStore();
const { getView, getViewSettings, getViewState, setViewSettings } = useReaderStore();
const config = getConfig(bookKey)!;
const bookData = getBookData(bookKey)!;
const viewSettings = getViewSettings(bookKey)!;
const viewState = getViewState(bookKey);
const { themeMode, isDarkMode, setThemeMode } = useThemeStore();
const [isScrolledMode, setScrolledMode] = useState(viewSettings!.scrolled);
@@ -259,6 +260,7 @@ const ViewMenu: React.FC<ViewMenuProps> = ({
: _('Never synced')
}
Icon={user ? MdSync : MdSyncProblem}
iconClassName={user && viewState?.syncing ? 'animate-reverse-spin' : ''}
onClick={handleSync}
/>
@@ -14,6 +14,7 @@ import { isWebAppPlatform } from '@/services/environment';
import { eventDispatcher } from '@/utils/event';
import { DOWNLOAD_READEST_URL } from '@/services/constants';
import { setKOSyncSettingsWindowVisible } from '@/app/reader/components/KOSyncSettings';
import { FIXED_LAYOUT_FORMATS } from '@/types/book';
import useBooksManager from '../../hooks/useBooksManager';
import MenuItem from '@/components/MenuItem';
@@ -104,7 +105,7 @@ const BookMenu: React.FC<BookMenuProps> = ({ menuClassName, setIsDropdownOpen })
>
<ul className='max-h-60 overflow-y-auto'>
{getVisibleLibrary()
.filter((book) => book.format !== 'PDF' && book.format !== 'CBZ')
.filter((book) => !FIXED_LAYOUT_FORMATS.has(book.format))
.filter((book) => !!book.downloadedAt)
.slice(0, 20)
.map((book) => (