sync: check local file availability before opening (#262)

This commit is contained in:
Huang Xin
2025-01-28 21:02:19 +01:00
committed by GitHub
parent 171a7ee759
commit c0d715bf77
6 changed files with 84 additions and 51 deletions
@@ -79,8 +79,27 @@ const Bookshelf: React.FC<BookshelfProps> = ({
const isImportingBook = useRef(false);
const [showDetailsBook, setShowDetailsBook] = useState<Book | null>(null);
const showBookDetailsModal = (book: Book) => {
setShowDetailsBook(book);
const makeBookAvailable = async (book: Book) => {
console.log('Make book available:', book);
if (book.uploadedAt && !book.downloadedAt) {
setLoading(true);
let available = false;
try {
await appService?.downloadBook(book);
updateBook(envConfig, book);
available = true;
} finally {
setLoading(false);
return available;
}
}
return true;
};
const showBookDetailsModal = async (book: Book) => {
if (await makeBookAvailable(book)) {
setShowDetailsBook(book);
}
};
const dismissBookDetailsModal = () => {
@@ -115,15 +134,8 @@ const Bookshelf: React.FC<BookshelfProps> = ({
const bookshelfItems = generateBookshelfItems(libraryBooks);
const handleBookClick = async (book: Book) => {
if (book.uploadedAt && !book.downloadedAt) {
setLoading(true);
try {
await appService?.downloadBook(book);
updateBook(envConfig, book);
} finally {
setLoading(false);
}
}
if (!(await makeBookAvailable(book))) return;
if (isSelectMode) {
toggleSelection(book.hash);
} else {
@@ -1,9 +1,10 @@
import { 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 { useEnv } from '@/context/EnvContext';
import { Book } from '@/types/book';
export const useBooksSync = () => {
const { user } = useAuth();
@@ -51,41 +52,45 @@ export const useBooksSync = () => {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [library]);
useEffect(() => {
const updateLibrary = async () => {
if (syncedBooks?.length) {
const updatedLibrary = library.map((oldBook) => {
const matchingBook = syncedBooks.find((newBook) => newBook.hash === oldBook.hash);
if (matchingBook) {
return {
...oldBook,
...matchingBook,
updatedAt: oldBook.updatedAt,
deletedAt: oldBook.deletedAt,
progress: oldBook.progress,
};
const updateLibrary = async () => {
if (!syncedBooks?.length) return;
const processOldBook = async (oldBook: Book) => {
const matchingBook = syncedBooks.find((newBook) => newBook.hash === oldBook.hash);
if (matchingBook) {
if (!matchingBook.deletedAt && matchingBook.uploadedAt && !oldBook.downloadedAt) {
await appService?.downloadBook(oldBook, true);
}
return {
...oldBook,
...matchingBook,
updatedAt: oldBook.updatedAt,
progress: matchingBook.progress ?? oldBook.progress,
};
}
return oldBook;
};
const updatedLibrary = await Promise.all(library.map(processOldBook));
const processNewBook = async (newBook: Book) => {
if (!updatedLibrary.some((oldBook) => oldBook.hash === newBook.hash)) {
if (newBook.uploadedAt && !newBook.deletedAt) {
try {
updatedLibrary.push(newBook);
await appService?.downloadBook(newBook, true);
newBook.coverImageUrl = await appService?.generateCoverImageUrl(newBook);
} catch {
console.error('Failed to download book:', newBook);
}
return oldBook;
});
await Promise.all(
syncedBooks.map(async (newBook) => {
if (!updatedLibrary.some((oldBook) => oldBook.hash === newBook.hash)) {
if (newBook.uploadedAt) {
try {
await appService?.downloadBook(newBook, true);
newBook.coverImageUrl = await appService?.generateCoverImageUrl(newBook);
updatedLibrary.push(newBook);
} catch {
console.error('Failed to download book:', newBook);
}
}
}
}),
);
setLibrary(updatedLibrary);
appService?.saveLibraryBooks(updatedLibrary);
}
}
};
await Promise.all(syncedBooks.map(processNewBook));
setLibrary(updatedLibrary);
appService?.saveLibraryBooks(updatedLibrary);
};
useEffect(() => {
updateLibrary();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [syncedBooks]);
@@ -59,7 +59,9 @@ const ReaderContent: React.FC<{ ids?: string; settings: SystemSettings }> = ({ i
const isPrimary = !uniqueIds.has(id);
uniqueIds.add(id);
if (!getViewState(key)) {
initViewState(envConfig, id, key, isPrimary);
initViewState(envConfig, id, key, isPrimary).catch((error) => {
console.log('Error initializing book', key, error);
});
if (index === 0) setSideBarBookKey(key);
}
});