Fixes problems like
```
java.lang.ClassNotFoundException: org.cef.callback.CefResourceReadCallback_N
```
and
```
Exception in thread "Thread-584" java.lang.NoSuchMethodError: open
```
* Reset update-flag on uninstall
If there is an update available when the extension is uninstalled, the
table will still have the update flag, which makes no sense if it is not
installed.
Example:
```
{
"pkgName": "eu.kanade.tachiyomi.extension.en.comix",
"name": "Comix",
"lang": "en",
"versionCode": 20,
"versionName": "1.4.20",
"iconUrl": "/api/v1/extension/icon/tachiyomi-en.comix-v1.4.20.apk",
"repo": "<hidden>",
"isNsfw": true,
"isInstalled": false,
"isObsolete": false,
"hasUpdate": true,
"__typename": "ExtensionType"
},
```
* Update changelog
* Standardize toSqlName
* Rename Meta Key db field since KEY is now a reserved name in H2
* Changelog entry
* Use toSqlName
* Forgot this key
* Catch any exception
* Update graphqlkotlin to v9
* Update to the v10 alpha due to nullability issues in v9
* Fixes
* Remove asDataFetcherResult
---------
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Syer10 <syer10@users.noreply.github.com>
Add KCEF build args to docker-compose.yml so the image is built with
Xvfb and CEF binaries, enabling WebView-based sources like MangaFire.
Remove redundant kcefDir.createDirectories() in ServerSetup which caused
FileAlreadyExistsException when KCEF.init tried to create the same dir.
New GET endpoint at /api/v1/manga/{mangaId}/chapter/{chapterIndex}/page/{index}/image
that buffers the image into a byte array and sets Content-Length, enabling
progress tracking in Tachiyomi-based Android extensions.
Makes it so that the client section is less likely to get outdated and therefore requires less maintenance
Provides only information about how the clients can be run.
The client repo itself is responsible for providing any other information.
Remove clients that have not had any commits in years
Using a script to inject the base tag is unnecessarily complex as well as it is introducing an issue where the initial requests will potentially fail, due to the base tag not being injected yet.
See https://github.com/Suwayomi/Suwayomi-WebUI/issues/1096, same issue applies when a subpath is set up which can't be fixed on the client side
* fix: support for POST requests
Works with Flaresolverr. Required for Kagane.
Byparr is not a drop-in replacement, it just ignores the `cmd` and interprets everything as a GET request.
* Use encodeToString instead
* linting
* Use FormBody for encoding
Co-authored-by: Mitchell Syer <Syer10@users.noreply.github.com>
* Add missing imports
* linting, again
---------
Co-authored-by: Mitchell Syer <Syer10@users.noreply.github.com>
I mistakenly thought that the suwayomi schema was always being used and therefore did not think a migration for the fix b4595b70d6 was necessary.
However, this was only the case in case the username was set to suwayomi. Otherwise, the public schema was being used.
Thus, we need to migrate the data from the public schema to the suwayomi schema in these cases.
* Set default schema for postgresql db
The schema was only set once during startup. This is, however, only set for the current connection. So when using hikaricp, depending on which connection was used, the schema might have been set, or it might not have been set.
fixes#1670
* Revert "Fix database connection and errors (#1681)"
This reverts commit 2e0f72f182.
Not necessary anymore as the issue that this change intended to fix is now fixed with 091206800025ed9370d611e7ca3430ab409a0cb2
* fix: Do not return `inputStream` from conversion
The returned value must be owned, since the caller closes the input
stream on success
* fix: Assume a conversion error consumes the input stream
e.g. converting an ARGB png to jpeg will throw "bogus colorspace", but
only after the inputstream is consumed. so in case of an exception, we
have to assume that the stream is broken and re-open the page from cache
* BitmapFactory: Support basic options
* Bitmap: Support querying image type
* Bitmap: Support all BufferedImage image types
Required to be able to construct a bitmap with exactly the same
parameters
* Remove link to reference config
We don't include that any more, since it's now generated at build time
* Update outdated note regarding backup in Database section
Since #1682, the caution block is not true anymore
The "download conversions headers" caused a SerializationException.
kotlinx.serialization.SerializationException: 'null' is not supported as the value of collection types in ProtoBuf
The server setting updater passed an already converted value to the setting validator, which then tried to convert the value again, which caused an error
Regression aa8d27f679
* Move the "group" arg at the second position after "protoNumber"
To make it consistent for all settings
* Improve server config non privacy safe setting handling
---------
Co-authored-by: Mitchell Syer <Syer10@users.noreply.github.com>
* Fix typo in setting validation error message
* Convert value to internal type before validating it
* Only update setting in case value is valid
* Ignore settings validation errors on backup restore
* Remove potential not privacy safe value from logs
There is a possibility that the serve folder was only partially deleted. This then could cause "FileAlreadyExistsException" when copying the webui files to the serve folder.
* Use JDK 25 to build and include in releases
* Set Jvm Targets in BuildSrc
* Put JvmTarget in libs.versions.toml
* Maybe this will work for Zulu
* Use LTS java version
* Remove koreader-sync credentials from config
These are supposed to be set via the login/logout mutations and are not meant to be set manually by the user. Thus, they are not really settings and do not belong to the config
* Reduce log levels of KoreaderSyncService
Requesting a chapter page while having a non basic auth mode (e.g. ui login) enabled caused the basic auth prompt.
However, this is only supposed to be happen for opds
When the webUI got opened before the setup was completed, the missing folder caused an exception and broke the javalin server.
In that case, even after the webui setup completed, the server just returned the index.html for every path
* [#1749] Only consider path in SIMPLE_LOGIN redirect
We don't really care about the origin, since that is implicit in
`Location` headers if not given, which sidesteps the HTTP/HTTPS issue
* Refuse non-relative redirects
* Revert "[#1739] Support sending floats (#1740)"
This reverts commit c1f2aae90d.
Closes#1746
* Use `DoubleFilter` for GQL interface, convert to `FloatFilter`
Closes#1739 (again)
* [#1739] Support sending floats
Required for `FloatFilter`, which needs to be float due to DB layer
* Simplify `parseValueImpl`, use correct coercion hints
* fix: Match URLs with trailing /
* Handle permission requests and attempt to enable Widevine
* Tie CEF loglevel to server debug logs
* Lint
* Add missing file
Forgot to add in previous commits
* Provide WebResourceResponse
* Fix NullException if headers are not set
* fix: Don't allow interception for initial page load
fixes#1713
* Lint
* Add backup flags to auto backups
* Mark ServerConfig properties as deprecated
---------
Co-authored-by: Mitchell Syer <Syer10@users.noreply.github.com>
* Extract global metadata backup logic into BackupGlobalMetaHandler
* Extract category backup logic into BackupCategoryHandler
* Extract source backup logic into BackupSourceHandler
* Extract manga backup logic into BackupMangaHandler
On mac the temp system folder is a symlink which jetty does not allow by default due to security reasons.
This caused the webui files to not get served on mac.
There was a possible race condition where immediate state updates got overwritten by previously queued ones.
For example, when the download was successful but the downloaded files are deemed invalid, a previously queued download progress state update might overwrite the emitted error state.
* Add way to exclude settings from backups
* Exclude flaresolverrEnabled
* Exclude usernames/passwords
* Exclude writing deprecated settings to the backup
* Exclude AuthMode
* Move `apt` commands behind `$CI`
Same as for the windows command, no need to rerun this every time
* Use fallback to avoid unbound variables
* Scripts: Switch to Zulu JRE
* workflows: Switch to zulu JDK
* fix: Launcher requires sun.awt.* exports
* Update renovate for Zulu
* 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
* 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>
* 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
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.
* [#1575] Support paste
* WebView: Implement copy
* Localize copy dialog, lint
* Implement a custom context menu for copy/paste
* Remove click event which causes double events
* WebView: Fix input events broken by moved preventDefault
We want to fall back to the `input` event for Android bug and paste, but
we want to prevent the event for the others, so change the order
* Initial Noto fonts
* Use Noto for other default fonts
* Typeface: Prefer main font
Eagerly switch back to main font as soon as it can display again;
otherwise we might never switch back (or later than necessary); we
should always prefer the main font
* fix: Font metrics with fallback font on TextLine
* 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
* 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
* fix: correct chapter facets URL to include /chapters endpoint
Update addChapterSortAndFilterFacets to use the correct URL path
from `/manga/{id}` to `/manga/{id}/chapters` for proper routing.
* feat(opds): restructure feeds and add exploration capabilities
This commit completely refactors the OPDS v1.2 implementation to align it more closely with the WebUI experience, separating "Library" browsing from "Explore" functionality.
Key changes include:
- The root feed is now a navigation feed directing to distinct "Library" and "Explore" sections.
- A new "History" feed has been added to the root to show recently read chapters.
- The "Explore" section now allows browsing all available sources, not just those with manga in the library.
- Feeds for exploring a source now support faceting by "Popular" and "Latest", mirroring the WebUI.
- The "Library" section retains all previous browsing methods (by category, genre, status, etc.).
- Facet link generation has been corrected to use the proper base URL, fixing broken navigation in chapter lists.
- The `OpdsFeedBuilder.kt` file has been refactorized into smaller, more manageable helper files (`OpdsEntryBuilder.kt`, `OpdsFeedHelper.kt`) to resolve a `java.lang.OutOfMemoryError: GC overhead limit exceeded` error during compilation.
- All OPDS-related strings (`strings.xml`) have been updated to reflect the new structure and improve clarity.
This new structure provides a much more intuitive and powerful browsing experience for OPDS clients, enabling content discovery in addition to library management.
* feat(opds)!: implement advanced filtering and sorting for library feeds
This commit significantly enhances the OPDS library feeds by introducing advanced sorting and filtering capabilities, mirroring the features available in the WebUI. It also standardizes the terminology from "manga" to "series" across all user-facing OPDS feeds for better clarity and consistency.
Key Features & Changes:
- **Library Facets:** All library feeds (All Series, By Source, By Category, By Genre, etc.) now include OPDS facets for:
- **Sorting:** By title (A-Z, Z-A), last read, latest chapter, date added, and total unread chapters.
- **Filtering:** By content status including unread, downloaded, ongoing, and completed.
- **Terminology Update:** The term "manga" has been replaced with "series" in all user-facing OPDS titles, descriptions, and endpoints to align with the frontend terminology.
- **Code Refactoring:**
- `MangaRepository` has been updated with the correct Exposed SQL syntax (`Case`/`sum` for conditional counts, `having` clause for filtering on aggregates) to support the new facets.
- `OpdsEntryBuilder` now includes a new function `addLibraryMangaSortAndFilterFacets` to generate the facet links.
- `OpdsV1Controller` and `OpdsFeedBuilder` have been updated to handle the new `sort` and `filter` parameters and to call the new facet generation logic.
BREAKING CHANGE: The API endpoints for manga have been renamed to use 'series'. Any client implementation will need to update its routes.
For example, `/api/opds/v1.2/manga/{id}/chapters` is now `/api/opds/v1.2/series/{id}/chapters`.
* feat(opds): add item counts (thr:count) to navigation and facet links
This change enhances the OPDS feeds by including the number of items for various navigation links and filter facets, adhering to the OPDS 1.2 specification.
The `thr:count` attribute provides a hint to clients about the number of entries in a linked feed, significantly improving the user experience by showing counts upfront.
- Navigation Feeds (Categories, Sources, Genres, Statuses, Languages) now display the total number of manga for each entry in their respective links.
- Acquisition Feeds for the library and chapters now include counts for their filter facets (e.g., Unread, Downloaded, Completed).
This required updating DTOs to carry count data, modifying repository queries to calculate these counts efficiently, and adjusting the feed builders to include the `thr:count` attribute in the generated XML.
* refactor(opds)!: simplify root feed by removing library sub-level
The OPDS feed navigation was previously nested, requiring users to first select "Library" and then navigate to a subsection like "All Series" or "Categories". This extra step is cumbersome for OPDS clients and complicates the user experience.
This change elevates all library-related navigation entries directly to the root feed, flattening the hierarchy and making content more accessible.
As part of this refactoring:
- The `getLibraryFeed` builder and its corresponding controller/API endpoints have been removed.
- Unused string resources for the "Library" entry have been deleted.
BREAKING CHANGE: The `/api/opds/v1.2/library` endpoint has been removed. Clients should now discover library sections directly from the root feed at `/api/opds/v1.2`.
* feat(opds): enhance feeds with comprehensive manga and chapter details
This commit significantly enriches the OPDS feeds to provide a more detailed and compliant user experience.
- Refactored `OpdsMangaAcqEntry` and `OpdsChapterMetadataAcqEntry` to include additional fields such as status, source information, author, description, and web URLs.
- The OPDS entry builder (`OpdsEntryBuilder`) now populates entries with this richer metadata, including summaries, content descriptions, authors, and categories, aligning more closely with the OPDS Catalog specification.
- Added OPDS constants for 'popular' and 'new' sort relations to align with the specification.
- Included "alternate" links for both manga and chapters, allowing clients to open the item on its source website ("View on web").
- Updated internationalization strings and constants to support the new features and metadata.
* fix(opds): fetch chapters for non-library manga in feed
Previously, when accessing the OPDS chapter feed for a manga discovered via the "Explore" feature (and thus not yet in the library), the feed would be empty. This was because the feed generation logic only queried the local database, which had no chapter entries for these manga.
This commit resolves the issue by modifying `getSeriesChaptersFeed` to be a suspend function. It now implements a fallback mechanism:
- It first attempts to load chapters from the local database.
- If no chapters are found, it triggers an online fetch from the source to populate the database.
- It then re-queries the local data to build the complete chapter feed.
This ensures that chapter lists are correctly displayed for all manga, whether they are in the library or being explored for the first time.
Additionally, this commit includes a minor correction to the URN identifier for the root feed to better align with its path.
* feat(opds): provide direct stream and acquisition links when page count is known
Previously, the OPDS chapter feed always provided a single link to a separate metadata feed for each chapter. This was done to defer the costly operation of fetching the page count for undownloaded chapters, ensuring the main chapter list loaded quickly.
This commit introduces a more efficient, conditional approach. If a chapter's page count is already known (e.g., because it's downloaded or has been previously fetched), the chapter feed entry now includes direct links for:
- OPDS-PSE page streaming (`pse:stream`).
- CBZ file acquisition (`acquisition/open-access`).
- Chapter cover image (`image`).
If the page count is not known, the entry falls back to the previous behavior, linking to the metadata feed to perform the page count lookup on-demand.
This significantly improves the user experience for OPDS clients by reducing the number of requests needed to start reading or downloading chapters that are already available on the server, making navigation faster and more fluid.
* fix(opds): resolve suspend calls and add missing lastReadAt for OPDS feeds
The OPDS feed generation was failing to compile due to two main issues:
1. The `OpdsChapterListAcqEntry` DTO was missing the `lastReadAt` property, which is required for the OPDS-PSE `lastReadDate` attribute.
2. Several functions in `OpdsFeedBuilder` were attempting to call the `suspend` function `createChapterListEntry` from a non-coroutine context.
This commit resolves these issues by:
- Adding the `lastReadAt` field to `OpdsChapterListAcqEntry` and populating it correctly from the database in the `ChapterRepository`.
- Refactoring `getHistoryFeed`, `getLibraryUpdatesFeed`, and `getSeriesChaptersFeed` in `OpdsFeedBuilder` to be `suspend` functions.
- Wrapping the entry creation logic in `withContext(Dispatchers.IO)` to provide the necessary coroutine scope for the suspend call and to perform the mapping on a background thread.
* refactor(opds): standardize library feed generation and enhance facets
This commit refactors the OPDS v1.2 feed generation logic to improve code structure, correctness, and feature capability.
The primary changes include:
- A new private `getLibraryFeed` helper function in `OpdsV1Controller` has been introduced to centralize and DRY up the logic for creating library-specific acquisition feeds.
- A new `OpdsMangaFilter` DTO now encapsulates all filtering, sorting, and pagination parameters, simplifying the controller handlers and making them more maintainable.
- URL generation for category, genre, status, and language feeds has been corrected. Links now correctly point to root-level paths (e.g., `/opds/v1.2/genre/{name}`) instead of being incorrectly nested under `/library/`.
- The OPDS facet system is enhanced with more specific facet groups and "All" links for a better user experience when clearing filters.
Associated changes:
- i18n strings in `strings.xml` have been reorganized with comments and new strings have been added to support the enhanced facet groups.
- The route for the publication status feed has been renamed from `/status/{id}` to `/statuses` for consistency.
- KDoc comments have been added and improved throughout the affected files for better code documentation.
* fix(opds): revert direct acquisition links in chapter feeds to improve performance
This reverts commit 33cdc0d534292760a3225cee18e274df542f0778.
The previous change introduced direct stream and download links in chapter list feeds when the page count was known. While convenient, this caused a significant performance degradation on feeds with many chapters, as it required checking for the existence of a CBZ file for every single entry.
This commit restores the original behavior where chapter list entries always link to a dedicated metadata feed. This approach defers expensive I/O operations until a user explicitly requests a single chapter's details, ensuring that chapter list feeds load quickly and efficiently. Direct acquisition and streaming links are now exclusively generated within the metadata feed.
* Delete duplicated chapter page rows by index and chapter
In case duplicated rows based on the condition for the updated unique constraint existed, the new constraint could not be added and caused the migration to fail
* Drop UC_PAGE only if it exists
* [#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>
* 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.
* [#1497] WebView: Localstorage
* WebView: Transition to our own header/postData system
This is also what is recommended by most other posts, I haven't seen the
context used anywhere, and `KCEFResourceRequestHandler` seems to just
bypass a lot of CEF
* Lint
* [#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>
* WebView: Add initial controller
Co-authored-by: Mitchell Syer <Syer10@users.noreply.github.com>
* WebView: Prepare page
* WebView: Basic HTML setup
* WebView: Improve navigation
* WebView: Refactor message class deserialization
* WebView: Refactor event message serialization
* WebView: Handle click events
* WebView: Fix events after refactor
* WebView: Fix normalizing of URLs
* WebView: HTML remove navigation buttons
* WebView: Handle more events
* WebView: Handle document change in events
* WebView: Refactor to send mutation events
* WebView: More mouse events
* WebView: Include bubbles, cancelable in event
Those seem to be important
* WebView: Attempt to support nested iframe
* WebView: Handle long titles
* WebView: Avoid setting invalid url
* WebView: Send mousemove
* WebView: Start switch to canvas-based render
* WebView: Send on every render
* WebView: Dynamic size
* WebView: Keyboard events
* WebView: Handle mouse events in CEF
This is important because JS can't click into iFrames, meaning the
previous solution doesn't work for captchas
* WebView: Cleanup
* WebView: Cleanup 2
* WebView: Document title
* WebView: Also send title on address change
* WebView: Load and flush cookies from store
* WebView: remove outdated TODOs
* Offline WebView: Load cookies from store
* Cleanup
* Add KcefCookieManager, need to figure out how to inject it
* ktLintFormat
* Fix a few cookie bugs
* Fix Webview on Windows
* Minor cleanup
* WebView: Remove /tmp image write, lint
* Remove custom cookie manager
* Multiple cookie fixes
* Minor fix
* Minor cleanup and add support for MacOS meta key
* Get enter working
* WebView HTML: Make responsive for mobile pages
* WebView: Translate touch events to mouse scroll
* WebView: Overlay an actual input to allow typing on mobile
Browsers will only show the keyboard if an input is focused. This also
removes the `tabstop` hack.
* WebView: Protect against occasional NullPointerException
* WebView: Use float for clientX/Y
* WebView: Fix ChromeAndroid being a pain
* Simplify enter fix
* NetworkHelper: Fix cache
* Improve CookieStore url matching, fix another cookie conversion issue
* Move distinctBy
* WebView: Mouse direction toggle
* Remove accidentally copied comment
---------
Co-authored-by: Mitchell Syer <Syer10@users.noreply.github.com>
Some native code (CEF) may cause SIGTRAP to be sent on fatal errors,
which brings down the entire server. Instead only kill the thread and
attempt to continue.
* Bitmap: Use provided config
* Bitmap: implement copy
* Bitmap: Simplify getPixels
This also fixes a bug where the returned data may not be in the correct
format
Android getPixels():
> The returned colors are non-premultiplied ARGB values in the sRGB color space.
BufferedImage getRGB():
> Returns an array of integer pixels in the default RGB color model (TYPE_INT_ARGB) and default sRGB color space
* Stub TextPaint and Paint
* Paint: Implement some required functions
* Stub StaticLayout and Layout
* Implement some Paint support
* Draw Bounds
* WebP write support
* First text rendering
* Paint: Fix text size, font metrics
* Paint: Fix not copying new properties
Fixes font size in draw
* Canvas: Stroke add cap/join for better aliasing
Otherwise we get bad artifacts on sharp corners
Based on https://stackoverflow.com/a/35222059/
* Remove logs
* Canvas: Implement other drawText methods
* Bitmap: support erase
* Layout: Fix text direction
Should be LTR, otherwise 0 is read, which is automatically interpreted
as RTL without explicit check
* Bitmap: scale to destination rectangle
* Canvas: drawBitmap with just x/y
* Bitmap: Convert image on JPEG export to RGB
JPEG does not support alpha, so will throw "bogus color space"
* Switch to newer fork
* LoadData: Use regular load but intercept request
The method we used before, `createBrowserWithHtml`, is implemented by
KCEF. This method creates a `file://` url and adds handlers for that.
Instead, use regular `createBrowser` and intercept the request later on.
This has the effect of creating the page with the correct origin, while
still setting the requested HTML instead of live data. This is important
for scripts due to CORS.
Also fixes a mistake in the ResourceRequestHandler, where (a) the status
was not set, resulting in ABORT, (b) the return value of `readResponse`
was correct (`false` too early) and (c) the callback was unnecessarily
called on the MainLoop.
Based on https://stackoverflow.com/a/52423252/
* Convince the compiler we're doing it right
Invoking "public final" methods would fail. Not sure why this only
happens for some extensions, but it does. We need to tell the compiler
we're sure we have access to it, for some reason...
* JS: Invoke result handler on the loop
Some extensions call WebView methods on the result, so this should be on
the same loop as the WebView itself
* JS: Await arguments
* Fix using wrong URL property for errors
* 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
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
* 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
* Implement Android's Looper
Looper handles thread messaging. This is used by extensions when they
want to enqueue actions e.g. for sleeping while WebView does someting
* Stub WebView
* Continue stubbing ViewGroup for WebView
* Implement WebView via Playwright
* Lint
* Implement request interception
Supports Yidan
* Support WebChromeClient
For Bokugen
* Fix onPageStarted
* Make Playwright configurable
* Subscribe to config changes
* Fix exposing of functions
* Support data urls
* Looper: Fix infinite sleep
* Looper: Avoid killing the loop on exception
Just log it and continue
* Pump playwright's message queue periodically
https://playwright.dev/java/docs/multithreading#pagewaitfortimeout-vs-threadsleep
* Update server/src/main/kotlin/suwayomi/tachidesk/graphql/types/SettingsType.kt
Co-authored-by: Mitchell Syer <Syer10@users.noreply.github.com>
* Stub a KCef WebViewProvider
* Initial Kcef Webview implementation
Still buggy, on the second call it just seems to fall over
* Format, restructure to create browser on load
This is much more consistent, before we would sometimes see errors from
about:blank, which block the actual page
* Implement some small useful properties
* Move inline objects to class
* Handle requests in Kcef
* Move Playwright implementation
* Document Playwright settings, fix deprecated warnings
* Inject default user agent from NetworkHelper
* Move playwright to libs.versions.toml
* Lint
* Fix missing imports after lint
* Update server/src/main/kotlin/suwayomi/tachidesk/server/ServerSetup.kt
Co-authored-by: Mitchell Syer <Syer10@users.noreply.github.com>
* Fix default user agent set/get
Use System.getProperty instead of SystemProperties.get
* Configurable WebView provider implementation
* Simplify Playwright settings init
* Minor cleanup and improvements
* Remove playwright WebView impl
* Document WebView for Linux
---------
Co-authored-by: Mitchell Syer <Syer10@users.noreply.github.com>
* 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>
* 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
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.
* 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>
* Log exceptions during graphql execution
Exceptions got swallowed by graphql
* Add stack trace to error in graphql response
Depending on the exceptions error message, the error in the response might be quite useless (e.g. "Stub!" error in android classes)
* Update github issue templates to yml format
* Remove "issue moderator" workflow
* Require more client info for "bug issues"
- client name
- client version
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
* Initial import of Kitsu tracker
Based on Mihon 6c6ea84509cc1bd859c880bebbc69067a241b358 because its
successor 9f99f03 relies on incompatible changes
* Kitsu: Avoid stupid long/int cast
* Optimize restoring manga chapters
* Streamline restoring manga data
* Optimize restoring manga trackers
* Simplify passing manga category restore data
* Properly prevent mangas from getting added to default category
76595233fc never actually worked...
* Extract logic to add manga to categories from gql mutation
* Optimize restoring manga categories
* Optimize restoring categories
coerceIn throws an error in case the max value is less than the min value ("Cannot coerce value to an empty range: maximum <max> is less than minimum <min>")
Regression from c8bd39b4bf
* Extract logic to restore manga chapters into function
* Extract logic to restore manga categories into function
* Extract logic to restore manga trackers into function
* Handle duplicated chapters in backup
In case a backup contained duplicated chapters for a manga, the manga failed to restore since the ChapterTable has a unique constraint to prevent multiple chapters with the same "url" and "mangaId"
* Añadiendo algunos cambios iniciales para probar OPDS
* Add suport to OPDS v1.2
* Added support for OPDS-PSE and reorganized controllers
* Rename chapterIndex to chapterId in the API and controller, and update descriptions in OPDS
* Refactor OPDS to use formatted timestamps and proxy thumbnail URLs
* Refactor OPDS to use formatted timestamps and proxy thumbnail URLs
* Update Manga API to download chapters cbz using only chapterId and improve chapter download query
* Optimize OPDS queries
* Update Manga API to download chapters cbz using only chapterId and improve chapter download query
* Optimize OPDS queries
* Use SourceDataClass to map sources and optimize thumbnail URL retrieval
* Kotlin lint errors in ChapterDownloadHelper and Opds
* Kotlin lint errors in ChapterDownloadHelper and Opds
* Refactor OPDS API endpoints and rename OpdsController to OpdsV1Controller
* Translate OpdsV1Controller comments to English and remove unused imports
* Translate comments in OpdsAPI.kt to English
* Add SearchCriteria class and update OpdsV1Controller
* Remove spanish comments
* Refactor search handling in OpdsV1Controller and update search feed endpoint
* Fix search
* Añadiendo algunos cambios iniciales para probar OPDS
* Add suport to OPDS v1.2
* Added support for OPDS-PSE and reorganized controllers
* Rename chapterIndex to chapterId in the API and controller, and update descriptions in OPDS
* Refactor OPDS to use formatted timestamps and proxy thumbnail URLs
* Refactor OPDS to use formatted timestamps and proxy thumbnail URLs
* Update Manga API to download chapters cbz using only chapterId and improve chapter download query
* Optimize OPDS queries
* Update Manga API to download chapters cbz using only chapterId and improve chapter download query
* Optimize OPDS queries
* Use SourceDataClass to map sources and optimize thumbnail URL retrieval
* Kotlin lint errors in ChapterDownloadHelper and Opds
* Kotlin lint errors in ChapterDownloadHelper and Opds
* Customize JRE
* Fix build push
* Run test
* Where is jre
* Try this
* Fix debain-all and linux-assets
* Stop ref-master for test
* Revert "Stop ref-master for test"
This reverts commit 8e34a12247087eff643676ef0ac692df4c2700ff.
* Revert "Run test"
This reverts commit dad629aaff2cf5c270b7fffeb98dfb9e3d1c93e5.
It's possible that a manga is bound to a tracker while there is no search result.
This happens when e.g. restoring a backup which includes track bindings for which there was never a tracker search.
In that case when trying to e.g. copy the binding to another manga, the mutation would fail due to not finding a search result.
These cases can be handled by additionally checking the TrackRecordTable to get the necessary track info.
* Update to exposed-migrations v3.5.0
* Update to kotlin-logging v7.0.0
* Update to exposed v0.46.0
* Update to exposed v0.47.0
* Update to exposed v0.55.0
* Update to exposed v0.56.0
* Update to exposed v0.57.0
* Update graphqlkotlin to v8
* Go back to JsonMapper
* Add context to data loaders
* Compile fixes
---------
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Syer10 <syer10@users.noreply.github.com>
* Properly set download update type on exceptions
* Always send FINISHED download update to client for deprecated subscription
By the time the status was sent to the client, the finished download item was already removed from the queue, causing the client to never get the latest status, thus, having an outdated cache
Regression introduced with 168b76cb0c
* Validate setting values on mutation
* Handle invalid negative setting values
* Ensure at least one source is downloading at all times
* Prevent possible IllegalArgumentException
The "serverConfig.maxSourcesInParallel" value could have changed after the if-condition
* Emit only download changes instead of full status
The download subscription emitted the full download status, which, depending on how big the queue was, took forever because the graphql subscription does not support data loader batching, causing it to run into the n+1 problem
* Rename "DownloadManager#status" to "DownloadManager#updates"
* Add initial queue to download subscription type
Adds the current queue at the time of sending the initial message.
This field is null for all following messages after the initial one
* Optionally limit and omit download updates
To prevent the n+1 dataloader issue, the max number of updates included in the download subscription can be limited.
This way, the problem will be circumvented and instead, the latest download status should be (re-)fetched via the download status query, which does not run into this problem.
* Formatting
* Update graphqlkotlin to v6.8.5
* Replace Jackson with Kotlinx.Serialization where possible
---------
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Syer10 <syer10@users.noreply.github.com>
* Keep up to 31 log files
On average one log file per day gets created, thus, increasing to 31 files will store log files for one month
* Decrease total log files size to 100mb
* Make log appender settings configurable
* feat(comicinfo): add date fields to comic info
This will be parsed by Komga, Kavita etc ... and any other library management to also have the date of the chapter.
* refactor: improve code readability
Co-authored-by: Mitchell Syer <Syer10@users.noreply.github.com>
---------
Co-authored-by: Mitchell Syer <Syer10@users.noreply.github.com>
This PR:
https://github.com/FlareSolverr/FlareSolverr/pull/1300
Solve a lot of issue with not solving challenge, however, the cookie don't have path, httpOnly, secure and sameSite.
By making them optional that should work for both version of flaresolverr.
* Launch missed auto backup task in background
* Launch missed auto global update task in background
* Launch missed auto webui update check task in background
In case a manga gets added to the library which has not been initialized yet, it should be tried to initialize it.
Since it's not an error to have uninitialized manga in the library, this can be done in the background via the updater and the client receives the updated data via the update subscription.
They were only initialized in case the setting to refresh manga metadata during an update was enabled.
However, this should always be done for uninitialized manga, regardless of the setting.
06bfc33e72 prevents uninitialized manga from getting filtered out, however, it did not ensure to initialize the manga
* Properly check for first page in cbz files
The download check for cbz files only checked if the archive existed but didn't check for the first page
* Streamline getImageImpl of ChapterDownloadProviders
* Exclude comic info file from page list
In case the download folder did not contain any page files, only the comic info file existed, which caused the download check to incorrectly detect the first page
* Add logging to ChapterForDownload#asDownloadReady
* Move JUI and Sorayomi to inactive clients
* Update client descriptions
* Remove outdated mihon sync info
* Update feature list
* Move Docker installation info to top of list
* Move feature list higher in readme
* Rename feature list section to "Features"
* Separate inactive/abonded clients
Manga can be added to the library while they have not been initialized yet.
In this case, depending on the manga exclusion setting, they will never be updated automatically unless they get refreshed once manually.
* Persist page count during chapter list update
In case a downloaded chapter gets deleted during a chapter list update, the download status was tried to be preserved.
However, in case the status could be preserved, the page count was lost and thus, the chapter now was marked as downloaded with a page count of -1.
* Mark downloaded chapters without page count as not downloaded
* Prevent adding duplicated chapters into the db
it's possible that the source returns a list containing chapters with the same url
once such duplicated chapters have been added, they aren't being removed anymore as long as there is
a chapter with the same url in the fetched chapter list, even if the duplicated chapter itself
does not exist anymore on the source
* Drop duplicated chapters from database table
* Add unique constraint to chapter table
This is to completely prevent duplicated chapters from being added to the database.
Since once a duplicated chapter has been added to the database, it does not get removed anymore as long as a chapter with the same url is included in the requested source chapter list
The automated backup cleanup just deleted every file (recursively in subfolders as well) in the set folder in case it was older than the set backup ttl.
This made it impossible to save the automated backups into a folder with different files.
* Remove code duplication
* Remove unnecessary functions
* Simplify filtering for multiple values in queries
Makes it easier to filter for multiple values at ones without having to nest filters with multiple "and".
e.g.
```gql
query MyQuery {
mangas(
filter: {genre: {includesInsensitive: "action"}, and: {genre: {includesInsensitive: "adventure"}, and: { ... }}}
) {
nodes {
id
}
}
}
```
can be simplified to
```gql
query MyQuery {
mangas(
filter: {genre: {includesInsensitive: ["action", "adventure", ...]}}
) {
nodes {
id
}
}
}
```
* Add filter for matching "any" value in list
Makes it easier to filter for entries that match any value without having to nest filters with multiple "or".
e.g.
```gql
query MyQuery {
mangas(
filter: {genre: {includesInsensitiveAny: ["action", "adventure", ...]}}
) {
nodes {
id
}
}
}
```
instead of
```gql
query MyQuery {
mangas(
filter: {genre: {includesInsensitive: "action", or: {genre: includesInsensitive: "adventure", or: {...}}}}
) {
nodes {
id
}
}
}
```
* Add util function to apply "andWhere/All/Any"
* Compare webUI version with bundled webUI version
The bundled webUI version was incorrectly compared with the minimum server version.
This worked until the latest release, because the bundled webUI version had a lower revision number than the server revision, however, with the latest release, it is now higher, resulting in no compatible webUI version to be found
* Consider bundled webUI version only for default flavor
* Add "isDefault" util function to WebUIFlavor
Browsing a source loads only a minimal representation of a manga which does not include some metadata.
This metadata is only loaded when the specific manga gets fetched.
Thus, when the extra metadata of a manga was already loaded, it got removed when browsing the source and a page response included this manga
In case e.g. a mutation was made which looked like this
myMutation {
mutationA { ... }
mutationB { ... }
mutationC { ... }
}
and mutation A and B succeeded while mutation C failed, the response only included the error of C and the successful mutation data response of A and B was missing
* Refresh track record only when logged in
In case one tracker was logged out, the refresh failed with an unauthenticated error and caused the other trackers to not get updated
* Prevent chapter track update from failing due to failure of other tracker
* Change level of log to "info"
* Properly prevent importing unsupported trackers from backup
Missed the early return in case no tracker record exists in the database in 2f362abb91be875e943b1364eb86d70a4144dd6f...
* Remove incorrect non null assertion
Prevented unbinding track records of unsupported trackers
* Prevent importing unsupported tracker from backup
This will lead to graphql field validation errors (non null declared field is null) once the track records get used, since they will point to trackers that do not exist
* Delete track records of unsupporter trackers
* Always return all track records of manga
Was already partially changed in 7df5f1c4c4 but this occurrence was missed
* Include tracking in validation of backup
* Always return track records
Not clear why an empty list should be returned in case no trackers are logged in
* Include tracking in backup creation
* Restore tracking from backup
In case the new chapters include duplicates from different scanlators, they would be included in the limit causing the auto download to potentially only download duplicated chapters while there might be more non duplicated chapters to download.
Instead, the limit should only consider unique chapters and then should include all duplicates of the chapters that should get downloaded
* Remove overrides of "ChapterFilesProvider::downloadImpl"
* Check final download folder for existing page on download
Downloads were changed to get downloaded to the system temp folder instead to directly into the final download folder.
This broke the check for existing pages, because now only the temp folder was checked instead of both the temp and the final download folder.
Regression introduced with 1c9a139006
* Properly check for already existing downloaded pages
The previous check was always false because the file ending of the page file is unknown and thus, missing from the created file path
* Cleanup cache download folder
* Update test/server-reference file
* Properly handle re-uploaded chapters in auto download of new chapters
In case of unhandable re-uploaded chapters (different chapter numbers) they potentially would have prevented auto downloads due being considered as unread.
Additionally, they would not have been considered to get downloaded due to not having a higher chapter number than the previous latest existing chapter before the chapter list fetch.
* Add option to ignore re-uploads for auto downloads
* Extract check for manga category download inclusion
* Extract logic to get new chapter ids to download
* Simplify manga category download inclusion check
In case the DEFAULT category does not exist, someone messed with the database and it is basically corrupted
* Add mutation to fetch the latest track data from the tracker
* Update Track.kt
---------
Co-authored-by: Mitchell Syer <Syer10@users.noreply.github.com>
* Extract unbinding track into function
* Introduce new unbind mutation
* Add option to delete track binding on track service
---------
Co-authored-by: Mitchell Syer <Syer10@users.noreply.github.com>
Triggering the progress update on server side does not work because the client needs to get the mutation result, otherwise, the clients cache will get outdated
* Update lastReadChapter on bind in case it's greater than remote
* Update lastReadChapter on chapter read in case it's greater than remote
* [Logging] Improve logs
* Extract thumbnail url fresh into function
* Remove incorrect non-null assertion
According to the typing there is no guarantee that fetching a manga from the source provides a thumbnail url
* Refresh manga thumbnail url on 404 error
* Refresh manga thumbnail url on unreachable origin cloudflare errors
* Set updater running flag to false only at the end of the update
For clearing the data loader cache properly, the update status subscription requires the update to be running.
For the last completed manga update the flag was immediately set to false which prevented the dataloader cache from getting cleared, returning outdated data for the last updated manga
* Correctly clear the "MangaForIdsDataLoader" cache
The cache keys for this dataloader are lists of manga ids.
Thus, it is not possible to clear only the cached data of the provided manga id and instead each cache entry that includes the manga id has to be cleared
* Ensure that manga dataloader caches gets cleared during global update
The "StateFlow" drops value updates in case the collector is too slow, which was the case for the "UpdateSubscription".
This caused the dataloader cache to not get properly cleared because the running state of the update was already set to false.
* Log "Browser::openInBrowser" errors
The error was never written to the log file.
It was only visible in the console
* Remove "printStackTrace" usage with logs
The local manga thumbnail got "downloaded" to thumbnail download folder of in library manga.
Since the "thumbnail url" of a local source manga never changes, the "downloaded" manga thumbnail never got updated
Regression introduced with f2dd67d87f
* Remove download ahead logic
Unnecessary on server side, should just be done by the client
* Rename "autoDownloadAheadLimit" to "autoDownloadNewChaptersLimit"
* Deprecate the old field
* Update Stable WebUI
* Update Stable WebUI
---------
Co-authored-by: Syer10 <syer10@users.noreply.github.com>
* Run functions for specific webui flavor
* Set default flavor of WebUIFlavor enum
* Consider flavor of served webUI when checking for update
In case the flavor was changed and the served webui files are still for the previous flavor, the update check could incorrectly detect no update
* Skip validation during initial setup
In case initial setup is triggered because of an invalid local webUI, doing a validation again is unnecessary
* Handle changed flavor on startup
In case a socket got disconnected, the session state of the subscriptions did not get correctly cleaned up.
The active operations did get closed but not removed and thus, when the client tried to reconnect, the server incorrectly detected an active subscription for an operation and immediately terminated the subscription.
In case there is no internet connection, it is not possible to verify the webUI files, leading to the server to fail from starting up.
Instead, the existing webUI should just be used
* Remove log of mangas to update
This logged the full manga data objects in the list with information that is not needed (e.g. description of a manga).
Once a manga gets updated via the updater, it gets logged, which should be enough
* Include manga id in updater log
* Use "toString" to log mangas
* Change "HttpLoggingInterceptor" level to "BASIC"
Was unintentionally merged with d658e07583
If called in quick succession it is possible that duplicated extensions get inserted to the database, because it has not yet been updated by the first call
* Rename IncludeInUpdate class to IncludeOrExclude
Signed-off-by: Chance Zibolski <chance.zibolski@gmail.com>
* Add support for configuring which categories are downloaded automatically
If a manga has no configured categories, behavior remains the same and
the automatic download functionality will download new chapters without
consulting the category includeInDownload configuration.
Signed-off-by: Chance Zibolski <chance.zibolski@gmail.com>
---------
Signed-off-by: Chance Zibolski <chance.zibolski@gmail.com>
* Prevent adding duplicated extensions to the db table
There is a possibility that multiple extension repos have been added which contain the same extensions.
In case these extensions have not been added to the db table yet, they would all get added to the db, which would create duplicated extensions
* Use the extension with the latest version from all repos
In case multiple repos have the same extension, use the extension with the latest version
* add trackers support
* Cleanup Tracker Code
* Add GraphQL support for Tracking
* Fix lint and deprecation errors
* remove password from logs
* Fixes after merge
* Disable tracking for now
* More disabled
---------
Co-authored-by: Syer10 <syer10@users.noreply.github.com>
Subtracting 1 from the first chapter to download index caused an additional chapter to get downloaded (e.g. limit 4 would download 5 chapters)
Regression was introduced with 05bf4f5525
* Return latest data for finished downloads
In case a download has finished, the cache of the data loader has to be cleared to be able to get the latest data, otherwise, the returned chapter will still be marked as not downloaded
* Correctly clear manga data loader caches
For finished downloads the immediate emission did not work because the emission was done async and by the time the state got updated with the new status, the finished download was already removed from the queue.
Thus, the new state was missing the finished download.
* Remove "updateAvailable" from webui update info
Doesn't add anything
* Extract status creation into function
* Optionally emit status immediately
Otherwise, some emissions can get lost due to the 1s sample period
* Rename "STOPPED" state to "IDLE"
* Reset webui update status
Currently, the update status never gets reset.
Thus, it will be "FINISHED" or "ERROR" until the next update gets triggered.
Due to this, the client won't know that the update result was already handled and will handle it again the next time it gets the update status.
To prevent this, the client has to be able to tell the server that it has handled the update result and that it can be resetted
Due to not immediately sending the status, the finished chapters were already removed from the queue by the time the status was actually send to the client.
This caused the client to never receive a status with the chapters downloaded flag to be true, resulting in the client to not know that a chapter is downloaded
* Use a new type for the webui about info query
Using the same type for this and the webui update queries/mutations caused apollo to save it as the same data in the cache, overwriting the "about info"
* Use a new type for the webui about check query
To prevent similar issues (cc3bf5f34a8afebadd306d037db1a10088ef9334) with the "update check" and the "update progress" payloads
* Throw update check error when calling it via the query
Otherwise, the error is never raised to the frontend
* Set "ERROR" state in case the update check failed on WebUI update trigger
The served file gets cached and thus, it won't reflect the latest version of the file.
This was a problem after the webUI got updated, since now the served "index.html" was outdated and pointed to files that didn't exist anymore.
When adding commits or switching between branches the "shadowJar" gradle task always used the same (outdated) commit count which created jars with confusing names
* Trigger initial auto backup in case server was not running
In case the server was not started (stopped, system shutdown - not in hibernation) during the scheduled auto backup time, the auto backup never got triggered.
* Update server util preferences
* Fix automatic chapter download for initial chapter list fetch
The initial fetch wasn't correctly detected which caused chapters to get downloaded.
Using index based numbers also caused the first chapter to not get downloaded due to it being omitted in the "subList" call which excludes the "toIndex".
* [Logging] Update logs
In case a chapter is marked as not downloaded, but the download folder exists already, the chapter did not get downloaded again.
This could cause issues in case the previous download failed or has missing pages.
Instead of only checking if the folder exists, each page should be checked individually
This was previously done and was incorrectly changed with 1c9a139006.
* Chapter fetch improvements
* Update previous date uploads
* Lint
* Fix backup inserts
* Remove extra maxSeenUploadDate
* Port downloaded over
* Make sure to set isDownloaded on all inserts
The function incorrectly exited early in case no latest read chapter was found.
This rendered disabling the setting "excludeEntryWithUnreadChapters" useless.
* Keep initial fetch date of existing chapters on a list fetch
The fetch at date should not get updated for existing chapters.
Updating this field makes it impossible to detect which chapters were actually newly fetched.
To get the last fetched timestamp of the chapters, the "chaptersLastFetchedAt" field of the manga should be used
got changed in 6d33d72663
* Get real chapter url safely
In case this causes an exception, it should not cause the whole list fetch to fail
was removed in 6d33d72663
Currently, the server tries to migrate the preference on every startup, even if the migration was already done.
This can lead to an unhandled exception, if the write permission to the system preference was revoked.
In case the migration has already happened, these permissions should not be required
* Reset backup status to idle in case of an exception
* Rename "performRestore" function
* Set backup status to failure on exception
Makes it possible to detect if the restore failed or not after the first status was received
* Set backup status to success on completion
Since the status is not provided over a subscription, but over a query that should be pulled, it is not really easily detectable if a restore finished or not, since both states will be indicated by "idle"
* Correctly wait for first new status when triggering backup import
The status is only "Idle" in case no backup import has ever run.
Once the first backup process finished it is either "Failure" or "Success"
* Rename "ProtoBackupImport::restore" function
* Add id to restore process
Makes it possible to differentiate between backup restore processes.
We do not allow any category to have the default categories name ("default" case-insensitive).
In case the backup includes a category with this name, it won't be matched to any category in our database and also won't insert a new category.
This will then lead to an exception, causing the backup to fail.
* Move running check to update function
* Move updating update status to process function
* Fail all source updates in case of update channel failure
In case the channel failed due to an exception, the update for the source failed completely.
This however was never handled and the pending updates for the source were never set to failed.
Due to this, the global updates running state was always true
* Remove completed update channel from available channels
* Always log specific update job failure
* Optionally fetch mangas during the update
The update only fetched the chapter list of a manga but never the manga itself.
Thus, e.g. unless the manga got online fetched via the ui, it would never get recognized if it is completed or not.
This would e.g. prevent the update setting, to not update completed mangas, from working as intended
* Make settings required
Mangas are not supposed to be mapped to the default category in the database.
In case this happens, the category query won't be able to correctly select mangas in the default category
In case the database got deleted without deleting cached/downloaded thumbnails, the next time a manga gets inserted, it's possible that a thumbnail was already downloaded for its id.
This then causes mangas to be displayed with incorrect thumbnails due to using the outdated cached/downloaded thumbnails
In case download ahead is disabled, all new chapters should get downloaded.
Due to incorrectly calculating the index of the first new chapter to download, no new chapter was downloaded at all
In case a manga was already loaded via the data loader, the cached data will get used.
Due to this, the update status did not return the updated manga data, but instead, stale data
* Set default log level to INFO
Default log level was accidentally changed to ERROR for the base logger in 56deea9fb3
* Reduce graphql log level to WARN
Otherwise, thrown exceptions are swallowed by graphql and never logged besides a very brief error in the graphql response
* Address build warnings and cleanup
* Actual name of who defined the protocol
* Remove uneeded detekt supression
* GraphQL Before-After cleanup
* Lint
* Cleanup unused functions
* Fix some discrepancies with the 1.5 source api and fix lang exception
* Filter mangas based on each genre of the genre condition
Genres are stored as a comma separated string in the database.
Thus, unless the correct string was passed in the condition, no manga would match the condition.
* Query mangas based on genre filter
* Correctly check for none PREVIEW channel latest compatible version
The only working channel was the PREVIEW channel, since any other channel would have fetched the actual version of the preview and used this as the potential latest compatible version.
This was caused due to incorrectly checking if the preview version should be ignored.
* Remove PREVIEW version constant
* Consider versions of different channels
In case the current server version isn't compatible with the latest version of the selected webUI channel, versions of other channel should be considered depending on the selected channel.
E.g. PREVIEW is the latest available version and thus, any version of another channel is also compatible with the PREVIEW channel
* Restrict min compatible version to the bundled version
The oldest compatible version for a server is the bundled version, thus, any version that is older than the bundled one should not be considered compatible
* Switch to new Ktlint plugin
* Add ktlintCheck to PR builds
* Run formatter
* Put ktlint version in libs toml
* Fix lint
* Use Zip4Java from libs.toml
* Add "download ahead" mutation
Checks if the specified number of unread chapters, that should be downloaded, are available.
In case not enough chapters are downloaded, the number of missing unread chapters will get downloaded
* Optionally pass the latest read chapter id of a manga
In case a chapter will get marked as read, which also triggered the download ahead call, it's possible, that by the time the download ahead logic gets triggered, the chapter hasn't been marked as read yet.
This could then cause this chapter to be included in the chapters to get downloaded.
By providing the chapter id, this chapter will be used as the latest read chapter instead, and thus, not be included inn the chapters to download.
In case a newer version of the extension is installed and the extension gets manually downgraded, the version in db is still the one of the newer version.
This will prevent detection of available updates, since it won't get recognized, that an older version is currently installed.
Chapters were added to the queue by database index order.
In case a chapters of different mangas got added to the queue, downloads got mingled instead of being group inserted per manga.
Also sort manga chapters by source order, to make sure, that, in case chapters of a manga are, for some reason, not in the correct order in the database, they will still get downloaded in the order of the source.
When using cursors for pagination while sorting, the sort order was inverted (desc -> asc, asc -> desc).
However, this was then not considered when selecting results based on the cursor.
For before/after results where always selected via greater/less.
Due to inverting the sort order, this also needs to be inverted depending on the sort order (desc or asc).
Since the number of chapters gets converted to be index based, 1 available chapter would result in 0.
Due to this, in case a manga had exactly one chapter before updating the chapters, it was incorrectly detected as the initial fetch and the new chapters did not get automatically downloaded.
Flow::stateIn has "Strong equality-based conflation" (see documentation).
Thus, it omits every value in case it's equal to the previous one.
Since the DownloadManger::getStatus function returns a status with a queue, that contains all current "DownloadChapters" by reference, the equality check was always true.
Thus, progress changes of downloads were never sent to subscribers.
Subscriber were only notified about finished downloads (size of queue changed) or downloader status changes
In case a download was finished, but the downloader got stopped before it was able to remove the finished download from the queue, the downloader got stuck in an endless loop of starting and pausing downloads.
This was caused by selecting the next chapter to download and then recognizing in "Downloader::step", that there is another chapter to download before the current one in the queue.
However, since this recognized chapter is already downloaded, the downloader selected the next queued chapter again.
It was then stuck in this loop until the finished chapter was manually removed from the queue.
* Rename "newChapters" to "updatedChapterList"
* Do not auto download new chapters of entries with unread chapters
Makes it possible to prevent unnecessary chapter downloads in case the entry hasn't yet been caught up
* Optionally limit auto new chapter downloads
* Prevent downloading new chapters for mangas not in the library
In case the user config file has to be updated, the file needs to get reset.
While doing the reset, the already loaded internal state of the config got also reset, but was never updated again.
Due to this, the internal state of the config was the default config reference until the next server startup
Regression introduced with a31446557d.
The function always returned the PREVIEW version as the latest compatible version.
This was caused by incorrectly selecting the version from the json object, which resulted in the version to be wrapped in '"'.
* Create manga download dir in case it's missing for cbz downloads
The directory, in which the cbz file should have been saved in, was never created.
* Correctly copy chapter download to final download location
"renameTo" does not include the content of a directory.
Thus, it just created an empty chapter folder int the final download directory
These are information that are necessary for nearly all manga requests.
They could be selected via the categories mutation, but this only works for a single manga.
It is not possible to select this information for lists of mangas without having to request all chapters for every manga in the list.
* Set graphql logs to error level
Set log level for loggers with names
- ExecutionStrategy (spams logs with "... completing field ...")
- notprivacysafe (logs every received request up to 4 times (received, parse, validate, execute))
* Extract logic to get logger for name into function
* Add function to set log level for a logger
* Add settings to enable graphql debug logging
* Move chapter download logic to base class
* Do not reuse "FolderProvider" in "ArchiveProviders" download function
Due to reusing the "FolderProvider" to download a chapter as a cbz file, a normal chapter download folder was created.
In case the download was aborted before the cbz file got created and the folder deleted, the next time the chapter got downloaded, the wrong "FileProvider" was selected, causing the chapter not to get downloaded as a cbz file.
In case e.g. no manga exists for the passed id, the query returned null.
This makes it harder to have a "streamlined" error handling in the client, since these types of queries need a special handling.
* Update chapter page refresh logic with logic from "ChapterMutation"
* Rename function to "getChapterDownloadReadyByIndex"
* Update "ChapterForDownload" to work with only "chapterId" being passed
* Return database chapter page list in case chapter is downloaded
In case the chapter is downloaded, fetching the chapter pages info should not be needed.
It should also currently break reading downloaded chapters while being offline, since the page request will always fail, since there is no internet connection
* Provide last global update timestamp
* Provide skipped mangas in update status
* Extract update status logic into function
* Rename update "statusMap" to "mangaStatusMap"
* Provide info about categories in update status
* Add "uiName" to WebUI enum
* Add "Custom" WebUI to enum
* Rename "WebUI" enum to "WebUIFlavor"
* Add "WebUIInterface" enum
* Add query for server settings
* Add mutation for server settings
* Add mutation to reset the server settings
* Only update the config in case the value changed
In case the value of the config is already the same as the new value of the state flow, it is not necessary to update the config file
* Make server config value changes subscribable
* Make server config value changes subscribable - Update usage
* Add util functions to listen to server config value changes
* Listen to server config value changes - Auto backups
* Listen to server config value changes - Auto global update
* Listen to server config value changes - WebUI auto updates
* Listen to server config value changes - Javalin update ip and port
* Listen to server config value changes - Update socks proxy
* Listen to server config value changes - Update debug log level
* Listen to server config value changes - Update system tray icon
* Update config values one at a time
In case settings are changed in quick succession it's possible that each setting update reverts the change of the previous changed setting because the internal config hasn't been updated yet.
E.g.
1. settingA changed
2. settingB changed
3. settingA updates config file
4. settingB updates config file (internal config hasn't been updated yet with change from settingA)
5. settingA updates internal config (settingA updated)
6. settingB updates internal config (settingB updated, settingA outdated)
now settingA is unchanged because settingB reverted its change while updating the config with its new value
* Always add log interceptor to OkHttpClient
In case debug logs are disabled then the KotlinLogging log level will be set to level > debug and thus, these logs won't get logged
* Rename "maxParallelUpdateRequests" to "maxSourcesInParallel"
* Use server setting "maxSourcesInParallel" for downloads
* Listen to server config value changes - downloads
* Always use latest server settings - Browser
* Always use latest server settings - folders
* [Test] Fix type error
Gets already called by "Chapter::fetchChapterList", thus, this is unnecessary.
Additionally, "chapters.toList()" and "chapters.map()" have to be called in a transaction block, which they are not, and thus, cause an unhandled exception, breaking the mutation
There were cases where the last page read was greater than the max page count of a chapter.
This is not possible and is just invalid data, that is saved in the database, possible leading to other errors down the line.
This could happen in case the chapter was loaded at some point with e.g. 18 pages and after some time got fetched again from the source, now with fewer pages than before e.g. 15.
If the chapters last page was already read by that time, the last read page would have been 18, while the chapter now has only 15 pages.
* Rename "DownloadedFilesProvider" to "ChaptersFilesProvider"
* Move files into sub packages
* Further abstract "DownloadedFilesProvider"
* Rename "getCachedImageResponse" to "getImageResponse"
* Extract getting cached image response into new function
* Decouple thumbnail cache and download
* Download and delete permanent thumbnails
When adding/removing manga from/to the library make sure the permanent thumbnail files will get handled properly
* Move thumbnail cache to actual temp folder
* Rename "mangaDownloadsRoot" to "downloadRoot"
* Move manga downloads into "mangas" subfolder
* Clear downloaded thumbnail
* Add "server" to "checkForUpdate" logic names
* Use "webUIRoot" as default path for "getLocalVersion"
* Use local version as default version for "isUpdateAvailable"
* Return the version with the webUI update check
* Update WebinterfaceManager to be async
* Add query, mutation and subscription for webUI update
* Catch error and return default error value for missing local WebUI version
* Catch error when updating to bundled webUI
In case the bundled webUI is missing, the webUI setup threw an error and made the server startup fail.
Since a local webUI exists the error should be ignored, since it's only a try to update to a newer webUI version.
* Extract logic to setup bundled webUI version
* Update to bundled webUI try to download missing bundled webUI
* Get rid of multiple static "assets/" usage
* Correctly add new zip entry
The name of the entry has to be a "/" separated path, otherwise, the files can't be found.
* Extract reorder logic into function
* Save download queue everytime a download was finished
The download queue was never saved after a download was finished.
This caused finished download to be restored on a server start, which caused unnecessary "downloads" which most of the time would just finish immediately since the pages were still in the cache
* Wait for download queue save process to be finished
Since multiple downloaders could be finished at the same time, the download queue should be saved synchronously
* Remove unnecessary download queue save trigger
This gets called everytime a downloader finished downloading all chapters of its source.
Since the queue is now saved everytime a download is finished, this is trigger is not needed anymore
* Log extension load failure
In case the extension couldn't be loaded the error was never logged, making it impossible to analyse what was going on
* Log exception in "GetCatalogueSource:: getCatalogueSourceOrNull"
In case "GetCatalogueSource::getCatalogueSource" threw an error, this was never logged here
In case the file could not be retrieved, the page retrieve just failed and wasn't triggered again.
In case of the downloader, the chapter download just kept failing 3 times and was aborted
* Use the Launcher
* Test launcher
* a
* Revert "a"
This reverts commit eb8667e4397c20dae7a7dfdf26058f5aff76fff8.
* Move launcher
* Test launcher 2
* Update dex2jar
* Fixes
* Use regular java with deb install
* Improve linux installs
* Revert "Test launcher 2"
This reverts commit 265825808fd82616223e4a919718ea87a7eeff43.
* Revert "Test launcher"
This reverts commit 7ff83c7ab954bcab6c0b039701041b639a489382.
* Rename functions
* Require version to be passed to "downloadVersion"
Makes it possible to download different versions than the latest compatible one with retry functionality
* Fallback to downloading bundled webUI in case it's missing
In case no download was possible and the fallback to the bundled version also failed due to it not existing, try to download the version of the bundled version as a last resort.
* Handle exception of "getLatestCompatibleVersion"
* Move validation of download to actual download function
* Extract retry logic into function
* Retry every fetch up to 3 times
* Log full exception and change log level
In case on the startup no webUI update was available but the bundled version of the server is newer than the current used version, then the bundled version should be used.
This could be the case in case a new server version was installed and no compatible webUI version is available
* Return actual version for "PREVIEW" in "getLatestCompatibleVersion"
In case "PREVIEW" is the latest available version, the function should immediately fetch the actual webUI version that is currently the latest released version.
Thus, the function always returns a valid version and the preview version has not to be considered anymore at other places in the code
* Ignore download failure in case local webUI version is valid
In case the download failed e.g. due to internet connection issues, the server should only fall back to another version in case the local version is invalid or missing
* Change log level of download error
* Change type of sourceId in Downloader
Unclear why it was converted to Long since it just got converted back to String anyway when it was used in the Downloader
* Only stop downloads from source of the Downloader
The downloader just changed the state of all downloads, ignoring if they are from the source the Downloader is for or not
* Remove unnecessary DownloadManager::start calls
In case chapters were added to the queue the DownloadManager will start itself
* Extract download filtering into property
* Improve Downloader logging
* Notify clients only in case Downloader was started
In case nothing was done there is nothing to notify about
* Do not start Downloaders for failed downloads
In case there were failed chapter downloads in the queue the DownloadManager still created a Downloader and started it.
This Downloader would than immediately call "onComplete", since there is no available download, which then would refresh the Downloaders again which created an infinite loop until the failed download got removed from the queue
* Retry download in case it failed it gets re-added to the queue
In case a failed downloaded that was still in the queue was tried to get added to the queue again, nothing happened.
Instead of doing nothing, the download should get retried.
Thus, it also provides the logic to easily retry a failed download by just "adding" the chapter to the queue again.
Currently, to retry a failed download, the download has to be removed from the queue and then get re-added.
* Rename function "unqueue" to "dequeue"
* Move "dequeue" function
* Extract dequeue logic into function
* Improve DownloadManager logging
* Override "toString" of DownloadChapter
See documentation (%/rem, mod) for differences.
Example for "issue" that occurred:
mathematical: -4 % 6 = 2 (expected)
kotlin: -4 % 6 = -4 (unexpected)
* Trigger missed auto global update immediately on server start
In case the last execution was missed, it was never immediately scheduled.
Thus, it had to be waited for the next scheduled execution to be executed.
* Schedule auto global updates at a later point during the startup
In case a global update was triggered immediately, the server setup wasn't far enough causing an error due to trying to use things (e.g. database) that weren't initialized yet
* Correctly set the "firstExecutionTime" of a "HATask"
In case an initial delay is used for "Timer::scheduleAtFixedRate" (e.g. when rescheduling) then the "firstExecutionTime" of the "HATask" was incorrect, since it considered the first execution to be based on the actual interval.
This caused
- calculations for execution times (e.g. "timeToNextExecution", "nextExecutionTime") to be incorrect
- the ordering of the "scheduledTasks" queue to be incorrect
* Add logging
* Do not modify queue during forEach loop
Caused a "ConcurrentModificationException" and broke the system suspension detection due to the unhandled exception canceling the task
* Log all uncaught exceptions
In case an exception is uncaught/unhandled, it only gets logged in the console, but is not included in the log file.
E.g. the "HAScheduler::scheduleHibernateCheckerTask" task caused an unhandled "ConcurrentModificationException" which caused the task to get dropped.
In the log files this error could not be seen and thus, analysing the issue of the suspension detection to stop working was not possible via the logs
* Schedule "HATask" immediately when its last execution was missed
The missed execution was never triggered
* Calculate the "HATask" "last execution time" correctly
When scheduling a task for the first time, the "first execution time" is in the future.
This time is used for by all functions calculating times for this task (e.g. next/last execution time).
In case the first execution didn't happen yet and the current time, would have been an "execution time" based on the interval, the "hibernation detection" would trigger for this task, since it would think that the last execution was missed, due to the "last execution" being in the future.
To prevent this, it has to be made sure, that the "last execution time" is in the past.
* Check correctly if task threshold was met
It was incorrectly considered to be met in case the remaining time till the next execution was less than the threshold.
Instead, it has to be greater, since that would mean, that the next execution is taking long enough to not be triggering a double execution
Thus, the current logic is not, as intended, preventing possible double executions and instead is making sure to only execute missed tasks in case it will lead to double executions...
* Always trigger missed executions
The idea to have a threshold to prevent double executions in case the next scheduled execution isn't too far in the future doesn't really work with big intervals (e.g. in the days range).
For such cases, multiple days left for the next executions could be considered to cause double executions.
Decreasing the threshold doesn't really work since then it wouldn't really work for low intervals.
Instead, it makes more sense to just allow possible double executions and to just live with it.
In case it would be a problem for a specific task, the task should handle this issue itself.
* Rename schedule functions
* Introduce Base task for "HATask"
* Support kotlin Timer repeated interval in HAScheduler
It's not possible to schedule a task via cron expression to run every x hours in case the set hours are greater than 23.
To be able to do this and still keep the functionality provided by the "HAScheduler" it has to also support repeated tasks scheduled via the default Timer
* Support global update interval greater 23 hours
* Use "globalUpdateInterval" to disable auto updates
Gets rid of an unnecessary setting
* Setup "logback" to write to file
To be able to dynamically set the log file save location, logback has to be setup via code instead of a config file
* Log OkHttp via logback
Otherwise, the logs would only get written to the console and thus, not be included in the log file
* Init logback
Has to be done after the config was loaded, otherwise, the root directory would be unknown.
Moved the log of the loaded config to the "applicationSetup" since otherwise, the log would not be included in the log file
The actual version of the preview was never loaded and compared to the local version.
Instead, for the preview channel it was incorrectly decided that a new version is available on every update check
* Convert "WebInterfaceManager" to singleton
* Move server webUI mapping to the webUI
* Extract logic into functions
* Retry failed download
* Validate downloaded webUI
* Automatically check for webUI updates
* Add logic to support different webUIs
* Update logs
* Close ZipFile after extracting it
* Add option to disable cleanup of backups
* Ensure the minimum TTL of backups to 1 day
* Schedule the automated backup on a specific time of the day
* Introduce scheduler that takes system hibernation time into account
In case the system was hibernating/suspended scheduled task that should have been executed during that time would not get triggered and thus, miss an execution.
To prevent this, this new scheduler periodically checks if the system was suspended and in case it was, triggers any task that missed its last execution
* Use new scheduler
Some extension require some assets to work properly.
Currently, the extracted jar file does not contain these assets, thus, these extensions wouldn't work
The server reference config file was only able to be read while in dev mode.
Using the build jar, the content of the file was empty, since in the build jar resources aren't actual files anymore, instead they are streams.
This caused the user config content to be replaced with an empty string.
Currently, the "UserConfig" was created in case it was missing.
But in case settings changed (added/removed), an already existing "UserConfig" never reflected these changes and thus, was out of date
* Exclude "default" category from reordering
Due to the "default" category having been added to the database, the index based approach to reorder the categories didn't work anymore.
In case one tried to move a category to or from pos 1, the default category was selected due to being at index 0
* Normalize categories after reordering
Makes sure that the ordering is correct.
E.g. "default" category should always be at position 0
There is a possibility that a partially downloaded file remains in case of an error.
In that case, the next time the image gets requested the existing file would be handled as a successfully cached image.
* Improve default category handling and add cascade to references where possible
* Minor fix for default category
* Make the default category always first in the normalization
Makes it possible to only update specific categories.
In case a manga is in an excluded category it will be excluded even if it is also in an included category.
* Separate cache dir from download dir
* Move downloader logic outside of caching/image download logic
* remove unnecessary method duplication
* moved download logic inside download provider
* optimize and handle partial downloads
* made code review changes
* Support extensions lib 1.4
* Fix build
* Support UpdateStrategy
* Update extension lib min/max to match Tachiyomi
* Use HttpSource.getMangaUrl and add Chapter.realUrl
* Get Playwright working with ShadowJar
* Set system driver implementation
* Minor cleanup
* Fix run gradle task and re-add some removed code
* No need to get the FS if it already exists
* use java implementation
Co-authored-by: Aria Moradi <aria.moradi007@gmail.com>
* get default User Agent from WebView
* make sure to close browser
Co-authored-by: Mitchell Syer <Mitchellptbo@gmail.com>
Co-authored-by: Mitchell Syer <Mitchellptbo@gmail.com>
* WebView based cloudflare interceptor
ported https://github.com/vvanglro/cf-clearance to kotlin
* code clean up
* Forgot to commit these
* Get ResolveWithWebView working
1. Make sure to .use all closeable resources
2. Use 10 seconds instead of 1 second for waiting for cloudflare(this was the most probable issue)
3. Use Extension UA when possible
4. Minor cleanup of logging
* rewrite and refactor
Co-authored-by: Syer10 <syer10@users.noreply.github.com>
* Add immediate updates to download queue manager for updates that always needs to be delivered
* Update server/src/main/kotlin/suwayomi/tachidesk/manga/impl/download/DownloadManager.kt
Co-authored-by: Mitchell Syer <Mitchellptbo@gmail.com>
* Revert change to make sure that data in status sent to client are actual
* Reduce number of immediate updates to clients
Co-authored-by: Mitchell Syer <Mitchellptbo@gmail.com>
* Add new endpoint for batch editing any chapter
* Add option to batch editing chapters to delete chapter (remove downloaded content)
* Rename the endpoint to match single manga batch endpoint
* Do not return early, in case there are other changes
* PR changes
* Downloader rewrite
- Rewrite downloader to use coroutines instead of a thread
- Remove unused Page functions
- Add page progress
- Add ProgressResponseBody
- Add support for canceling a download in the middle of downloading
- Fix clear download queue
* Minor fix
* Minor improvements
- notifyAllClients now launches in another thread and only sends new data every second
- Better handling of download queue checker in step()
- Minor improvements and fixes
* Reorder downloads
* Download in parallel by source
* Remove TODO
* Add POST /downloads endpoint for creating multiple
* Fix review notes
* Add chapter id to API endpoints
* Rewrite batch chapter download to use chapter id instead of mangaId+chapterIndex combination
* Change EnqueueInput format to be more futureproof
* Change endpoint path
* Change endpoint path
* Add POST variant for `/{sourceId}/search` endpoint which handles body data as list of FilterChanges
* Revert changes to existing endpoint and create new route and change the interface
* Update doc
* Rename api endpoint
* Add lastFetchedAt and chaptersLastFetchedAt columns to manga
* Update lastFetchedAt columns when data are fetched from source
* Add age and chaptersAge fields to MangaDataClass
* Replace two migrations with single migration
* fix: handle and throw proper error if pageNum is zero for popular/latest api, fixes#75
* chore: replace if-else with kotlin require which throws IllegalArgumentException and add comment
* fix: remove comment as exception message is enough
* replace quickjs with jdk 8 default js engine
* replace quickjs with rhino engine and translate type for read comic online extension
* move quick js to AndroidCompat
* fix commicabc long type cast exception
* Improve DocumentationDsl, bugfix default values and add queryParams
Adding `queryParams<Int>("mangaId[]")` would allow something like this: `http://127.0.0.1:4567/api/v1/download/manga?mangaId[]=1&mangaId[]=2`
* Remove extra comma
* Make QueryParams not nullable and use default value if empty
* Allow nullable again
* Rename debian to deb
* Merge scripts into one
* Add error handler
* Disable wine installation to change electron icon due to error
* Replace debuild with dpkg-buildpackage
* Update workflows with new script
* Fix path
* Upgrade junrar version to 7.5.0 and set unrar.extractor.thread-keep-alive-seconds to 30 (default is 5)
* #338 Read whole archive in case RAR file is solid (it is, it can't be decompressed at an arbitrary location).
* Fix lintian errors
Fix lintian errors
Short description in debian/changelog to hide lintian changelog warnings
Use launcher scripts that run java and electron from /usr/bin
* Update changelog version
* Rename laucnher scripts. Put electron installaion guide in electron-launcher-standalone.sh
* Seperate debian packager codes from unix-bundler.sh
* chmod +x debian-packager.sh
* Fix mistakes
* Fix mistakes
* Add missing '!' to shebang
* Change faviconlogo.png to tachidesk.png
* Change faviconlogo.png to tachidesk.png
* Automate debian package building
Move wxs files to scripts/resources/msi/
Define icon's path inside script instead of hardcoding it in wxs
* Revert back Windows script improvments
* Remove copyright year. Use uppercase for first letter of foruzesh
* Seperate deb from tar code with defining new debian-x64 arch
* Add ./unix-bundler.sh debian-x64
* Fix mistake
* Remove unneeded change of license
* add support for MultiSelectListPreference
* Update AndroidCompat/src/main/java/xyz/nulldev/androidcompat/io/sharedprefs/JavaSharedPreferences.kt
Co-authored-by: Mitchell Syer <Mitchellptbo@gmail.com>
* don't convert to list
* fix by @Syer10
Co-authored-by: Mitchell Syer <Mitchellptbo@gmail.com>
* #224 Created view for unread and download badges
* #224 Basic test structure
* Created test and cleaned up a bit
* Move counts to MangaDataClass and delete MangaViewDataClass
* Readded trailing space
* Removed SQL view and calculate with joins now
* initial PreferenceScreen support, works with 'NeoXXX Scans' (pt-br)
* convert EditTextPreference to json successfully
* commit what I've got
* bring back the old SharedPreferences for CustomContext, implement Toast
* put back syer's implementation
* differentiate ContinuesHorizontalLTR and ContinuesHorizontalRTL
* fix displaying pages in horizontal viewer
* add scroll handler for horizontal mode
* update curPage when images pass through center of the screen
* add click events to navigate pages
* remove console.log
* fix click mapping for ContinuesHorizontalRTL
* remove disable eslint inline comment
* fix ContinuesHorizontalRTL not updating curPage on scroll
* add ability to click to drag
* add margin in between images
* Added some key mappings to navigate pages
* use keyboard event codes
* unused files removed
* use a reference to current page
* fix some bugs with Virtuoso
* add keymapping for space to navigate to next page
* commit my changes
* fix functions not regenerating
* fix partial scroll back to start of page issue
Co-authored-by: Aria Moradi <aria.moradi007@gmail.com>
* Load next chapter when scrolling to the bottom (Webtoon, Continues Vertical)
* Load next chapter when scrolling to the bottom (Paged reader)
* Added missing types to IReaderProps
* Move load next chapter when at last page to VerticalReader
* Dependency fix
* Use react history for loading next page
* GC Unused or only used once objects
* Move things around a bit
* Revert some changes
* Fix imports
* Revert about change
* Put back logger
* Private logger
* Revert systemtray
* Move import
* Manga description changed from 4096 to 8192
* Check that the description of a manga is not longer than 4096, trim otherwise
* Revert description length changes
- I have updated to the latest version of the app.
- I have tried the troubleshooting guide described in `README.md`
- If this is a request for adding/changing an extension it should be brought up to Tachiyomi: https://github.com/tachiyomiorg/tachiyomi-extensions/issues/new/choose
- If this is an issue with some extension not working properly, It does work inside Tachiyomi as intended.
- I have searched the existing issues and this is a new ticket **NOT** a duplicate or related to another open issue
- I will fill out the title and the information in this template
Note that the issue will be automatically closed if you do not fill out the title or requested information.
**DELETE THIS SECTION IF YOU HAVE READ AND ACKNOWLEDGED IT**
---
## Device information
- Tachidesk version: (Example: v0.2.3-r255-win32)
- Server Operating System: (Example: Ubuntu 20.04)
- Server JVM version: bundled with win32 or (Example: Java 8 Update 281 or OpenJDK 8u281)
- Client Operating System: <usually the same as above Server Operating System>
- Client Web Browser: (Example: Google Chrome 89.0.4389.82)
description:The system on which the Suwayomi-WebUI is running on
placeholder:|
Example: "Windows 11 Pro 24H2 | Ubuntu 24.04.2 LTS"
validations:
required:true
- type:textarea
id:other-details
attributes:
label:Other details
description:The more information that gets provided the better, especially via videos and images
placeholder:|
Additional details and attachments.
- type:checkboxes
id:acknowledgements
attributes:
label:Acknowledgements
description:Read this carefully, we will close and ignore your issue if you skimmed through this.
options:
- label:I have searched the existing issues and this is a new ticket, **NOT** a duplicate or related to another open or closed issue.
required:true
- label:I have written a short but informative title (ideally less than ~100 characters).
required:true
- label:I have tried the troubleshooting guide described in [README.md](https://github.com/Suwayomi/Suwayomi-Server?tab=readme-ov-file#troubleshooting-and-support)
required:true
- label:I have updated to the **[latest version](https://github.com/suwayomi/suwayomi-server/releases/latest)**.
required:true
- label:I have filled out all of the requested information in this form, including specific version numbers.
required:true
- label:I understand that **Suwayomi does not have or fix any extensions**, and I **will not receive help** for any issues related to sources or extensions.
- I have updated to the latest version of the app.
- I have tried the troubleshooting guide described in `README.md`
- If this is a request for adding/changing an extension it should be brought up to Tachiyomi: https://github.com/tachiyomiorg/tachiyomi-extensions/issues/new/choose
- If this is an issue with some extension not working properly, It does work in Tachiyomi application as intended.
- I have searched the existing issues and this is a new ticket **NOT** a duplicate or related to another open issue
- I will fill out the title and the information in this template
Note that the issue will be automatically closed if you do not fill out the title or requested information.
**DELETE THIS SECTION IF YOU HAVE READ AND ACKNOWLEDGED IT**
---
## What feature should be added to Tachidesk?
Explain What the feature is and how it should work in detail
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.