* feat: Add comprehensive Calibre metadata extraction system - Implemented configurable field mapping system for Calibre user_metadata - Added support for series_total custom column extraction - Pre-built mappings for ALL BookMetadata fields (20+ fields) - Added support for Set fields (tags, moods, categories, authors) - Lowercase field names with underscores (Calibre requirement) - Multiple ISBN support (ISBN-10 and ISBN-13 simultaneously) - ISBN hyphen handling (strips hyphens before validation) - Type-safe parsing (String, Integer, Float, Double, Set) - Professional logging with IDENTIFIER prefix - Added CALIBRE_FIELD_MAPPING_REFERENCE.txt documentation - Updated .gitignore and created .dockerignore for test files
* Updated gitignore
* Delete CALIBRE_FIELD_MAPPING_REFERENCE.txt
* Remove unnecessary files: example.epub and og_metadata.java
* Refactor EpubMetadataExtractor to address PR review feedback
- Eliminate DRY violations in identifier extraction with helper methods
- Fix Build-to-Check anti-pattern using processedFields tracking
- Move regex patterns to static constants to avoid recompilation
- Replace magic numbers with calculated prefix lengths
- Consolidate repetitive Set field and pagecount parsing patterns
- Remove excessive documentation and comments
- Remove unrelated .dockerignore and .gitignore entries
* chore: trigger CI/CD pipeline
* Add @Singular annotation to collection fields to support builder accumulation
* Update identifiers to URN format for Calibre compatibility
* fix: resolve MetadataChangeDetectorTest failures and enhance Calibre EPUB integration
- Fixed NullPointerException in testEdgeCase_emptyCollectionToNull_returnsTrue()
- Fixed NullPointerException in testHasValueChanges_whenEmptySetToNull_returnsTrue()
Implementing @Singular for moods and tags prevents metadata fields from being null,
which then fails edge test cases. Since we are no longer double looping during
metadata extraction, @Singular is not needed. Removing it allows the edge case
tests (by Balázs Szücs) to pass.
- Removed douban fields from persistence layer (kept in DTO for DoubanBookParser)
I was under the impression we were saving this value to the DB, but as far as I
can find, we only use Douban data for searching. Adding to the identifiers section
would raise issues with the database not having where to store that value.
Database modifications are left to the professionals.
- Added support for all identifier formats (URN and simple prefix)
Calibre only detects identifiers during IMPORT if they are in URN format.
However, it saves them back as simple prefix. Booklore now handles both.
- Added removeAllCalibreMetadata() to strip all Calibre traces
Cleans up saved EPUBs in Booklore's library, removing all Calibre metadata traces.
- Ensures clean EPUB 3 compliant output with only booklore:* tags
ALL metadata is now saved by Booklore into EPUBs using booklore:* tags.
This preserves Booklore's metadata and we can read it back during import.
Calibre support is ONLY during IMPORT, as it should be since this is the
Booklore project.
(If Calibre users want to extract Booklore metadata, they can build a Calibre
plugin to extract booklore:* tags.)
No longer use #genres or #categories. We stick to dc:subject as suggested,
and Booklore tags can be read from Calibre custom column #extra_tags.
We store tags as booklore:tags.
Removed all tests that used #genres/#categories.
Added tests to check booklore:* tags extraction.
* fix: Remove DoubanId copy helper call - upstream MetadataClearFlags missing isDoubanId()
* Fix Calibre moods and tags extraction from EPUB metadata
- Add fallback logic to check alternative key names (value, #val#) if #value# is missing
- Maintain compatibility with upstream metadata structure changes
* fix: resolve rebase conflicts and compilation errors - Fixed missing closing brace in MetadataRefreshService.java - Added MoodRepository and TagRepository to BookCreatorService - Added addMoodsToBook() and addTagsToBook() methods - Fixed EpubProcessor to use new methods
* Restore Booklore's metadata persistance, Logic Lost during Rebase + Added support for Lubimyczytac and ranobedb
Fixed lubimyczytac metadata not saving during EPUB bookdrop imports.
Root cause: The Angular bookdrop form was missing lubimyczytacId and lubimyczytacRating fields, preventing these values from being sent to the backend during finalization.
Backend fixes:
- EpubMetadataExtractor: Fixed method references with explicit lambdas for lubimyczytac field setters (ranobedb also updated preventively)
- BookMetadataUpdater: Fixed method references with explicit lambdas for lubimyczytac field updates (ranobedb also updated preventively)
Frontend fix:
- bookdrop-file-review.component.ts: Added lubimyczytacId and lubimyczytacRating form fields to createMetadataForm() and resetMetadata() methods
This ensures lubimyczytac metadata extracted from EPUB booklore:tags flows correctly through: extraction → database → UI form → backend → final book record.
* Restore Original ONLY Calibre custom column name to #pagecount So as not to break other users flow.
* fix: resolve compilation error in EpubProcessor.java - Changed bookEntity.getFileName() to bookEntity.getPrimaryBookFile().getFileName() to fix gradlew build check
* Add EPUB 3 compliant prefix declaration for custom booklore metadata
Declares the booklore: prefix in the package element's prefix attribute according to EPUB 3 specification for custom vocabularies.
* Move hardcoverBookId to standard URN identifier format
Changed hardcoverBookId from custom booklore metadata to standard dc:identifier with urn:hardcoverbook: prefix for consistency with other identifiers.
* UPDATE: migrate hardcover_book_id to VARCHAR and fix related issues
## Changes
### 1. Database Migration
- Changed hardcover_book_id column from INTEGER to VARCHAR(255)
- Supports alphanumeric book IDs from Hardcover API
- Updated HardcoverSyncService to handle String ↔ Integer conversion
### 2. Metadata Editor Fixes
- Fixed metadata change detection for provider-specific fields
- Added missing clearFlags entries: hardcoverBookId, lubimyczytacId, lubimyczytacRating
- Resolves issue where rating/review count fields wouldn't save independently
Affected fields now save properly independently:
- Amazon rating & review count
- Goodreads rating & review count
- Hardcover rating & review count
- Lubimyczytac rating
- Ranobedb rating
### 3. Web Reader Hardcover Sync (Major Fix)
Since I changed the data type for hardcover_book_id I had to update references in the HardCoverSyncService.java This turned out to reveal
the Sync Service was not fully implemented:
- Added Hardcover progress sync to ReadingProgressService
- Previously, HARDCOVER sync only worked for Kobo and KOReader devices
- Web browser reading progress now syncs to Hardcover.app
## Files Modified
- booklore-api/src/main/resources/db/migration/V107__Change_hardcover_book_id_to_varchar.sql
- booklore-api/src/main/java/.../service/hardcover/HardcoverSyncService.java
- booklore-api/src/main/java/.../service/progress/ReadingProgressService.java
- booklore-ui/src/app/features/metadata/.../metadata-editor.component.ts
## Breaking Changes
None - migration handles existing integer IDs gracefully
## Testing
- Hardcover sync tested with web reader
- Metadata editor field updates verified
- Database migration confirmed successful
---------
Co-authored-by: ACX <8075870+acx10@users.noreply.github.com>
* fix(API): add missing fields to BookMapperV2
This fixes a regression introduced in the data model refactoring work
for multi-format support.
BookMapperV2 was missing mapping for file-related fields.
* Added missing mappings for BookMapperV2
* Added a test for BookMapperV2 to prevent future regressions
* fix(api): fix the code after rebase
* fix(audiobook-reader): use preload=none with API duration for instant load
* fix(audiobook-reader): debounce seek and limit streaming chunk size to 2MB
* no message
---------
Co-authored-by: acx10 <acx10@users.noreply.github.com>
Add updatedAt timestamp field to EpubProgress, PdfProgress, and CbxProgress
DTOs to support progress conflict detection in the mobile app.
The mobile app uses this timestamp to detect when progress has changed on the
server (e.g., from reading in the web UI) while the app was offline with
local progress, enabling automatic conflict resolution.
- Add GET /api/v1/user-stats/heatmap/monthly endpoint for month-based data
- Keep original /heatmap endpoint unchanged for backward compatibility
- Add findSessionCountsByUserAndYearAndMonth repository method
- Add getSessionHeatmapForMonth service method
* fix(library-processing): re-fetch library entity after clearing entity manager during rescan
Ensure the latest library entity state is retrieved after clearing the entity manager in rescanLibrary. Add test to verify fresh entity is used for subsequent processing.
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* test(library-processing): update rescan test to verify grouping service usage and remove obsolete assertions
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
---------
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* fix(metadata-parsers): improve ISBN search logic and fallback strategies for metadata fetching
- Update GoogleParser, HardcoverParser, and ComicvineBookParser to prioritize ISBN search and implement robust fallbacks to title+author and title-only queries
- Refactor GoogleParser to allow dependency injection for HttpClient and Jsoup connections, improving testability
- Enhance HardcoverParser to retry with title-only search if combined title+author results are filtered out
- Adjust MetadataRefreshService to prefer ISBN-13 over ISBN-10 when building fetch requests
- Add JsoupConnectionFactory and DefaultJsoupConnectionFactory for injectable Jsoup connections
- Expand and improve unit tests for GoogleParser and HardcoverParser to cover new fallback behaviors
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* fix(google-parser): handle null primary file and correct search term return
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
---------
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
- Update provider priority logic to ensure P1 > P2 > P3 > P4 for all metadata fields
- Refactor buildFetchMetadata to accept existing metadata and preserve fields when using REPLACE_ALL mode
- Adjust service and test method signatures for new parameter
- Add unit test to verify provider priority order
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* fix(book-rule-evaluator): fix file type handling and add mapping for specific formats to fix magic shelve based on filetype
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* fix(book-rule-evaluator): update test to simplify book creation for group rule evaluation
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
---------
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* fix: support reading alternative book formats using bookType query param
* feat: add streaming reader support for alternative EPUB formats
* refactor: extract tabs section into MetadataTabsComponent
* feat: implement per-file reading progress tracking
* feat: add configurable format priority with cascading fallback
* refactor: redesign library creator with single-page layout
* refactor: unify reading progress into ReadingProgressService
* refactor: improve delete options with clearer file format and book deletion
* refactor: improve book format matching with normalization and fuzzy fallback
* feat: add folder-based audiobook support with ZIP downloads and preparing state
* fix: display unique format types in metadata viewer
* refactor: auto-attach files to single book in folder during rescan
* feat: implement folder-centric book file grouping with fuzzy matching
* refactor: consolidate book grouping with organization mode support
* fix: use folder hash for folder-based audiobooks in auto-attach
* fix: delete only BookFileEntity on file removal, not entire book
* fix: set folderBased flag and correct file size for auto-attached audiobook folders
* fix: use count query to avoid lazy initialization in file delete handler
* fix: preserve book metadata when file is moved by detecting hash match
* fix: skip books with no files in restoration to avoid NPE
* fix: round all progress percentages to one decimal place before sending to UI
* style: improve library creator dialog spacing and layout
* fix: migrate FOLDER_AS_BOOK to BOOK_PER_FOLDER for backwards compatibility
* fix: FileMoveService now handles multi-file BookEntity properly
* style: redesign metadata-picker and file-mover UI components
* style: redesign file-naming-pattern UI and improve theme contrast
* style: relax spacing in library-creator component
* style: tighten directory-picker layout for consistency
* fix: PathPatternResolver now respects folderBased flag for audiobooks
* style: move checkmark column to left side and add pending status in file-mover
* refactor: consolidate BookFileType into BookType and add audiobook styling
* feat: show 'Continue Reading' button for in-progress books
* fix: preserve dots in folder names during grouping and prevent duplicate attachments
* style: reduce gap between download-all button and primary file section
* style: shorten 'Continue Reading' button to 'Read' on mobile
* feat: add DISK_TYPE config to disable file moves on network storage
* style: standardize settings pages with shared styles and consistent spacing
* style: revamp settings pages with modern card-based layouts
* style: revamp OPDS, auth, and task management settings layouts
* fix: update FileMoveService tests to include AppProperties parameter
* fix: derive BookFileType from extension when uploading additional book files
* feat: show format type and size in download button with dropdown for alternatives
* feat: add audiobook streaming player with HTTP Range support
* feat: add M4B chapter extraction and chapter navigation
* feat: add audiobook bookmarks and sleep timer
* refactor: split AudiobookReaderService into focused services
* feat: add Media Session API for background audio playback
* feat: display file extensions in format tags with distinct colors and add audiobook upload support
* feat: require bookFileId for viewer settings API
* fix: show split button for audiobooks with readable alternatives
* feat: improve reading sessions table with book type badges and better formatting
* feat: add audiobook play button in files tab
* feat: use file extension for format display and meaningful tab values
* feat: add extension field to BookFile DTO
* feat: use extension field for book card format pill
* fix: use mixed orientation for format priority drag-drop to support multi-line layout
* feat: add attach book files feature to consolidate single-file books
* fix: increase drag handle size for format priority chips
* fix: add missing BookFileRepository mock to BookServiceDeleteTests
* feat: add delete buttons to files tab and move shelf to other items menu
* feat: add physical books support for cataloging books without digital files
* refactor: redesign icon-picker component with improved styling
* refactor: redesign metadata-picker component with improved layout and alignment
* refactor: move Add Physical Book to top of library menu
* refactor: use p-autoComplete for authors/categories in add-physical-book dialog
* feat: add square cover search and display support for audiobooks
* fix: navigate to first page when opening unread ebooks
* fix: exclude API requests from service worker interception
* feat: support fileless books with automatic file attachment
* fix: bypass service worker for audiobook streaming requests
* refactor: remove alphabetical filter sorting, default to count, limit filters to 100
---------
Co-authored-by: acx10 <acx10@users.noreply.github.com>
this avoids a remote call to github's raw download
so the application is less reliant on public internet
access. further this prevents unknown failures
when the bg.png is removed or changed in the external repo
The current experience was not great when you have several libraries, instead of swallowing the drop it was disabling the drag/drop zone leading to the browser taking over and opening the file.
This changes keeps the drag & drop enabled but just swallows the files and displays an error if no library is selected.
It also improves the UI by making it more clear when a drag event is happening.
- Fix issue with hardcover toggle not being selectable
- Resolve syncing problem with Booklore toggle
- Address CSS warnings for cleaner styling
Co-authored-by: acx10 <acx10@users.noreply.github.com>
* do not group reading sessions on a per-day basis
* calculate actual duration for reading sessions
---------
Co-authored-by: WorldTeacher <coding_contact@pm.me>