* Cleanup subpath handling
* Move webUI serve setup logic to WebInterfaceManager
* Fix webUI subpath injection
Dynamic subpath support on the client requires using relative paths for everything.
Without a <base> tag this only works when opening the client on the root path.
Any subpath will result in a blank page because the used url to request e.g., an asset will be invalid and cause an error (type mismatch, since the index.html will be returned for any unmatch route).
* Catch config value migration exception
In case the value did not exist in the config a "ConfigException.Missing" exception was thrown which caused the whole migration to fail.
Fixes#1645
* Improve config migration logging
* Update user config file after config update
The user config file gets reset before the update.
This could cause the user settings to get lost on the next server start in case something went wrong during the update and the updated config never got saved to the actual file.
* Redact username and passwords from config log
* Redact empty username and password
* Make regex Username/Password case-insensitive in config redaction
* Skip thumbnail download for local manga sources
Local manga sources do not require downloading thumbnails as they are stored locally.
* Always update local source manga info when browsing
When making changes to an in library local source manga, a refresh from the source was required to get the latest data.
From a user perspective, this is unexpected behavior that looks like a bug.
If, for example, the thumbnail file extension got changed, the file could not be found anymore and an error was shown in the client. To fix this, a manga refresh was required.
Exposes the existing push and pull functionality from the KoreaderSyncService via the GraphQL API.
This change introduces two new mutations:
- `pushKoSyncProgress`: Manually sends the current chapter's reading progress to the KOReader sync server.
- `pullKoSyncProgress`: Manually fetches and applies the latest reading progress from the KOReader sync server.
These mutations enable clients and WebUIs to implement manual sync triggers, providing users with more direct control over their reading progress synchronization, similar to the functionality offered by the official KOReader plugin and other clients like Readest.
* refactor(kosync): introduce differentiated sync strategies
Replaces the single `koreaderSyncStrategy` setting with `koreaderSyncStrategyForward` and `koreaderSyncStrategyBackward`. This allows users to define distinct conflict resolution behaviors based on whether the remote progress is newer or older than the local progress.
The `KoreaderSyncStrategy` enum has been simplified to `KoreaderSyncConflictStrategy` with four clear options: `PROMPT`, `KEEP_LOCAL`, `KEEP_REMOTE`, and `DISABLED`. The ambiguous `SILENT` option is removed, as its behavior is now implicitly covered by selecting `KEEP_REMOTE` for forward syncs and `KEEP_LOCAL` for backward syncs.
The legacy `koreaderSyncStrategy` setting is now deprecated and is seamlessly migrated to the new dual-strategy system using `MigratedConfigValue`, ensuring backward compatibility for existing user configurations.
* fix(kosync): correct proto numbers and setting order for sync strategies
* fix(kosync): proto number 78 to 68
* fix(server): migrate KOReader sync strategy during settings cleanup
Add migration logic to convert the old `server.koreaderSyncStrategy` key
into the new `server.koreaderSyncStrategyForward` and
`server.koreaderSyncStrategyBackward` keys during server setup.
* Support PostgreSQL Databases
* Set the database Schema
* See if we can test postgres
* Another test
* Disable node container
* Update database when changed
* Simplify test workflow
* Only exit on failed migrations
* Run the first databaseUp sync
* Map the port
* Use absolute path for LD_PRELOAD
* Timeout after 1m
* Open the server in both database configurations
* Only exit on migration failed in ci
* Lint
* Use new ServerConfig configuration
* Cleanup graphql setting mutation
* Validate values read from config
* Generate server-reference.conf files from ServerConfig
* Remove unnecessary enum value handling in config value update
Commit df0078b725 introduced the usage of config4k, which handles enums automatically. Thus, this handling is outdated and not needed anymore
* Generate gql SettingsType from ServerConfig
* Extract settings backup logic
* Generate settings backup files
* Move "group" arg to second position
To make it easier to detect and have it at the same position consistently for all settings.
* Remove setting generation from compilation
* Extract setting generation code into new module
* Extract pure setting generation code into new module
* Remove generated settings files from src tree
* Force each setting to set a default value
* Move API authorization to UserType
We already verify the JWT there, so do the same with cookies. This makes
the next steps easier
* OPDS: Allow basic auth as fallback
* Send 404 for any unmatched API request
Redirecting to the UI is weird and can cause problems with the
SIMPLE_LOGIN check (which ignores API requests)
* Webview: Present Login page in SIMPLE_LOGIN mode
For BASIC_AUTH, the dialog is always presented. With UI_LOGIN, we have a
custom login dialog.
Before, SIMPLE_LOGIN would just say "Unauthorized", as with all API
endpoints. With the last commits, SIMPLE_LOGIN is checked by the
endpoints, which Webview did not, so the page would load, but then the
Websocket would error out, despite showing the login dialog.
* Lint
* refactor(opds): align feed generation with RFC5005 and OpenSearch specs
This commit refactors the OPDS feed generation to strictly adhere to official specifications for search and pagination.
Previously, OpenSearch response elements (totalResults, itemsPerPage, startIndex) were incorrectly included in all acquisition feeds. According to the OPDS 1.2 and OpenSearch 1.1 specifications, these elements should only be present in feeds that are a direct response to a search query. This change restricts their inclusion to search result feeds only, ensuring spec compliance.
Additionally, pagination link relations were not fully implemented as per RFC 5005. This commit enhances all paginated feeds to include `first` and `last` links, in addition to the existing `prev` and `next` links. This provides a complete and standard-compliant navigation experience for OPDS clients.
- `FeedBuilderInternal` now accepts an `isSearchFeed` flag to conditionally add OpenSearch elements.
- All feed generation methods in `OpdsFeedBuilder` and `OpdsV1Controller` now correctly identify search contexts.
- RFC 5005 pagination links (`first`, `last`, `prev`, `next`) are now generated for all paginated feeds.
- Added necessary link relation constants to `OpdsConstants`.
* feat(opds): improve pagination navigation and code organization
When generating a hash on-the-fly for the binary checksum method, the code was performing a full MD5 hash of the entire file stream. This was incorrect as the KOReader binary method expects a specific partial hash (reading small chunks at different offsets).
This change ensures that when an in-memory CBZ is created, it is first written to a temporary file. Then, the correct `KoreaderHelper.hashContents()` function is used on that file to generate the partial hash, matching KOReader's logic. The temporary file is deleted immediately after.
* fix(archive): unify CBZ generation to produce deterministic archives
Previously, CBZ files generated on-the-fly (`FolderProvider`) had a different hash than those created directly (`ArchiveProvider`), even with identical content. This inconsistency was caused by using two different ZIP libraries (`java.util.zip` vs. `org.apache.commons.compress`) and not normalizing file metadata.
This inconsistent hashing breaks binary-based synchronization with external services like KOReader Sync Server, as the same chapter could be identified as a different file on each generation.
This change ensures CBZ generation is fully deterministic by:
- Unifying both providers to use `org.apache.commons.compress`.
- Setting a fixed epoch timestamp (`time = 0L`) for all ZIP entries.
- Explicitly setting the compression method and level to `DEFLATED` with default compression.
This guarantees that a CBZ file for a given chapter will always have the same hash, regardless of how it's generated, resolving synchronization issues.
* feat(kosync): lazily generate and cache CBZ hashes for sync
Previously, KOReader progress sync in binary mode was limited to chapters explicitly downloaded as CBZ files. Chapters stored as folders lacked a hash, preventing them from being synced.
With the recent move to deterministic CBZ generation, it's now possible to create a consistent hash for any downloaded chapter on-the-fly.
This commit enhances the `getOrGenerateChapterHash` function to act as a central point for hash management. If a hash is requested for a downloaded chapter that doesn't have one cached in the database:
1. It generates the CBZ archive in-memory from the downloaded folder or existing CBZ using `ChapterDownloadHelper.getAsArchiveStream()`.
2. It calculates the deterministic hash of the generated archive content.
3. It saves this hash to the `koreader_hash` column in the `Chapter` table for future use.
The cached hash is cleared when the chapter download is deleted, ensuring hashes are only tracked for available content.
This change transparently extends Koreader Sync compatibility to all downloaded chapters, regardless of their storage format, without requiring users to pre-convert their library to CBZ.
* fix: rename getAsArchiveStream to getArchiveStreamWithSize