diff --git a/backend/src/chitai/services/book.py b/backend/src/chitai/services/book.py index 2bacd80..9fe0f52 100644 --- a/backend/src/chitai/services/book.py +++ b/backend/src/chitai/services/book.py @@ -38,18 +38,14 @@ from chitai.database.models import ( BookSeries, FileMetadata, Identifier, - BookList, Library, ) -from chitai.database.models.book_progress import BookProgress from chitai.schemas.book import BooksCreateFromFiles from chitai.services.filesystem_library import BookPathGenerator from chitai.services.metadata_extractor import Extractor as MetadataExtractor from chitai.services.utils import ( cleanup_empty_parent_directories, - delete_directory, delete_file, - is_empty, move_dir_contents, move_file, save_image, @@ -262,6 +258,9 @@ class BookService(SQLAlchemyAsyncRepositoryService[Book]): ValueError: If the file is missing or not found for the given book. """ book = await self.get(book_id) + if book.path is None: + raise ValueError("Cannot download file: book has no path") + for file in book.files: if file.id != file_id: continue @@ -342,14 +341,15 @@ class BookService(SQLAlchemyAsyncRepositoryService[Book]): await self._save_cover_image(data) # TODO: extract out into its own function _update_book_path - # Check if file path must be updated - path_gen = BookPathGenerator(library.root_path) - updated_path = path_gen.generate_path(book.to_dict() | data) - if str(updated_path) != book.path: - # TODO: Move only the files associated with the book instead of the whole directory - await move_dir_contents(book.path, updated_path) - data["path"] = str(updated_path) - cleanup_empty_parent_directories(Path(book.path), Path(library.root_path)) + # Check if file path must be updated (only for books with files) + if book.path is not None: + path_gen = BookPathGenerator(library.root_path) + updated_path = path_gen.generate_path(book.to_dict() | data) + if str(updated_path) != book.path: + # TODO: Move only the files associated with the book instead of the whole directory + await move_dir_contents(book.path, updated_path) + data["path"] = str(updated_path) + cleanup_empty_parent_directories(Path(book.path), Path(library.root_path)) return await super().update(data, item_id=book_id, execution_options={"populate_existing": True}) @@ -367,8 +367,8 @@ class BookService(SQLAlchemyAsyncRepositoryService[Book]): book = await self.get(book_id) data = book.to_dict() data["files"] = files - await self._save_book_files(library, data) - book.files.extend(data["files"]) + new_files = await self._save_book_files(library, data) + book.files.extend(new_files) await self.update_book(book.id, {"files": [file for file in book.files]}, library) async def remove_files( @@ -387,7 +387,7 @@ class BookService(SQLAlchemyAsyncRepositoryService[Book]): """ book = await self.get_one(Book.id == book_id, Book.library_id == library.id) - if delete_files: + if delete_files and book.path is not None: # TODO: Extract this out into its own function for file in (file for file in book.files if file.id in file_ids): full_path = Path(book.path) / Path(file.path) @@ -446,7 +446,7 @@ class BookService(SQLAlchemyAsyncRepositoryService[Book]): return data - async def _populate_with_unique_relationships(self, data: ModelDictT[Book]): + async def _populate_with_unique_relationships(self, data: ModelDictT[Book]) -> ModelDictT[Book]: """ Ensure relationship entities (authors, series, tags, etc.) are unique in the database. @@ -508,7 +508,7 @@ class BookService(SQLAlchemyAsyncRepositoryService[Book]): return model_data - async def _save_book_files(self, library: Library, data: dict) -> dict: + async def _save_book_files(self, library: Library, data: dict) -> list[FileMetadata]: """ Save uploaded book files to the filesystem. @@ -558,7 +558,7 @@ class BookService(SQLAlchemyAsyncRepositoryService[Book]): ) data["files"] = file_metadata - return data + return data["files"] async def _parse_metadata_from_files(self, data: dict, root_path: Path | None = None) -> dict: """