* feat(stats): add 5 new user statistics charts
* fix(stats): use COALESCE for dateFinished in heartbeat and page turner queries
* refactor(stats): remove heartbeat, genre flow, reading seasons, and abandonment autopsy charts
* feat(stats): add 5 new user statistics charts
* feat(stats): add info tooltips to all 5 new charts
* perf(stats): limit completion race chart to 15 most recent books server-side
* fix(stats): limit completion race to 10 books and cap progress at 100%
* refactor(stats): replace streak bars with GitHub-style activity heatmap calendar
* fix(stats): widen chart info tooltips to prevent tall narrow box
* feat(stats): add info tooltip to Page Turner Score chart
* feat(stats): add info tooltips to 7 existing charts
* refactor(stats): deduplicate chart-info-icon style into global styles.scss
* refactor(stats): fix scoring bugs and improve Reading DNA and Reading Habits charts
* refactor(stats): rebalance Series Progress Tracker layout and unify heatmap footer pills
* feat(stats): add info tooltips to 4 remaining charts
* fix(stats): fix session duration and overlap bugs in Reading Session Timeline
Amazon, Audible, and GoodReads parsers now fetch full detailed metadata
(4 results each) instead of returning lightweight previews. Adds randomized
500-1500ms delays between requests. GoodReads retries with title-only search
(2 results) when title+author yields no matches.
Co-authored-by: acx10 <acx10@users.noreply.github.com>
* fix(sidebar): replace routerLinkActive with getter-based route matching to prevent stale highlights
* feat(sort): replace compound sort options with atomic fields and add 6 new sort criteria
* feat(metadata): add BookLore custom metadata support for moods, tags, ratings, and external IDs in EPUB, PDF, and CBZ
- Introduce BookLoreSchema for XMP custom fields and BookLoreMetadata for namespace constants
- Write and extract moods, tags, ratings, and external IDs (Goodreads, Amazon, Hardcover, Lubimyczytac, RanobeDB, Google) in EPUB, PDF, and CBZ metadata
- Store BookLore custom fields in ComicInfo.xml notes and Web fields for CBZ
- Add BookLore fields to XMP metadata in PDF, including moods and tags as separate fields
- Update extractors and writers to handle BookLore fields and ensure separation of categories, moods, and tags
- Add comprehensive tests for BookLore metadata extraction and writing
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* refactor(metadata): standardize hardcoverBookId as String and improve identifier handling
- Change hardcoverBookId field and related methods to use String instead of Integer for consistency across extractors and writers
- Update metadata copy helpers and tests to reflect new hardcoverBookId type
- Improve identifier prefix handling in EPUB and PDF extractors to be case-insensitive and trim whitespace
- Allow PDF keywords to be split by comma or semicolon
- Rename TaskCreateRequest#getOptions to getOptionsAs for clarity and update usages
- Adjust series number writing in EPUB metadata to preserve decimals when needed
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* refactor(metadata): standardize usage of tags over categories and improve BookLore field extraction
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* feat(metadata): add rating and ratingLocked fields to BookMetadata and improve PDF metadata extraction
- Add rating and ratingLocked fields to BookMetadata for enhanced rating support
- Refine PDF keyword extraction to handle both comma and semicolon delimiters
- Ensure ISBN fields are only set if cleaned values are non-blank
- Use temp file only stream cache when loading PDFs for metadata writing
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* feat(metadata): implement ComicInfo.xml writing via JAXB, ensure XSD compliance and add tests for CBX metadata persistence
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* feat(metadata): enhance metadata extraction with additional identifiers and improve parsing logic
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* feat(metadata): improve metadata handling by ensuring descriptions are prioritized and enhancing keyword management for PDF compatibility
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* refactor(metadata): simplify Pages class structure in ComicInfo.java
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* feat(metadata): refine PDF metadata writing by isolating categories for legacy compatibility and removing moods and tags from keywords
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* feat(metadata): enhance PDF metadata extraction and writing with support for additional fields and improved handling of series information
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* feat(metadata): enhance PDF metadata extraction and writing with support for additional fields and improved handling of series information
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* feat(metadata): implement secure XML parsing utility and enhance metadata extraction with improved GTIN validation and debug logging
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* refactor(metadata): update package structure to align with new organization naming conventions
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* fix(epub-metadata): streamline cover image extraction logic and improve error handling
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* feat(metadata): enhance PDF and comic metadata extraction with additional fields
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* feat(metadata): migrate to tools.jackson for JSON processing in sidecar metadata handling
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* fix(epub-metadata): streamline cover image extraction and enhance XML parsing security
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
---------
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* fix(epub-metadata): enhance cover extraction with heuristic fallbacks for manifest and ZIP entries
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* test(epub-metadata-extractor): add heuristic cover creation methods for EPUB files
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
---------
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* feat: add comic metadata support to metadata picker and fix Comicvine parser
* feat: lazy-load Comicvine issue details on selection
* feat: lazy-load detail metadata for Amazon, GoodReads, and Audible parsers
* fix: prevent spurious comic_metadata row creation for non-comic books
* fix: extract rich previews from Audible search and reorder picker sections
* feat: redesign metadata editor layout with collapsible sections and boolean selects
* fix: implement per-field comic metadata locks replacing grouped locks
* feat: add comic metadata filters and fix visibleFilters backend support
* fix: use human-readable role labels in comic creator filter
* fix: auto-populate comic metadata from ComicVine during metadata fetch
* refactor: clean up ComicvineBookParser remove duplication and comments
* fix: use ComicMetadata webLink for ComicVine favicon URL
* fix: cache library options to prevent Set All dropdowns from resetting
* fix: stream book content from disk instead of loading entire file into memory
* fix: increase max visible filters from 15 to 20
* feat: replace filter multiselect with drag-and-drop reorderable list
* fix: use audiobook-specific cover paths and cache busting for audiobook thumbnail updates
* chore: enforce mandatory screenshots and stricter testing requirements in PR template
* fix: update BookServiceTest to match Resource return type after streaming change
---------
Co-authored-by: acx10 <acx10@users.noreply.github.com>
* feat: remove nginx and serve Angular directly from Spring Boot
* fix: handle null values in EnabledFields deserialization from persisted JSON
* fix(migration): auto-repair failed Flyway migrations on startup
* fix(migration): replace DB triggers with app-level orphan cleanup
* fix: restore default port to 6060 for backwards compatibility
* fix: align all port references to 6060 and add OPDS compression MIME types
* fix: resolve NG0101 recursive tick error in book browser selection
---------
Co-authored-by: acx10 <acx10@users.noreply.github.com>
Add IF NOT EXISTS / IF EXISTS / DROP IF EXISTS guards to prevent
failures when migrations are re-run after partial application on
MariaDB which lacks transactional DDL support.
Reverts V114 to its original content to preserve Flyway checksum
for existing installations. Moves orphan-cleanup triggers to new
V117 migration to avoid checksum mismatch failures on MariaDB.
* refactor: simplify RestTemplate and ObjectMapper configurations, add no-args constructors to progress classes
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* chore: update Gradle and Java versions in Docker configuration and build files
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* test: enhance header assertions in tests and add spring-boot-test-autoconfigure dependency
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* refactor(tests): migrate to SpringBootTest and update entity management in test cases
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* test: update test property configurations for H2 database in Healthcheck and BookOpds repository tests
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* test: clean up HealthcheckControllerTest by removing unnecessary whitespace and comments
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* test: remove unnecessary whitespace in HealthcheckControllerTest
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* chore: downgrade Flyway version from 12.0.0 to 11.14.1 in build.gradle
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* chore: downgrade Flyway version from 12.0.0 to 11.14.1 in build.gradle
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* feat: add @DependsOn annotation for Flyway in MultipartConfig
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* feat: add @DependsOn annotation for Flyway in LibraryService
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* feat: add test configuration for Flyway in HealthcheckControllerTest
chore: remove unused path variable in deleteLibrary method of LibraryService
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* feat: configure Flyway migration and update test configuration
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* feat: enable remote debugging in bootRun configuration
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* feat: update Flyway version and enhance ObjectMapper configuration
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* feat: remove @DependsOn annotation for Flyway in MultipartConfig and LibraryService
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* feat: add NoArgsConstructor and AllArgsConstructor annotations to DTO classes
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* feat: add NoArgsConstructor and AllArgsConstructor annotations to FileProcessResult, MetadataUpdateContext, and MetadataUpdateWrapper classes
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* feat: add DependsOnDatabaseInitialization annotation to MultipartConfig, AppSettingService, LibraryService, and JwtSecretService classes
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* feat: add DependsOnDatabaseInitialization annotation to MultipartConfig and CronService classes
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* feat: implement lazy initialization and thread safety for JWT secret retrieval
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* feat: add Flyway dependency and update LibraryService initialization to use ApplicationReadyEvent
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* refactor: remove outdated comments from JwtSecretService class
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* refactor: migrate from com.fasterxml.jackson to tools.jackson for JSON processing
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* refactor: remove unused ObjectMapper bean and related imports from JacksonConfig
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* feat: configure async support with VirtualThreadTaskExecutor in WebMvcConfig
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* feat: enhance application performance with virtual threads and HTTP/2 support
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* feat: add JsonSetter annotation to skip null values for triggeredByCron field
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* feat: add triggeredByCron field to TaskCreateRequest and initialize in task management
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* feat: enable Spring Data web support with DTO serialization in WebMvcConfig
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* refactor(UserDefaultsService): simplify class structure and remove unused methods
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* refactor(BookOpdsRepositoryDataJpaTest): simplify test setup and use TestEntityManager
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* refactor(BookOpdsRepositoryDataJpaTest): update test configuration and simplify entity persistence
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* refactor: update Jackson dependencies and migrate to Jackson 3
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* refactor(build.gradle): update jackson-annotations dependency to use Jackson 3 BOM
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* refactor(BookOpdsRepositoryDataJpaTest): remove unused ObjectMapper bean definition
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* refactor(LibraryService): simplify library deletion logic
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
---------
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
Allow users to choose which file format to send when emailing a book.
Includes file size display and large file warnings for files >25MB.
Backend:
- Add optional bookFileId to SendBookByEmailRequest
- Add resolveBookFile() to resolve specific file or fallback to primary
- Update SendEmailV2Service to use specified file path
Frontend:
- Change openCustomSendDialog to accept Book object
- Add format selection with radio buttons showing type/size
- Add "Primary" badge and large file warning banner
- Update book-card and metadata-viewer callers
Co-authored-by: acx10 <acx10@users.noreply.github.com>
* feat(icons): Made icons for libraries and shelves optional with no default icon displayed.
* Added tests for making sure the API handles nullable icons for Shelves and Libraries.
* Fixed some issues identified during PR review.
* Rebased on develop.
* fix(hardcover-sync): Don't send repeated read status to Hardcover.app
* fix(hardcover-sync): Use progress percentage instead of read status
* fix(hardcover-sync): Add test cases
* fix(hardcover-sync): Also check read status for changes
* feat(kobo-sync): sync shelves and magic shelves to kobo tags
* refactor(kobo-sync): replace `EntityNotFoundException` with `NoSuchElementException`, update timestamps handling, and add unit tests for `generateTags`
---------
Co-authored-by: ACX <8075870+acx10@users.noreply.github.com>
* Audiobook enhancement
* Fix choppy virtual scroller with mixed audiobook/ebook cards by using uniform heights
* Fix audiobook cover regeneration for combined books and improve error messages
* Fix cover extraction when attaching audiobook files during rescan
* Set audiobookCoverUpdatedOn for cache busting when generating cover
* Add support for regenerating covers from specific book files
* Fix Continue Reading/Listening scrollers to filter by actual progress instead of primary file type
* Show ebook cover and open ebook reader in Continue Reading scroller for combined books
* Prevent read status from being downgraded when saving audiobook progress
* Fix BookCoverServiceTest to match updated regenerateCover method signature
---------
Co-authored-by: acx10 <acx10@users.noreply.github.com>
* fix(kobo-sync): Kobo reading state sync by returning the device expected shape and improve management with new DTOs and timestamp normalization
- Introduced `KoboReadingStateList` and `KoboReadingStateRequest` DTOs for improved handling of reading states.
- Updated `KoboController` to utilize the new DTOs and log request bodies.
- Enhanced `KoboReadingStateService` to normalize timestamps during reading state updates and merges.
- Adjusted repository queries to include user ID for better data integrity.
- Updated tests to reflect changes in DTOs and repository interactions.
* feat(kobo-sync): Enhance Kobo reading state management with user ID integration
* feat(kobo-sync): Add JSON annotations to KoboReadingStateList for improved serialization
* refactor(kobo-sync): Update repository and service methods to enhance reading state retrieval logic
- Replaced the existing method for fetching reading states with a new query that orders results by priority and timestamps.
- Updated service classes to utilize the new repository method for improved data handling.
- Adjusted unit tests to reflect changes in repository interactions.
* Enhance KoboReadingStateService and add database migration for user_id
- Added a new column `user_id` to the `kobo_reading_state` table with a foreign key constraint referencing the `users` table.
- Updated the `KoboReadingStateService` class by adding a new method to check for blank values, improving code readability and maintainability.
Refactor bulkUpdateMetadata to process each book update in its own transaction using PROPAGATION_REQUIRES_NEW, improving concurrency safety. Add BookMetadataServiceConcurrencyTest to verify correct fetching strategy and transactional behavior.
Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
* 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>