sync: also update deleted notes in synchronization, closes #1356 (#1357)

This commit is contained in:
Huang Xin
2025-06-06 17:47:26 +08:00
committed by GitHub
parent f2309ef496
commit ebe1c10c84
4 changed files with 35 additions and 50 deletions
@@ -1,10 +1,11 @@
import { useEffect, useRef } from 'react';
import { useCallback, useEffect, useRef } from 'react';
import { useAuth } from '@/context/AuthContext';
import { useEnv } from '@/context/EnvContext';
import { useSync } from '@/hooks/useSync';
import { useLibraryStore } from '@/store/libraryStore';
import { SYNC_BOOKS_INTERVAL_SEC } from '@/services/constants';
import { Book } from '@/types/book';
import { SYNC_BOOKS_INTERVAL_SEC } from '@/services/constants';
import { debounce } from '@/utils/debounce';
export interface UseBooksSyncProps {
onSyncStart?: () => void;
@@ -38,9 +39,6 @@ export const useBooksSync = ({ onSyncStart, onSyncEnd }: UseBooksSyncProps) => {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const lastSyncTime = useRef<number>(0);
const syncTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
const getNewBooks = () => {
if (!user) return [];
const newBooks = library.filter(
@@ -49,26 +47,18 @@ export const useBooksSync = ({ onSyncStart, onSyncEnd }: UseBooksSyncProps) => {
return newBooks;
};
useEffect(() => {
if (!user) return;
const now = Date.now();
const timeSinceLastSync = now - lastSyncTime.current;
if (timeSinceLastSync > SYNC_BOOKS_INTERVAL_SEC * 1000) {
lastSyncTime.current = now;
// eslint-disable-next-line react-hooks/exhaustive-deps
const handleAutoSync = useCallback(
debounce(() => {
const newBooks = getNewBooks();
syncBooks(newBooks, 'both');
} else {
if (syncTimeoutRef.current) clearTimeout(syncTimeoutRef.current);
syncTimeoutRef.current = setTimeout(
() => {
lastSyncTime.current = Date.now();
const newBooks = getNewBooks();
syncBooks(newBooks, 'both');
syncTimeoutRef.current = null;
},
SYNC_BOOKS_INTERVAL_SEC * 1000 - timeSinceLastSync,
);
}
}, SYNC_BOOKS_INTERVAL_SEC * 1000),
[library, lastSyncedAtBooks],
);
useEffect(() => {
if (!user) return;
handleAutoSync();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [library]);
@@ -1,9 +1,10 @@
import { useEffect, useRef } from 'react';
import { useCallback, useEffect } from 'react';
import { useAuth } from '@/context/AuthContext';
import { useSync } from '@/hooks/useSync';
import { BookNote } from '@/types/book';
import { useBookDataStore } from '@/store/bookDataStore';
import { SYNC_NOTES_INTERVAL_SEC } from '@/services/constants';
import { debounce } from '@/utils/debounce';
export const useNotesSync = (bookKey: string) => {
const { user } = useAuth();
@@ -13,10 +14,8 @@ export const useNotesSync = (bookKey: string) => {
const config = getConfig(bookKey);
const bookHash = bookKey.split('-')[0]!;
const lastSyncTime = useRef<number>(0);
const syncTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
const getNewNotes = () => {
const config = getConfig(bookKey);
if (!config?.location || !user) return [];
const bookNotes = config.booknotes ?? [];
const newNotes = bookNotes.filter(
@@ -28,35 +27,31 @@ export const useNotesSync = (bookKey: string) => {
return newNotes;
};
useEffect(() => {
if (!config?.location || !user) return;
const now = Date.now();
const timeSinceLastSync = now - lastSyncTime.current;
if (timeSinceLastSync > SYNC_NOTES_INTERVAL_SEC * 1000) {
lastSyncTime.current = now;
// eslint-disable-next-line react-hooks/exhaustive-deps
const handleAutoSync = useCallback(
debounce(() => {
const newNotes = getNewNotes();
syncNotes(newNotes, bookHash, 'both');
} else {
if (syncTimeoutRef.current) clearTimeout(syncTimeoutRef.current);
syncTimeoutRef.current = setTimeout(
() => {
lastSyncTime.current = Date.now();
const newNotes = getNewNotes();
syncNotes(newNotes, bookHash, 'both');
syncTimeoutRef.current = null;
},
SYNC_NOTES_INTERVAL_SEC * 1000 - timeSinceLastSync,
);
}
}, SYNC_NOTES_INTERVAL_SEC * 1000),
[lastSyncedAtNotes],
);
useEffect(() => {
if (!config?.location || !user) return;
handleAutoSync();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [config]);
useEffect(() => {
const processNewNote = (note: BookNote) => {
const config = getConfig(bookKey);
const oldNotes = config?.booknotes ?? [];
const existingNote = oldNotes.find((oldNote) => oldNote.id === note.id);
if (existingNote) {
if (existingNote.updatedAt < note.updatedAt) {
if (
existingNote.updatedAt < note.updatedAt ||
(existingNote.deletedAt ?? 0) < (note.deletedAt ?? 0)
) {
return { ...existingNote, ...note };
} else {
return { ...note, ...existingNote };
@@ -69,7 +69,7 @@ export const useProgressSync = (bookKey: string) => {
}, [bookKey]);
// eslint-disable-next-line react-hooks/exhaustive-deps
const debouncedAutoSync = useCallback(
const handleAutoSync = useCallback(
debounce(() => {
syncConfig();
}, SYNC_PROGRESS_INTERVAL_SEC * 1000),
@@ -79,7 +79,7 @@ export const useProgressSync = (bookKey: string) => {
// Push: auto-push progress when progress changes with a debounce
useEffect(() => {
if (!progress?.location || !user) return;
debouncedAutoSync();
handleAutoSync();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [progress]);
+2 -2
View File
@@ -521,8 +521,8 @@ export const READEST_UPDATER_FILE = `${GITHUB_LATEST_DOWNLOAD}/latest.json`;
export const READEST_CHANGELOG_FILE = `${GITHUB_LATEST_DOWNLOAD}/release-notes.json`;
export const SYNC_PROGRESS_INTERVAL_SEC = 3;
export const SYNC_NOTES_INTERVAL_SEC = 10;
export const SYNC_BOOKS_INTERVAL_SEC = 10;
export const SYNC_NOTES_INTERVAL_SEC = 5;
export const SYNC_BOOKS_INTERVAL_SEC = 5;
export const CHECK_UPDATE_INTERVAL_SEC = 24 * 60 * 60;
export const MAX_ZOOM_LEVEL = 500;