Commit Graph

409 Commits

Author SHA1 Message Date
schroda
9a33e3808a Feature/graphql settings add jwt settings (#1612)
* Add jwt settings to grapqhl SettingsType

* Sort proto BackupServerSettings by ProtNumber
2025-08-24 12:35:59 -04:00
Zeedif
a5d64be197 fix(kosync): use correct partial hash for binary checksum (#1610)
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.
2025-08-24 12:35:38 -04:00
Zeedif
f46745d70c feat(kosync): Implement On-the-Fly Deterministic Hashing for KOReader Sync (#1606)
* 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
2025-08-21 19:18:27 -04:00
Constantin Piber
8547159eec Basic JWT implementation (#1524)
* Basic JWT implementation

* Move JWT to UI_LOGIN mode and bring back SIMPLE_LOGIN as before

* Update server/src/main/kotlin/suwayomi/tachidesk/global/impl/util/Jwt.kt

Co-authored-by: Mitchell Syer <Syer10@users.noreply.github.com>

* Refresh: Update only access token

Co-authored-by: Mitchell Syer <Syer10@users.noreply.github.com>

* Implement JWT Audience

* Store JWT key

Generates the key on startup if not set

* Handle invalid Base64

* Make JWT expiry configurable

* Missing value parse

* Update server/src/main/kotlin/suwayomi/tachidesk/global/impl/util/Jwt.kt

Co-authored-by: Mitchell Syer <Syer10@users.noreply.github.com>

* Simplify Duration parsing

* JWT Protect Mutations

* JWT Protect Queries and Subscriptions

* JWT Protect v1 WebSockets

* WebSockets allow sending token via protocol header

* Also respect the `suwayomi-server-token` cookie

* JWT reduce default token expiry

* JWT Support cookie on WebSocket as well

* Lint

* Authenticate graphql subscription via connection_init payload

* WebView: Prefer explicit token over cookie

This hack was implemented because WebView sent `"null"` if no token was
supplied, just don't send a bad token, then we can do this properly

* WebView: Implement basic login dialog if no token supplied

---------

Co-authored-by: Mitchell Syer <Syer10@users.noreply.github.com>
Co-authored-by: schroda <50052685+schroda@users.noreply.github.com>
2025-08-20 18:04:48 -04:00
Zeedif
82ad2fbe80 feat(opds): Enhance KOSync Conflict Handling and Reliability (#1602)
* feat(opds): Enhance KOSync conflict handling and reliability

This commit introduces several improvements to the KOSync integration within the OPDS feed, focusing on fixing bugs, improving network stability, and enhancing user feedback during synchronization conflicts.

- fix(sync): Corrects a KOSync JSON deserialization issue by mapping the `updated_at` field from the server response to the `timestamp` property in the client's data model. This resolves a critical bug where remote progress was being ignored.
- fix(sync): Adds a `Connection: close` header to all KOSync API requests. This prevents `unexpected end of stream` errors by ensuring a fresh connection is used, improving network reliability.
- feat(opds): Resolve sync conflicts by generating separate OPDS entries for local and remote progress. This aligns with the OPDS-PSE specification's implicit design of one stream link per entry. Instead of incorrectly adding multiple links to a single entry, the feed now presents two distinct, clearly labeled entries, allowing users to choose their desired reading position from compatible clients.
- chore(sync): Adds detailed debug logging for KOSync `GET` and `PUT` requests, including request URLs, sent data, and received responses. This improves traceability and makes debugging future issues significantly easier.

* change synced icon

* unnecessary comments removed
2025-08-20 18:03:33 -04:00
Zeedif
a414860626 fix(api): optimize HEAD requests for chapter downloads (#1601)
Previously, handling a HEAD request on the chapter download endpoint was inefficient as it triggered the full CBZ file generation process in-memory just to retrieve metadata like Content-Length and Content-Disposition. This caused unnecessary latency especially for OPDS clients.

This commit introduces a separate, lightweight path for HEAD requests.

- A new `getCbzMetadataForDownload` method is added to `ChapterDownloadHelper` to calculate the filename and file size without generating an archive stream.
- The `ChaptersFilesProvider` interface is updated with a `getArchiveSize()` method, implemented by both `ArchiveProvider` and `FolderProvider`, to retrieve the total size.
- The `MangaController` now differentiates between GET and HEAD methods, invoking the appropriate helper to ensure HEAD requests are served instantly with only the required metadata.
2025-08-20 18:03:26 -04:00
Mitchell Syer
7a0d3a1efe Expose the Source baseUrl (#1585)
* Expose the source baseUrl

* Lint
2025-08-19 15:01:14 -04:00
Zeedif
590e43c827 feat(sync/koreader): Add KOReader reading progress synchronization (#1560)
* feat(sync/koreader): implement reading progress synchronization

This commit introduces a comprehensive integration with KOReader Sync Server to enable two-way synchronization of reading progress.

The core logic is encapsulated in a new `KoreaderSyncService`, which handles authentication, registration, and progress pushing/pulling based on user-defined strategies (LATEST, KOSYNC, SUWAYOMI).

Key changes include:

- A new GraphQL API is added to manage the KOReader Sync connection:
  - `connectKoSyncAccount` mutation provides a simplified flow that attempts to log in and, if the user doesn't exist, automatically registers them.
  - `logoutKoSyncAccount` mutation to clear credentials.
  - `koSyncStatus` query to check the current connection status.

- Reading progress is now synchronized at key points:
  - The `fetchChapterPages` mutation pulls the latest progress from the sync server before loading the reader. It respects the configured sync strategy and updates the local database if necessary.
  - The `updateChapters` and other progress-updating methods now push changes to the sync server automatically.
- OPDS chapter entries also pull the latest progress, ensuring clients receive up-to-date reading status.

- Supporting backend changes have been made:
  - The `Chapter` table is extended with a `koreader_hash` column to uniquely identify documents. A database migration is included.
  - New configuration options are added to `server.conf` to manage the feature (enable, server URL, credentials, strategy, etc.).

* perf(opds): defer KOReader sync to improve chapter feed performance

Removes the KOReader Sync progress-pulling logic from the `createChapterListEntry` function.

The previous implementation triggered a network request to the sync server for every single chapter when generating a list, leading to severe performance issues and slow load times on feeds with many entries.

This change reverts to the more performant approach of always linking to the chapter's metadata feed. The expensive sync operation will be handled within the metadata entry generation instead, ensuring it's only triggered on-demand for a single chapter. This restores the responsiveness of browsing chapter feeds.

* refactor(koreader): Use enums for sync settings and correct OPDS logic

Refactor Koreader Sync settings to use enums instead of raw strings for `checksumMethod` and `strategy`. This improves type safety, prevents typos, and makes the configuration handling more robust.

The changes include:
- Introducing `KoreaderSyncChecksumMethod` and `KoreaderSyncStrategy` enums.
- Updating `ServerConfig`, GraphQL types, and backup models to use these new enums.
- Refactoring `KoreaderSyncService` to work with the enum types.

Additionally, this commit fixes an issue in `OpdsEntryBuilder` where the logic for determining which sync progress to use (local vs. remote) was duplicated. The builder now correctly delegates this decision to `KoreaderSyncService.pullProgress`, which already contains the necessary strategy logic. This centralizes the logic and ensures consistent behavior.

* refactor(koreader): Improve config handling and remove redundant update

This commit combines several refactoring and cleanup tasks:

- **Koreader Sync:** The sync service is updated to use the modern `serverConfig` provider instead of the legacy `GlobalConfigManager`. This aligns it with the current configuration management approach in the project.

- **Download Provider:** A redundant `pageCount` database update is removed from `ChaptersFilesProvider`. This operation was unnecessary because the `getChapterDownloadReady` function, which is called earlier in the download process, already verifies and corrects the page count. This change eliminates a superfluous database write and fixes a related import issue.

* feat(sync/koreader)!: enhance sync strategy and add progress tolerance

This commit overhauls the KOReader synchronization feature to provide more granular control and robustness. The simple on/off toggle has been replaced with a more flexible strategy-based system.

Key changes include:
- Replaced `koreaderSyncEnabled` with a more powerful `koreaderSyncStrategy` enum.
- Introduced new sync strategies: `PROMPT`, `SILENT`, `SEND`, `RECEIVE`, and `DISABLE`, allowing for fine-grained control over the sync direction and conflict resolution.
- Added a `koreaderSyncPercentageTolerance` setting. This prevents unnecessary sync updates for minor progress differences between Suwayomi and KOReader.
- Refactored the `KoreaderSyncService` to implement the new strategies and use the configurable tolerance.
- Updated GraphQL schemas, mutations, and server configuration to remove the old setting and incorporate the new ones.
- Adjusted the backup and restore process to correctly handle the new configuration parameters.
- Modified API endpoints and internal logic to check and apply remote progress based on the selected strategy.

BREAKING CHANGE: The `koreaderSyncEnabled` setting is removed and replaced by a more granular `koreaderSyncStrategy`. The enum values for the strategy have been completely changed, making previous configurations incompatible.

* fix: remove unused imports

* feat(opds, sync): enhance Koreader sync and OPDS conflict handling

This commit introduces significant improvements to the Koreader synchronization feature, focusing on providing a better user experience for handling progress conflicts in both OPDS and GraphQL clients.

Key changes include:

- **OPDS Conflict Resolution:** When a reading progress conflict is detected, the OPDS feed for a chapter now provides two distinct "Read Online" links: one to continue from the local progress and another to continue from the synced progress from the remote device (e.g., "Continue Reading Online (Synced from KOReader)"). This empowers users to choose which progress to follow.

- **GraphQL Sync Conflict Information:** The `fetchChapterPages` GraphQL mutation now includes a `syncConflict` field in its payload. This field provides the remote device name and page number, allowing GraphQL clients to implement a user-facing prompt to resolve sync conflicts.

- **Improved Sync Strategy Handling:**
  - The `connectKoSyncAccount` mutation no longer unconditionally sets the sync strategy to `PROMPT`. It now respects the user's existing setting, preventing accidental configuration changes upon re-login.
  - The default `koreaderSyncStrategy` in the configuration is changed to `DISABLED`, providing a safer and more intuitive default for new users.

- **Refinements & Fixes:**
  - The fallback for the remote device name is now centralized within the KoreaderSyncService, defaulting to "KOReader" if not provided.
  - Renamed `KoreaderSyncStrategy.DISABLE` to `DISABLED` for consistency.
  - Updated i18n strings for OPDS links to be more descriptive and user-friendly.

* refactor(kosync): rename stream page link titles for consistency

* refactor(kosync): return SettingsType in auth mutation payloads

The `connectKoSyncAccount` and `logoutKoSyncAccount` mutations modify server settings (username and userkey) but did not previously return the updated configuration. This forced client applications to manually refetch settings to avoid a stale cache.

This change modifies the payloads for both mutations to include the full `SettingsType`.

By returning the updated settings directly, GraphQL clients like Apollo Client can automatically update their cache, simplifying client-side state management and ensuring the UI always reflects the current server configuration.

Additionally, `clientMutationId` has been added to `KoSyncConnectPayload` for consistency with GraphQL practices, aligning it with the logout mutation.

Refs: #1560

* refactor(kosync): replace KoSyncConnectPayload with ConnectResult in connect method

* fix(kosync): add koreaderSyncPercentageTolerance default setting
2025-08-19 15:00:19 -04:00
schroda
1d9991e562 Feature/Improve chapter download with valid existing download handling (#1553)
* Fix early exit on download for existing download for FolderProvider

The current check only worked for the "ArchiveProvider". The "FolderProvider" never moved the existing download to the cache folder.

In case the existing download is considered to be reusable, there is no need to proceed with the download logic.

* Fix "ArchiveProvider#extractExistingDownload"

The "ChaptersFilesProvider#extractExistingDownload" expects the download to be extracted into the final download folder.
However, the "ArchiveProvider" extracted the download into the chapter download cache folder.

* Add chapter download function call requirements
2025-07-31 19:55:09 -04:00
schroda
ad7a8dd7dc Fix/page download conversion reduce logs (#1545)
* Cleanup chapter page conversion

* Reduce chapter page conversion logging
2025-07-25 19:42:06 -04:00
schroda
e3338211d6 Handle too long page image urls (#1544)
Attempted fix of 3ff29aa38a might not work, because there is no guarantee that the extension supports retrieving a specific page.
2025-07-25 19:42:00 -04:00
Mitchell Syer
ac5f1a0d93 Add enabled preference setting (#1539)
* Add enabled preference setting

* Don't change preference if its not enabled
2025-07-21 15:13:17 -04:00
Chiru-Dey
3ff29aa38a snowmtl extension error fix: dynamic retrieval (#1531)
* dynamic retrieval

* ktlint errors fixed

* reinstated comments
2025-07-21 15:12:57 -04:00
schroda
192136e66c Change "download conversion compression level" type to Double (#1535)
https://opensource.expediagroup.com/graphql-kotlin/docs/schema-generator/writing-schemas/scalars/#primitive-types
2025-07-20 17:00:00 -04:00
schroda
5057a57f7f Properly bind track privately (#1534)
In case the track was read from the TrackSearchTable the private status was never applied
2025-07-20 16:59:48 -04:00
Mitchell Syer
c63a06730f Fix downloads on errors when converting image (#1526)
* Fix downloads on errors when converting image

* Lint

* Simplify it

* No need for return

* Simplified
2025-07-16 21:52:54 -04:00
schroda
3bac176bf6 Prevent UnsupportedOperationException in DownloadManager (#1521)
CopyOnWriteArraySet does not support the usage of "removeAll" with a predicate
2025-07-15 09:32:11 -04:00
Constantin Piber
df0078b725 [#1496] Image conversion (#1505)
* [#1496] First conversion attempt

* [#1496] Configurable conversion

* Fix: allow nested configs (map)

* [#1496] Support explicit `none` conversion

* Use MimeUtils for provided download

* [1496] Support image conversion on load for downloaded images

* Lint

* [#1496] Support conversion on fresh download as well

Previous commit was only for already downloaded images, now also for
fresh and cached

* [#1496] Refactor: Move where conversion for download happens

* Rewrite config handling, improve custom types

* Lint

* Add format to pages mutation

* Lint

* Standardize url encode

* Lint

* Config: Allow additional conversion parameters

* Implement conversion quality parameter

* Lint

* Implement a conversion util to allow fallback readers

* Add downloadConversions to api and backup, fix updateValue issues

* Lint

* Minor cleanup

* Update libs.versions.toml

---------

Co-authored-by: Syer10 <syer10@users.noreply.github.com>
2025-07-14 17:51:18 -04:00
schroda
09c950a890 Fix/gql download subscription errors spamming emits (#1518)
* Remove immediate download notification for latest gql subscription

There is a problem where too many immediate updates can cause the client to lag out (e.g., in case it has to update the queue in the cache based on the updates).
This happens in case e.g., a source is broken and all its downloads error out basically immediately.
With each errored out download, a new one starts, which causes an immediate notification to the clients.

* Determine downloader status from active state of downloader jobs

In case the downloader is active but all downloads are erroring out immediately, no download will have the DOWNLOADING status.
This then would result in the downloader status to constantly be STOPPED.

* Prevent multiple update for the same downloads

It was possible that multiple updates got added for the same download.
This caused issues with the graphql apollo client, because it wasn't able to correctly update the client cache.

* Set download error state only after reaching max retries

In case the max retries haven't been reached yet, the download will be retried and thus setting and emitting the error state will cause weird looking ui updates.
2025-07-14 17:50:03 -04:00
schroda
06c1eeb995 Add missing transaction context to manga category update (#1516)
fixes #1510
2025-07-14 17:49:03 -04:00
Constantin Piber
68a131dbeb [#1349] Basic Cookie Authentication (#1498)
* [#1349] Stub basic cookie authentication

* [#1349] Basic login page

Also adjusts WebView header color and shadow to match WebUI. WebUI uses
a background-image gradient to change the perceived color, which was not
noticed originally.

* [#1349] Handle login post

* [#1349] Redirect to previous URL

* [#1349] Return a basic 401 for api endpoints

Instead of redirecting to a visual login page, API should just indicate
the bad state

* Use more appropriate 303 redirect

* Update server/src/main/kotlin/suwayomi/tachidesk/server/JavalinSetup.kt

Co-authored-by: Mitchell Syer <Syer10@users.noreply.github.com>

* Update server/src/main/kotlin/suwayomi/tachidesk/server/JavalinSetup.kt

Co-authored-by: Mitchell Syer <Syer10@users.noreply.github.com>

* Lint

* Transition to AuthMode enum with migration path

* Make basicAuthEnabled auto property, Lint

* ConfigManager: Make sure to re-parse the config after migration

* basicAuth{Username,Password} -> auth{Username,Password}

* Lint

* Update server settings backup model

* Update comment

* Minor cleanup

* Improve backup legacy settings fix

* Lint

* Simplify config value migration

---------

Co-authored-by: Mitchell Syer <Syer10@users.noreply.github.com>
2025-07-06 12:08:29 -04:00
Mitchell Syer
8c4a2cb529 Add chapter lastReadAt to backups as BackupHistory (#1477)
* Add chapter lastReadAt to backups as BackupHistory

* MaxOrNull
2025-06-28 17:04:04 -04:00
Mitchell Syer
52201e2488 Add private to trackrecords filter (#1468)
* Add private to trackrecords filter

* Remove sourceMapping from base

* Format
2025-06-26 22:04:26 -04:00
Mitchell Syer
ee9de376a3 Fix new private parameter in tracking backup (#1463)
* Fix new private parameter in tracking backup

* Cleanup uneeded models
2025-06-22 20:17:31 -04:00
Mitchell Syer
b54dc6f967 Fix Tracking DisplayScore (#1461) 2025-06-22 15:53:25 -04:00
Mitchell Syer
abea85d831 Update Tracking Backend (#1457)
* Update Tracking Library

* Update Bangumi

* Update Anilist

* Update MangaUpdates

* Update MAL

* Add private to bind track

* Use null

* Remove old nullable

* Remove custom implementation of supportsTrackDeletion

* Add private to updateTrack

* Some descriptions

* Another description
2025-06-22 10:38:22 -04:00
schroda
149b549d8d Handle chapter marked as downloaded without downloaded files (#1448)
In case a chapter was marked as downloaded but did not have any downloaded files, an uncaught exception was thrown
2025-06-15 17:15:10 -04:00
schroda
4086a73727 Feature/backup suwayomi data (#1430)
* Export meta data

* Import meta data

* Add missing "opdsUseBinaryFileSize" setting to gql

* Export server settings

* Import server settings

* Streamline server config enum handling

* Use "restore amount" in backup import progress
2025-06-15 17:14:13 -04:00
schroda
483e3a760f Increase chapter scanlator column max length (#1425) 2025-06-15 17:13:57 -04:00
schroda
ee4c852f1b Always update manga thumbnail on fetch (#1429)
It's possible that the cover changed, but the url is still the same.
In that case the cover never gets updated unless the downloaded/cached file gets deleted
2025-06-12 11:50:18 -04:00
schroda
1a5d334f6c Delete thumbnails during backup import (#1428)
Was accidentally removed with 633ea97848
2025-06-12 11:49:34 -04:00
schroda
7d72ff3514 Fix extracting "startDate" (#1427)
Value of json object was never properly accessed.
Start date can have different formats (yyyy-MM, yyyy-MM-dd) so it's not feasible to format it
2025-06-12 11:49:14 -04:00
schroda
e224e91100 Dequeue downloads of removed chapters (#1426)
Otherwise, graphql errors will be caused because the chapters won't be found and are unexpectedly null.

fixes #1358
2025-06-12 11:48:27 -04:00
schroda
ecea2ecdf5 Fix/initial scheduling of global update (#1416)
* Fix setting initial global update delay

In case no update has run yet, and the "last automated update" defaulted to 0, the calculation always resulted in a multiple of the interval.

This resulted for e.g., interval 24, to always be scheduled at 00:00.
For e.g., interval 6, it was always one of the following times: 00:00, 06:00, 12:00, 18:00; depending on the current system time.

* Delete the existing "last automated update time"

So that the update will be triggered based on the time the server got started again after the update.

* Extract migrations into separate functions

* Cleanup migration execution logic
2025-06-12 11:44:38 -04:00
schroda
1d7a60b630 Automatically truncate required varchar columns (#1423) 2025-06-12 11:39:19 -04:00
Zeedif
61f429896c feat(opds): implement full internationalization and refactor feed gen… (#1405)
* feat(opds): implement full internationalization and refactor feed generation

This commit introduces a comprehensive internationalization (i18n) framework
and significantly refactors the OPDS v1.2 implementation for improved
robustness, spec compliance, and localization.

Key changes:

Internationalization (`i18n`):
- Introduces `LocalizationService` to manage translations:
    - Loads localized strings from JSON files (e.g., `en.json`, `es.json`)
      stored in a new `i18n` data directory.
    - Default `en.json` and `es.json` files are bundled and copied from
      resources on first run if not present.
    - Supports template resolution with `$t()` cross-references, locale
      fallbacks (to "en" by default), and argument interpolation ({{placeholder}}).
- `ServerSetup` now initializes the `i18n` directory and `LocalizationService`.

OPDS Refactor & Enhancements:
- Replaces the previous `Opds.kt` and `OpdsDataClass.kt` with a new
  `OpdsFeedBuilder.kt` and a set of more granular, spec-aligned XML
  models (e.g., `OpdsFeedXml`, `OpdsEntryXml`, `OpdsLinkXml`).
- Integrates `LocalizationService` throughout all OPDS feeds:
    - All user-facing text (feed titles, entry titles, summaries,
      link titles, facet labels for sorting/filtering) is now localized.
    - Adds a `lang` query parameter to all OPDS endpoints to allow
      clients to request a specific UI language.
    - Uses the `Accept-Language` header as a fallback for language detection.
- The OpenSearch description (`/search` endpoint) is now localized and
  its template URL includes the determined language.
- Centralizes OPDS constants (namespaces, link relations, media types)
  in `OpdsConstants.kt`.
- Adds utility classes `OpdsDateUtil.kt`, `OpdsStringUtil.kt`, and
  `OpdsXmlUtil.kt` for common OPDS tasks.
- `MangaDataClass` now includes `sourceLang` to provide the content
  language of the manga in OPDS entries (`<dc:language>`).
- Updates OpenAPI documentation for OPDS endpoints with more detail
  and includes the new `lang` parameter.

Configuration:
- Adds `useBinaryFileSizes` server configuration option. File sizes in
  OPDS feeds now respect this setting (e.g., MiB vs MB), utilized via
  `OpdsStringUtil.formatFileSizeForOpds`.

This major refactor addresses the request for internationalization
originally mentioned in PR #1257 ("it would be great if messages were
adapted based on the user's language settings"). It builds upon the
foundational OPDS work in #1257 and subsequent enhancements in #1262,
#1263, #1278, and #1392, providing a more stable and extensible
OPDS implementation. Features like localized facet titles from #1392
are now fully integrated with the i18n system.

This resolves long-standing requests for better OPDS support (e.g., issue #769)
by making feeds more user-friendly, accessible, and standards-compliant,
also improving the robustness of features requested in #1390 (resolved by #1392)
and addressing underlying data needs for issues like #1265 (related to #1277, #1278).

* fix(opds): revert MIME type to application/xml for browser compatibility

* fix(opds): use chapter index for metadata feed and correct link relation

- Change `getChapterMetadataFeed` to use `chapterIndexFromPath` (sourceOrder)
  instead of `chapterIdFromPath` for fetching chapter data, ensuring
  consistency with how chapters are identified in manga feeds.
- Add error handling for cases where manga or chapter by index is not found.
- Correct OPDS link relation for chapter detail/fetch link in non-metadata
  chapter entries from `alternate` to `subsection` as per OPDS spec
  for navigation to more specific content or views.

* Use Moko-Resources

* Format

* Forgot the Languages.json

* refactor(opds)!: restructure OPDS feeds and introduce data repositories

This commit significantly refactors the OPDS v1.2 implementation by introducing dedicated repository classes for data fetching and by restructuring the feed generation logic for clarity and maintainability. The `chapterId` path parameter for chapter metadata feeds has been changed to `chapterIndex` (sourceOrder) to align with how chapters are identified in manga feeds.

BREAKING CHANGE: The OPDS endpoint for chapter metadata has changed from `/api/opds/v1.2/manga/{mangaId}/chapter/{chapterId}/fetch` to `/api/opds/v1.2/manga/{mangaId}/chapter/{chapterIndex}/fetch`. Clients will need to update to use the chapter's source order (index) instead of its database ID.

Key changes:
- Introduced `MangaRepository`, `ChapterRepository`, and `NavigationRepository` to encapsulate database queries and data transformation logic for OPDS feeds.
- Moved data fetching logic from `OpdsFeedBuilder` to these new repositories.
- `OpdsFeedBuilder` now primarily focuses on constructing the XML feed structure using DTOs provided by the repositories.
- Renamed `OpdsMangaAcqEntry.thumbnailUrl` to `rawThumbnailUrl` for clarity.
- Added various DTOs (e.g., `OpdsRootNavEntry`, `OpdsMangaDetails`, `OpdsChapterListAcqEntry`) to define clear data contracts between repositories and the feed builder.
- Simplified `OpdsV1Controller` by reorganizing feed endpoints into logical groups (Main Navigation, Filtered Acquisition, Item-Specific).
- Updated `OpdsAPI` to reflect the path parameter change for chapter metadata (`chapterIndex` instead of `chapterId`).
- Added `slugify()` utility to `OpdsStringUtil` for creating URL-friendly genre IDs.
- Standardized localization keys for root feed entry descriptions to use `*.entryContent` instead of `*.description`.
- Added `server.generated.BuildConfig` (likely from build process).

* style(opds): apply ktlint fixes

* Delete server/bin

* refactor(i18n): remove custom LocalizationService initialization

* refactor(i18n): remove unused imports from ServerSetup

* refactor(model): remove sourceLang from MangaDataClass

* refactor(opds): rename OPDS binary file size config property

- Rename `useBinaryFileSizes` to `opdsUseBinaryFileSizes` in code and config
- Update related condition check in formatFileSizeForOpds

BREAKING CHANGE: Existing server configurations using `server.useBinaryFileSizes` need to migrate to `server.opdsUseBinaryFileSizes`

* refactor(opds): improve OPDS endpoint structure and documentation

- Restructure endpoint paths for better resource hierarchy
- Add descriptive comments for each feed type and purpose
- Rename `/fetch` endpoint to `/metadata` for clarity
- Standardize feed naming conventions in route definitions

BREAKING CHANGE: Existing OPDS client integrations using old endpoint paths (`/manga/{mangaId}` and `/chapter/{chapterIndex}/fetch`) require updates to new paths (`/manga/{mangaId}/chapters` and `/chapter/{chapterIndex}/metadata`)

* fix(opds): Apply review suggestions for localization and comments

* Fix

* fix(opds): Update chapter links to include 'chapters' and 'metadata' in URLs

---------

Co-authored-by: Syer10 <syer10@users.noreply.github.com>
2025-05-26 20:46:14 -04:00
schroda
89421946af Properly deschedule active tasks (#1413) 2025-05-26 20:45:48 -04:00
Edge At Zero
d0f79ca473 Fix: Validate zipEntry directories during extension asset decompression (#1407) 2025-05-26 20:45:20 -04:00
Mitchell Syer
ec870759cf Add highest numbered chapter function in MangaType (#1397)
* Add highest numbered chapter function in MangaType

* Fix name
2025-05-22 19:58:09 -04:00
Shirish
0405a535c7 Feat: Adds OPDS Chapter Filtering/Ordering (#1392)
* Adds server level configs for OPDS

* PR comments

* Refactor server-reference.conf (itemsPerPage range)

* Coerce itemsPerPage (10, 5000) and default invalid sort orders to DESC

* Coerce itemsPerPage (10, 5000) and default invalid sort orders to DESC

* Change opdsChapterSortOrder type to Enum(SortOrder)

* Fix serialization of SortOrderEnum & Add `opdsShowOnlyDownloadedChapters` config
2025-05-22 19:57:55 -04:00
Mitchell Syer
538bd3f126 Improve Downloads Handling (#1387)
* Improve Downloads Handling

* Update known pagecount for downloaded chapters

* Get fresh data for downloadReady

* Format

* Assume downloaded if first page is found

* Filter out ComicInfoFile
2025-05-16 15:57:53 -04:00
Mitchell Syer
336f985894 Fix Downloaded pages with no cached pages from source (#1386) 2025-05-16 12:45:39 -04:00
schroda
785c0469ac Fix/m0045 prevent duplicated chapter pages migration (#1361)
* Fix "imageUrl" column name in migration

* Rename column "imageUrl" to "IMAGE_URL" of table "Page"
2025-04-27 19:33:15 -04:00
schroda
59d2151c92 Prevent duplicated chapter pages (#1353)
In case "ChapterForDownload#asDownloadReady" was called in quick succession, the page list got inserted twice.

This caused problems with getting the images from the rest endpoint, because they are selected by sorting them by asc index and selecting the page by using the provided index as an offset.

This, however, only works as long as there are no duplicates, otherwise, page indexes 1, 2; 3, 4; 5, 6; ... will just return the same page.
2025-04-27 18:54:54 -04:00
KAAAsS
f8d73819ea [Feature] Support Bangumi Tracker (#1343)
* feat: Support Bangumi Tracker

Credits: Andreas, AntsyLich, Caleb Morris, Gauthier, MCAxiaz, MajorTanya, NarwhalHorns, arkon, fei long, jmir1, mutsumi, stevenyomi

* Use Suwayomi api keys

---------

Co-authored-by: Mitchell Syer <Syer10@users.noreply.github.com>
2025-04-12 19:34:04 -04:00
schroda
3167d8aa15 Fix/startup jvm error after installation update via msi (#1229)
* Remove existing installations with msi installer

* Remove unused x86 wxs file

* Uninstall old msi versions with different upgrade code

* Progress but error 2721 happens on install

* Remove added uninstall previous version wxs stuff

* Use revision as patch number

MSI only uninstalls previous versions in case the version number changed (it only checks the first three numbers (major, minor, patch)).
Thus, to prevent each preview install to result in it getting registered as a new "app" and for it to uninstall the old versions, we have to change the version on each release.

* Deprecate "BuildConfig.REVISION"

* Remove outdated env vars

---------

Co-authored-by: Syer10 <syer10@users.noreply.github.com>
2025-04-06 15:09:56 -04:00
schroda
226fad5594 Remove "default" category from backups (#1307)
Restoring a suwayomi backup in mihon created a category named "Default"
2025-03-22 19:34:57 -04:00
schroda
439e0c8284 Emit only updater job changes instead of full status (#1302)
The update subscription emitted the full update status, which, depending on how big the status was, took forever because the graphql subscription does not support data loader batching, causing it to run into the n+1 problem
2025-03-22 19:34:43 -04:00
Shirish
95d9293fe0 Add support for opds-pse for undownloaded chapters (#1278)
* Add OPDS page streaming for undownloaded chapters

* Add [D] in chapter title prefix when isDownloaded

* Removed Chapter.isDownloaded check in query for other opds endpoints

* Add chapter progression tracking for streaming and refactor code

* dd  Unicode for chapters with 0 pages [post pageRefresh]

* Add Library Updates feed and remove redundant metadata fetching for OPDS chapters and manga

* Address PR comments & add chapter markAsRead for cbzDownload

* Address PR comment/s

* Rem. markAsRead for chapter download

* Rem. markAsRead for chapter download

---------

Co-authored-by: ShowY <showypro@gmail.com>
2025-03-08 11:31:07 -05:00
Constantin Piber
3be165a551 Initial import of Kitsu tracker (#1297)
* Initial import of Kitsu tracker

Based on Mihon 6c6ea84509cc1bd859c880bebbc69067a241b358 because its
successor 9f99f03 relies on incompatible changes

* Kitsu: Avoid stupid long/int cast
2025-03-08 11:30:59 -05:00