Compare commits

...

684 Commits

Author SHA1 Message Date
Aria Moradi
47d5a34012 add to test reference too 2024-02-19 14:26:04 +03:30
Aria Moradi
d9ead789a2 implement fixes and version 2024-02-19 14:23:41 +03:30
Aria Moradi
0194a6d52e fix lint issue 2024-02-19 02:28:59 +03:30
Aria Moradi
7b013bb391 better logging 2024-02-19 02:21:32 +03:30
Aria Moradi
532d5b9b9a Add auth support to socsk proxy 2024-02-19 02:18:24 +03:30
Mitchell Syer
af0dde5ae8 Add Source Meta (#875) 2024-02-17 11:24:01 -05:00
Mitchell Syer
ea6edaecc4 Fix local source being accidentally removed (#874) 2024-02-17 11:23:53 -05:00
schroda
eb2054bd5e Add VUI as a webUI flavor (#873) 2024-02-17 11:23:45 -05:00
schroda
b277b3e3af Add thumbnail fetch timestamp to the gql manga type (#872) 2024-02-17 11:23:35 -05:00
schroda
9dc3a4e6ee Use correct name for scores data loader (#870) 2024-02-17 11:23:25 -05:00
schroda
6fbd2f1079 Feature/remove download ahead logic (#867)
* 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>
2024-02-17 11:23:13 -05:00
schroda
9edbc7f1d7 Feature/support different webui flavors (#863)
* 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
2024-02-17 11:23:01 -05:00
schroda
8aa75be0d3 Cleanup gql subscription session state correctly (#859)
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.
2024-02-01 21:34:11 -05:00
Chance Zibolski
dc124fb15c Make flaresolverr session options configurable (#854)
Signed-off-by: Chance Zibolski <chance.zibolski@gmail.com>
2024-01-24 21:11:53 -05:00
Chance Zibolski
9109d1ca3e Use a session with flaresolverr (#853)
Signed-off-by: Chance Zibolski <chance.zibolski@gmail.com>
2024-01-24 20:44:45 -05:00
schroda
02296f1d1c Change flaresolverr settings to be non optional (#852)
The settings are not optional in the ServerConfig, thus, they should also not be optional in the returned settings type
2024-01-24 20:02:36 -05:00
Mitchell Syer
63e1082b97 Minor fixes for FlareSolverr (#851)
* Minor fixes for FlareSolverr

* Weird crash but ok
2024-01-24 17:49:51 -05:00
schroda
285f228660 Gracefully shutdown server in case webUI can't be setup (#850) 2024-01-24 17:49:42 -05:00
schroda
c18cf069b1 Prevent invalid webUI from stopping the server (#849)
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
2024-01-24 17:49:28 -05:00
schroda
fc64f47589 Fix/excessive logging (#848)
* 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
2024-01-24 17:49:16 -05:00
Mitchell Syer
562b940d91 Remove dot before cookie (#845) 2024-01-23 19:21:33 -05:00
Mitchell Syer
d658e07583 Implement FlareSolverr (#844)
* Implement FlareSolverr

* Oops
2024-01-23 18:48:55 -05:00
Mitchell Syer
9121a6341c Fix Tracker Status and Scores (#843) 2024-01-23 18:48:47 -05:00
Mitchell Syer
4bec027f11 Change Track.bind to use trackerId + remoteId (#842) 2024-01-22 21:35:56 -05:00
Mitchell Syer
b9053e3057 Fix graphql tracking (#840) 2024-01-21 20:04:24 -05:00
Mitchell Syer
0621138478 Improve Tracker Icons Implementation (#836)
* Improve tracker icons implementation

* Fix description
2024-01-21 14:37:51 -05:00
Mitchell Syer
ce42e89e25 Add MangaUpdates (#834) 2024-01-21 11:45:34 -05:00
Mitchell Syer
46e1e4c043 Table for Track Searches (#833)
* Table for Track Searches

* Lint
2024-01-20 23:12:18 -05:00
Andrei Paunescu
621468a183 Apply natural sort to local manga pages in Directory format (#826) 2024-01-20 19:42:08 -05:00
schroda
d8876cf96a Add mutex to "updateExtensionDatabase" (#829)
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
2024-01-20 19:42:01 -05:00
Chance Zibolski
57d5bc6480 Add support for configuring which categories are downloaded automatically (#832)
* 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>
2024-01-20 19:41:47 -05:00
Mitchell Syer
f224918f33 Create bin folder (#822) 2024-01-13 11:48:15 -05:00
Mitchell Syer
7b290dc465 Update User Agent (#821) 2024-01-12 23:48:33 -05:00
Mitchell Syer
b1412dda34 Update Java 8 (#820) 2024-01-12 23:46:57 -05:00
Mitchell Syer
28e4ac8dcb Remove Playwright (#643) 2024-01-12 23:46:47 -05:00
robo
79eeb6d703 [skip ci] add VUI to README.md (#819) 2024-01-12 23:46:37 -05:00
Mitchell Syer
0d0e735d0e Fix brotli (#818) 2024-01-11 23:09:31 -05:00
Mitchell Syer
d994502d06 Update Electron (#817) 2024-01-11 23:09:22 -05:00
schroda
dfbd7a65ae [skip ci] Correct wrong tracker oauth example url (#814) 2024-01-10 21:06:06 -05:00
schroda
f99f94c8d7 Enable tracking (#813)
* Enable tracking

* Add documentation
2024-01-10 20:31:56 -05:00
schroda
41c643496a Add more chapter fields to MangaType (#812)
- last read
- latest read (latest fetched chapter that has been read)
- latest fetched
- latest uploaded
2024-01-10 20:31:47 -05:00
Mitchell Syer
e5476f8a01 Extension repo fixes and improvements (#811) 2024-01-09 19:42:53 -05:00
Mitchell Syer
188fb188ce Set Mac Launcher Executable (#810) 2024-01-09 19:40:42 -05:00
schroda
c852592b34 Prevent adding duplicated extensions to the db table (#808)
* 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
2024-01-09 19:40:31 -05:00
schroda
3a1e0c5a63 Remove extension obsolete flag when updating db after extension list fetch (#807)
In case an extension got marked as obsolete and was found again in a set repo, the obsolete flag has to be removed
2024-01-09 19:40:16 -05:00
schroda
6376972130 Remove caching of extensions for gql mutation (#806)
The client should use the extension query to get "cached" extensions and the mutation to update the extensions
2024-01-09 19:38:21 -05:00
Mitchell Syer
c70c860a82 Create Client IDs (#804)
* Create Client IDs

* Cleanup imports
2024-01-07 15:36:23 -05:00
Tachimanga
5a178ada74 add trackers support (#720)
* 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>
2024-01-07 15:07:41 -05:00
Mitchell Syer
230427e758 Support Custom Repos (#803)
* Support custom repos

* Fix migration

* Make extension after update optional
2024-01-05 19:14:09 -05:00
Mitchell Syer
abf1af41a3 Update bundled webui (#802) 2024-01-05 15:22:04 -05:00
Mitchell Syer
61e2548bb7 Deb fixes (#801) 2024-01-05 14:51:23 -05:00
Mitchell Syer
f739c54292 Rename the project (#795) 2024-01-05 14:12:35 -05:00
brianmakesthings
3ed84de320 [skip ci] Add API info (#798) 2023-12-25 23:51:53 -05:00
schroda
621b4c0946 Correctly calculate the first chapter to download index (#796)
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
2023-12-23 16:23:06 -05:00
schroda
11be969101 Fix/download subscription returning outdated data for finished downloads (#794)
* 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
2023-12-16 12:59:17 -05:00
schroda
ea958cd8f7 Correctly emit the current status immediately (#792)
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.
2023-12-16 11:26:48 -05:00
Mitchell Syer
56048dcdb0 Update Github Actions (#788)
* Update github actions

* Replace set-output
2023-12-08 19:50:12 -05:00
schroda
fb545947ec Feature/gql improve webui update status (#783)
* 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
2023-12-08 19:17:25 -05:00
schroda
df57070b70 Make sure to always send finished chapter downloads with the download status (#782)
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
2023-12-08 19:16:52 -05:00
Mitchell Syer
9b27d7ee23 Improve Http Client Configuration (#786)
* Improve Http Client Configuration

* Lint
2023-12-08 19:16:38 -05:00
Mitchell Syer
a2d3fa6e1d Use new Tachiyomi backup filename format (#787)
* Use new Tachiyomi backup filename format

* Lint

* Get Backup Filename in more places

* Delete BackupFull
2023-12-08 19:16:25 -05:00
schroda
94b670eb81 Fix/gql about webui query same response type as webui update info (#781)
* 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
2023-11-26 17:17:28 -05:00
Mitchell Syer
d65ed6ced7 Fix Bundler Script (#780) 2023-11-25 21:42:25 -05:00
schroda
db50eb7526 Disable download ahead limit by default (#778)
Currently, it causes the download ahead while reading logic in the WebUI to be enabled by default, which should be disabled by default
2023-11-25 11:53:37 -05:00
schroda
d21b2018cb Add mutation to clear the cached images (#775) 2023-11-25 11:53:29 -05:00
schroda
9110c07ed9 Correctly select enum webui flavor via "ui name" (#772)
The selection always returned the default value fallback due to incorrectly using the enums value name instead of the "uiName" of the enum value
2023-11-19 19:22:26 -05:00
schroda
2298e71279 Feature/gql about webui query (#773)
* Rename "about" query to "aboutServer"

* Add "about" query for webUI
2023-11-19 19:22:16 -05:00
schroda
909bd76e08 Cleanup parent folders when deleting downloaded chapters (#776)
Currently, the download folder never gets cleaned up which leads to having a lot of empty folders (sources, mangas folders)
2023-11-19 19:22:06 -05:00
Mitchell Syer
50cd0c4e10 Fix Queries Containing % (#766) 2023-11-07 18:11:38 -05:00
Mitchell Syer
460fc235e3 Add Cache-Control to Extension Icons (#765) 2023-11-07 18:11:30 -05:00
schroda
c38a3d9eba Update served webUI after update (#764)
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.
2023-11-07 18:11:21 -05:00
schroda
b303291e94 Always get the latest commit count for jar name (#763)
When adding commits or switching between branches the "shadowJar" gradle task always used the same (outdated) commit count which created jars with confusing names
2023-11-05 21:16:55 -05:00
schroda
7993da038e Fix/initial auto backup never triggered in case server was not running (#762)
* 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
2023-11-05 21:16:48 -05:00
schroda
05bf4f5525 Fix/auto download new chapters initial fetch (#761)
* 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
2023-11-05 21:16:40 -05:00
Mitchell Syer
db36896f92 Fix chapter duplicates if its a different url but same chapter list size (#759) 2023-11-05 10:52:10 -05:00
Mitchell Syer
16dbad8bdf Fix path to Preference file if it contains a invalid path character (#750)
* Fix path to shared preference files if it contains a invalid character

* Lint
2023-11-04 18:10:58 -04:00
schroda
8a4c717d24 Check for all downloaded pages during a chapter download (#752)
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.
2023-11-04 18:10:06 -04:00
Mitchell Syer
442a290966 Improve Extensions List (#753)
* Use new extension icon path

* Improve Extension list performance
2023-11-04 18:09:55 -04:00
Mitchell Syer
0785f4d0f5 Chapter Fetch Improvements (#754)
* 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
2023-11-04 18:09:40 -04:00
schroda
21e325af9c Correctly handle download of new chapters of not started entries (#755)
The function incorrectly exited early in case no latest read chapter was found.
This rendered disabling the setting "excludeEntryWithUnreadChapters" useless.
2023-11-04 18:09:32 -04:00
schroda
3e9d29ea7f Remove username and password from config log (#756) 2023-11-04 18:09:24 -04:00
schroda
4324373e61 Fix/chapter list fetch updating and inserting chapters into database (#749)
* 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
2023-11-01 20:24:34 -04:00
schroda
673053d291 Migrate preferences only if necessary (#748)
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
2023-11-01 09:19:57 -04:00
schroda
5b3975f886 Only batch update in case list is not empty (#747)
Apparently "BatchUpdateStatement" can't handle an empty data set
2023-11-01 09:19:40 -04:00
schroda
7ed8f43859 Fix/backup import failure not resetting status (#746)
* 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.
2023-10-31 21:21:11 -04:00
schroda
dcbb1c0dd1 Handle backups with categories having default category name (#745)
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.
2023-10-30 19:47:33 -04:00
schroda
5d4d417f3e Extract downloaded webUI zip in temp folder for validation (#744)
Could cause issues due to not having permission to create the folder to extract the zip into
2023-10-30 19:47:23 -04:00
schroda
5943c6a2c6 Feature/improve browsing source performance (#743)
* Improve browse source database operations

* Reuse "insertOrGet" for "processEntries"
2023-10-30 19:47:13 -04:00
Alexandre Journet
6d33d72663 #733: Improve perfs on getChapterList with onlineFetch (Less databases calls) (#737)
* improve(#733): less databases calls on getChapterList with onlineFetch

* improve(#733): fixes (delete with ids), tried batch update but not successfull

* improve(#733): fixes (batch update)

* improve(#733): clean imports

* improve(#733): fixes SChapter to ChapterDataClass,

* improve(#733): re-added recognize chap number

---------

Co-authored-by: Alexandre JOURNET <alexandre.journet@axopen.com>
2023-10-30 19:47:03 -04:00
schroda
9d2b098837 Fix/updater update stuck in running status after failure (#731)
* 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
2023-10-30 19:46:54 -04:00
schroda
17bc2d2331 Fetch mangas during the update (#729)
* 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
2023-10-30 19:46:43 -04:00
Mitchell Syer
1c192b8db6 Fix Updater (#742) 2023-10-29 12:17:20 -04:00
schroda
76595233fc Prevent mangas from being added to the default category (#741)
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
2023-10-29 11:02:31 -04:00
schroda
6531b80998 Delete outdated thumbnails when inserting mangas into database (#739)
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
2023-10-29 11:02:23 -04:00
schroda
05707e29d7 Add missing settings to gql (#738)
* Add missing settings to gql

* Cleanup updating settings
2023-10-29 11:02:13 -04:00
schroda
616ed4637d Handle disabled download ahead limit for new chapters auto download (#734)
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
2023-10-29 11:02:02 -04:00
schroda
912c340a01 Fix update subscription returning stale data (#727)
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
2023-10-29 11:01:55 -04:00
Mitchell Syer
583a2f0fad Migrate to XML Settings from Preferences (#722)
* Migrate to XML Settings from Preferences

* Lint
2023-10-29 11:01:46 -04:00
schroda
60015bc041 Return source for preference mutation (#728) 2023-10-26 18:15:29 -04:00
Mitchell Syer
029f445d0a Revert Dex2Jar (#721)
* Revert attempts to fix Dex2Jar

* Revert to v64 of Dex2Jar
2023-10-16 20:13:06 -04:00
schroda
150416b578 Fix/default log level (#719)
* 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
2023-10-16 09:02:56 -04:00
schroda
6684576de1 Fix more missing functions (#718)
2cf9a407e8
2023-10-16 09:02:01 -04:00
Mitchell Syer
289acc9296 Fix Kavita (#716) 2023-10-15 21:58:38 -04:00
Mitchell Syer
2cf9a407e8 Fix MangaDex and Other Sources (#715) 2023-10-15 21:50:30 -04:00
Mitchell Syer
682c364647 Address Build Warnings and Cleanup (#707)
* 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
2023-10-15 20:16:30 -04:00
schroda
e70730e9a8 Query for mangas in specific categories (#712) 2023-10-15 20:14:59 -04:00
schroda
0ba6c88d69 Fix/graphql mangas query genre based filtering (#713)
* 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
2023-10-15 20:14:20 -04:00
schroda
c56bdea1e2 Do not log ping messages (#709) 2023-10-15 20:14:10 -04:00
schroda
a449a01a24 Fix/web interface manager get latest compatible version (#706)
* 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
2023-10-07 20:20:09 -04:00
Mitchell Syer
849acfca3d Switch to a new Ktlint Formatter (#705)
* 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
2023-10-06 23:38:39 -04:00
schroda
3cd3cb0186 Fix/graphql subscriptions logging (#704)
* Only log operationMessage in case gql logging is enabled

* Always log message type and operation name
2023-10-04 22:02:46 -04:00
Mitchell Syer
feead100f2 Update dependencies (#701) 2023-10-04 22:02:28 -04:00
Mitchell Syer
a9987e6ab0 Support more image types (#700) 2023-10-04 22:02:20 -04:00
schroda
ef0a6f54b8 Feature/auto download ahead (#681)
* 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.
2023-10-04 22:02:10 -04:00
Mitchell Syer
c8865ad185 Implement Non-Final 1.5 Extensions API (#699)
* Implement non-final 1.5 extensions API

* Bump lib version max

* Add visibility to preferences

* Add preference visibility
2023-10-04 22:01:45 -04:00
schroda
354968fba7 Update version "name" and "code" when installing external extension (#698)
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.
2023-10-02 17:46:46 -04:00
schroda
f985ed2131 Order chapters to download by manga and source order (#697)
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.
2023-10-02 17:46:38 -04:00
schroda
be2628875f Correctly select results using cursors while sorting (#696)
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).
2023-10-02 17:46:26 -04:00
Alessandro Schwaiger
9430c8c580 [skip ci] Added new Tachidesk-VaadinUI Client (#695) 2023-10-01 17:16:35 -04:00
Mitchell Syer
ea2cf5d4ff Fix File Upload (#694)
* Fix File Upload

* Use operations instead of operation

* Fix tests
2023-09-30 21:55:42 -04:00
He Zhu
3b36974d84 Fixed Bitmap missing method when using Baozi Manhua extensions. (#687) 2023-09-23 16:26:20 -04:00
MangaCrushTeam
41fea1d2a0 remove @Synchronized in CloudflareInterceptor.kt for performance (#688) 2023-09-23 16:26:07 -04:00
schroda
d81fafc9f6 Correctly detect initial fetch of chapters (#689)
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.
2023-09-23 16:25:59 -04:00
schroda
0a73177996 Update graphqlkotlin to v6.5.6 (#685) 2023-09-16 13:07:50 -04:00
schroda
c9423ef425 Send every download status change to the subscriber (#684)
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
2023-09-16 13:07:43 -04:00
schroda
7086055ec3 Handle finished downloads that weren't removed from the queue (#683)
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.
2023-09-16 13:07:35 -04:00
schroda
553b35d218 Feature/improve automatic chapter downloads (#680)
* 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
2023-09-16 13:07:24 -04:00
schroda
c910026308 Do not reset already loaded config when updating config file (#679)
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.
2023-09-05 20:57:59 -04:00
schroda
35be9f14e4 Return correct latest compatible webUI version (#677)
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 '"'.
2023-09-03 18:11:06 -04:00
schroda
abcbec9c2a Fix/downloader not creating folder or cbz file (#676)
* 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
2023-09-03 18:10:54 -04:00
schroda
ff6f5d7e89 Add more fields to the manga graphql type (#675)
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.
2023-09-03 18:10:49 -04:00
schroda
56deea9fb3 Feature/graphql logging (#674)
* 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
2023-09-03 18:10:43 -04:00
schroda
1c9a139006 Always return "ArchiveProvider" in case "downloadAsCbz" is enabled (#671)
* 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.
2023-08-28 19:25:50 -04:00
Mitchell Syer
4d89c324b9 Fix Oracle JRE Extension Install (#670)
* Minor cleanup

* Fix Oracle JRE Write issue
2023-08-27 22:39:05 -04:00
schroda
a76ce03911 Throw error instead of returning null (#666)
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.
2023-08-27 22:38:52 -04:00
schroda
9ee3f46ff0 Feature/graphql chapter pages mutation handle downloaded chapters (#665)
* 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
2023-08-27 22:38:33 -04:00
schroda
3343007cf8 Add mutation to install external extension (#667) 2023-08-26 22:19:51 -04:00
schroda
c42d314b76 Move source download dirs to new download subfolder (#660)
Should have been added with f2dd67d87f
2023-08-20 14:32:53 -04:00
Mitchell Syer
8db6c2153e Fix some settings not being applied properly (#661)
* Fix some settings not being applied properly

* Update ProtoBackupExport.kt

* Update Updater.kt

* Revert "Update ProtoBackupExport.kt"

This reverts commit 41deaee244.

* Revert "Update Updater.kt"

This reverts commit 2678792cf6.
2023-08-20 14:32:25 -04:00
schroda
5baf54335b Feature/updater provide more info about update (#657)
* 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
2023-08-15 17:51:21 -04:00
schroda
d9019b8f46 Correctly emit changed values (#656)
"SharedFlow::emit" blocked the flow due not being called in a new coroutine.
2023-08-12 14:06:38 -04:00
schroda
a31446557d Feature/graphql server settings (#629)
* 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
2023-08-12 12:03:25 -04:00
schroda
321fbe22dd Feature/listen to server config value changes (#617)
* 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
2023-08-12 11:47:41 -04:00
schroda
01ab912bd9 Remove unnecessary "downloadNewChapters" call in "fetchChapters" mutation (#652)
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
2023-08-12 11:15:06 -04:00
schroda
557bad60bc Prevent last page read to be greater than max page count (#655)
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.
2023-08-12 11:14:58 -04:00
schroda
f2dd67d87f Feature/decouple thumbnail downloads and cache (#581)
* 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
2023-08-12 11:14:43 -04:00
Mitchell Syer
b8b92c8d69 Suspend setupBundledWebUI() (#650) 2023-08-09 20:52:53 -04:00
schroda
74ff112e7a Feature/graphql web UI (#649)
* 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
2023-08-09 20:46:48 -04:00
schroda
684bb1875c Fix/webinterfacemanager update to bundled webui (#648)
* 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
2023-08-09 20:46:33 -04:00
schroda
f6fec2424c Fix/extracting assets from apks (#644)
* 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.
2023-08-06 23:21:31 -04:00
schroda
2889029b70 Fix/downloader manager persisting queue (#639)
* 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
2023-08-06 23:21:21 -04:00
Mitchell Syer
b56b4fa813 Update Local Source to latest Tachiyomi (#637)
* Update Local Source to latest Tachiyomi

* More formatting

* Enable zip64
2023-08-06 23:20:55 -04:00
schroda
00bc055d69 Fix/load extension log load failure (#641)
* 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
2023-08-05 20:10:12 -04:00
schroda
6fd291c7e3 Fetch downloaded chapters page again in case the stored file can't be retrieved (#640)
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
2023-08-05 20:10:02 -04:00
schroda
dbdb787076 Restore download queue async (#638)
The download queue was blocking the main thread, thus, slowing down the startup.
In case the stored queue was huge, this could take multiple seconds
2023-08-05 20:09:38 -04:00
Mitchell Syer
fc788a718d Add 128 px icon (#636) 2023-08-05 20:09:27 -04:00
Mitchell Syer
e093fe6a06 Add CookieManager implementation (#635)
* Add CookieManager implementation

* Remove Syncronized

* Rename CookieStore
2023-08-05 20:09:12 -04:00
Mitchell Syer
cdce368042 Fix Graphql-WS errors and Improve Downloader Subscription (#634)
* Fix errors in graphql-ws

* Send download messages more often
2023-08-04 22:48:41 -04:00
Mitchell Syer
689847d864 Update dependencies (#611) 2023-08-04 22:48:24 -04:00
Mitchell Syer
3675580d87 Add Subscriptions to GraphiQL and Update (#631)
* Add subscription url

* Update Graphiql and dependencies
2023-08-03 22:28:37 -04:00
Mitchell Syer
92f494d0fe Implement Graphql-WS Subscriptions (#630)
* Implement graphql-ws subscriptions

* Fix subscription payload issue

* Close session directly

* Improve id handling
2023-08-03 22:28:28 -04:00
Mitchell Syer
06d7a6d892 Info Queries (#627) 2023-08-03 18:09:11 -04:00
Mitchell Syer
e2754200af Use Tachidesk-Launcher (#618)
* Use the Launcher

* Test launcher

* a

* Revert "a"

This reverts commit eb8667e439.

* Move launcher

* Test launcher 2

* Update dex2jar

* Fixes

* Use regular java with deb install

* Improve linux installs

* Revert "Test launcher 2"

This reverts commit 265825808f.

* Revert "Test launcher"

This reverts commit 7ff83c7ab9.
2023-08-03 18:09:04 -04:00
Mitchell Syer
cdb083ff48 Downloader Queries and Mutations (#610)
* Add downloader GraphQL endpoints

* Fix names

* DeleteDownloadedChapter(s)

* DequeueChapterDownload(s)
2023-08-03 18:08:47 -04:00
Mitchell Syer
c3fb08d634 Library Update Queries and Mutations (#609)
* Add library update GraphQL endpoints

* No need for data classes

* UpdateLibraryManga
2023-08-03 18:08:35 -04:00
schroda
78a167aacf Fix/webui setup failure in case bundled webui is missing (#625)
* 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
2023-07-30 10:29:40 -04:00
schroda
5a913fdfbb Make path to local source changeable (#626) 2023-07-30 10:29:09 -04:00
schroda
f0a190e8d2 Update to bundled webUI version if necessary (#619)
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
2023-07-29 20:26:04 -04:00
schroda
a2715fb851 Feature/webui update download failure do not immediately fallback to bundled version (#620)
* 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
2023-07-29 20:25:47 -04:00
Mitchell Syer
47e5b03f45 Fix some manga filters (#624) 2023-07-29 20:25:27 -04:00
schroda
251141a5c3 Fix/downloader (#622)
* 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
2023-07-29 20:25:12 -04:00
schroda
6ac8f4c45d Use mathematical modulo implementation for calculations (#616)
See documentation (%/rem, mod) for differences.

Example for "issue" that occurred:
mathematical: -4 % 6 = 2 (expected)
kotlin: -4 % 6 = -4 (unexpected)
2023-07-26 19:28:13 -04:00
schroda
7ebefa7c42 Fix/updater scheduling auto updates (#615)
* 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
2023-07-25 20:33:57 -04:00
schroda
9e4c90f220 Always update the last webUI update check timestamp (#614) 2023-07-25 20:33:46 -04:00
schroda
50f988641b Fix/ha scheduler rescheduling ha tasks (#613)
* 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.
2023-07-25 20:33:36 -04:00
schroda
e53b9d4790 Fix/ha scheduler not triggering missed executions due to not meeting the threshold (#612)
* 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.
2023-07-23 12:40:22 -04:00
schroda
027805c4d5 Preserve download queue through server restarts (#599) 2023-07-22 11:42:48 -04:00
schroda
c02496c4f0 Fix/updater automated update max interval of 23 hours (#606)
* 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
2023-07-22 11:41:52 -04:00
schroda
2a83f290a5 Use "backupInterval" to disable auto backups (#608)
Gets rid of unnecessary setting
2023-07-22 11:41:21 -04:00
schroda
d4f9b0b1bc Feature/log to file (#607)
* 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
2023-07-21 19:53:41 -04:00
schroda
2452b03a49 Schedule automated update only once per hour (#605)
The update was scheduled to run every minute of the set hour.
But it should only run once in the set hour.
2023-07-21 19:52:12 -04:00
schroda
2ce423b6cb Correctly check if a new version is available for the preview channel (#604)
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
2023-07-21 19:51:51 -04:00
schroda
e9206158b8 Feature/move server frontend mapping to the frontend (#591)
* 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
2023-07-20 20:48:27 -04:00
schroda
8690e918dd Feature/automatically download new chapters (#596)
* Automatically download new chapters

* Log queued downloads

* Add function to get number of manga chapters
2023-07-20 17:47:46 -04:00
schroda
c1d702a51c Feature/improve automated backup (#597)
* 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
2023-07-20 17:47:30 -04:00
schroda
0338ac3810 Extract assets from apk file (#602)
Some extension require some assets to work properly.
Currently, the extracted jar file does not contain these assets, thus, these extensions wouldn't work
2023-07-20 17:47:08 -04:00
schroda
526fef85e4 Feature/global update trigger automatically (#593)
* Move "addCategoriesToUpdateQueue" to "Updater"

* Automatically trigger the global update
2023-07-10 13:14:14 +03:30
schroda
49f2d8588a Feature/automated backups (#595)
* Automatically create backups

* Cleanup automated backups

* Extract backup filename creation into function
2023-07-10 13:13:53 +03:30
schroda
9a80992aec Correctly read resource in build jar and dev mode (#594)
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.
2023-07-04 04:07:49 +03:30
Mitchell Syer
32d0890dba Proxy thumbnail urls (#589) 2023-07-02 19:18:44 +03:30
schroda
b4d37f9ba2 Make sure "UserConfig" is up-to-date (#590)
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
2023-07-02 19:18:08 +03:30
Mitchell Syer
5372ef8f0c Manga for Source data loader (#588) 2023-07-02 19:16:04 +03:30
Mitchell Syer
a11b654c3d Backup creation and restore gql endpoints (#587) 2023-07-02 19:15:44 +03:30
schroda
1a9a0b3394 Exclude "default" category from reordering (#586)
* 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
2023-07-01 21:23:10 +03:30
schroda
890920a57b Freeze graphql playground scripts to working versions (#585)
The latest versions might include breaking changes
2023-07-01 21:17:41 +03:30
Mitchell Syer
7fe7de5fdf Fix fetchSourceManga filtering 2023-07-01 13:28:15 -04:00
Mitchell Syer
b9b115d0ea Rewrite filter and preference mutations (#577) 2023-06-24 19:58:11 +03:30
schroda
08af195f11 Fix graphql/plugin-explorer urls (#584) 2023-06-24 19:56:29 +03:30
schroda
71cde729fc Delete tmp files on request failure (#582)
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.
2023-06-21 17:32:58 +03:30
schroda
077f0a03f6 Update "dex2jar" to v61 (#583) 2023-06-21 17:21:16 +03:30
Mitchell Syer
812eb8001b Add fetch chapter pages (#576) 2023-06-10 21:42:42 +03:30
schroda
b59af683ac Do not count mangas as part of categories that aren't in the library (#574)
Otherwise, the returned "size" of a property doesn't match the actual manga list, since that list only includes mangas from the library.
2023-06-09 18:27:16 +03:30
schroda
561d680e78 Exclude mangas with specific state from global update (#537) 2023-06-09 16:03:10 +03:30
Mitchell Syer
7c3eff2ba7 Complete source mutations (#567) 2023-06-05 16:49:03 +03:30
Mitchell Syer
300c0a8f35 Category Mutations (#566)
* Complete Category mutations

* Remove TODO
2023-06-05 16:48:57 +03:30
schroda
51bfdc0947 Feature/make config settings changeable during runtime (#545)
* Add logic to update config during runtime

* Update ConfigModule to always use the latest config

* Make ServerConfig settings re-assignable
2023-06-05 16:48:18 +03:30
Aria Moradi
a64566c0f3 fill in the cover according to spec (#571) 2023-06-05 16:18:03 +03:30
Aria Moradi
dbb9a80ea6 use commons-compress everywhere (#570) 2023-06-05 16:16:27 +03:30
Aria Moradi
e930c54246 improve zip parsing (#569) 2023-06-05 14:31:14 +03:30
Mitchell Syer
dfff047cbf Fix cascade migration (#565) 2023-05-29 17:29:54 -04:00
Mitchell Syer
44fb2b02bc Fix global meta delete (#564) 2023-05-29 23:41:39 +03:30
Mitchell Syer
6a7efafd9f Improve database column references and default category handling (#563)
* 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
2023-05-28 04:11:27 +03:30
Mitchell Syer
241abc3956 Add items that are related to the deleted meta (#562) 2023-05-27 21:39:47 +03:30
Mitchell Syer
1e82c879bf Add default category to the database (#561)
* Add default category to the database

* Fix getCategorySize
2023-05-27 03:20:21 +03:30
Mitchell Syer
a81d01d2e3 Don't use data fetchers in mutations (#559) 2023-05-27 03:09:31 +03:30
Mitchell Syer
2230796504 Extension mutations (#560) 2023-05-27 03:09:17 +03:30
Mitchell Syer
458ca7c7cf Fix update chapters (#557) 2023-05-26 13:45:25 +03:30
Mitchell Syer
3f91663ecf Rewrite meta and add meta mutations (#556) 2023-05-26 13:45:16 +03:30
Mitchell Syer
04a671382a Improve GQL Playground (#558) 2023-05-26 13:44:18 +03:30
Mitchell Syer
945ec818e5 Remove category filter (#551) 2023-05-24 14:01:21 +03:30
Mitchell Syer
ff7ac8a785 Fetch Manga and Chapters in GQL (#555) 2023-05-24 14:01:07 +03:30
Mitchell Syer
603105e2ea Fix StringFilter (#554) 2023-05-24 14:00:54 +03:30
Mitchell Syer
5475567b48 Cleanup download type (#553) 2023-05-24 14:00:29 +03:30
Mitchell Syer
2aec0adb08 Category mangas (#552) 2023-05-24 14:00:06 +03:30
Mitchell Syer
54fc3761bf Put graphql under api (#549) 2023-05-17 03:58:00 +03:30
Mitchell Syer
99e1912bfe Fix manga/source and manga/chapters for graphql (#548) 2023-05-17 03:57:20 +03:30
Aria Moradi
ecc1cabafd Merge pull request #547 from Suwayomi/graphql
add graphql
2023-05-13 23:00:13 +03:30
Aria Moradi
1a5b847b23 Update README.md 2023-05-01 19:16:32 +03:30
Aria Moradi
d3409e7133 Update README.md 2023-05-01 19:09:59 +03:30
Aria Moradi
4e553e3eb3 better description about the Tachiyomi extension 2023-05-01 18:44:28 +03:30
Syer10
4577bbc572 More mutations 2023-04-28 21:56:25 -04:00
Syer10
da8ca23496 Start working on mutations 2023-04-28 21:29:06 -04:00
Syer10
988853be63 Seems like this should return null if it errors 2023-04-28 21:28:18 -04:00
schroda
cde5dc5bfa Update "dex2jar" to v60 (#538) 2023-04-10 11:44:22 +03:30
Syer10
b617250eff Delete updates query since the chapters query can now mimic it 2023-04-08 22:55:56 -04:00
Syer10
313da99536 Add in library filter for chapters 2023-04-08 22:54:56 -04:00
Syer10
442e245216 Update TODO 2023-04-08 22:37:51 -04:00
Syer10
050ab17019 Complete SourceQuery 2023-04-08 21:05:05 -04:00
Syer10
c80f488a13 Complete ChapterQuery 2023-04-08 20:40:18 -04:00
Syer10
cf73804c71 Complete ExtensionQuery 2023-04-08 20:39:38 -04:00
Syer10
a90e5d13ea Complete MetaQuery 2023-04-08 15:47:10 -04:00
Syer10
891fb0b479 Simplify keyset pagination 2023-04-08 15:27:18 -04:00
Syer10
58a623d44d Fix keyset pagination for non-unique order by modes 2023-04-08 13:37:09 -04:00
Syer10
0e84b8a154 Lint 2023-04-08 13:36:28 -04:00
Syer10
a4dfcf80e4 Implement manga status filter 2023-04-07 21:30:20 -04:00
Syer10
d8567eadb2 Simplify queries 2023-04-07 21:10:38 -04:00
Syer10
0b88207ad5 Fix empty results errors 2023-04-07 00:02:00 -04:00
Syer10
671466a737 Complete CategoryQuery 2023-04-06 21:53:30 -04:00
Syer10
84881a0d52 Complete MangaQuery 2023-04-04 21:02:29 -04:00
Syer10
a589049cc7 Move things around and introduce Cursor type 2023-04-04 21:02:07 -04:00
Syer10
17877e0f17 Fix case insensitive 2023-04-03 22:12:38 -04:00
Syer10
1ed9bef2a1 Fix the playground explorer and add a updated default query 2023-04-03 22:07:10 -04:00
Syer10
a6dddf311c Basically finish MangaQuery, only paging left 2023-04-03 22:04:46 -04:00
Syer10
e8c2bad187 Handle missing objects in graphql 2023-04-02 20:39:56 -04:00
Syer10
52bda2c080 Start working on graphql paging 2023-04-02 20:15:09 -04:00
Syer10
607919f40f Implement more query parameters 2023-04-02 17:33:19 -04:00
Syer10
d830638ee6 Use actual MangaStatus enum 2023-04-02 16:47:00 -04:00
Syer10
106bda2097 Proper conversion Scalar for Long to String and back 2023-04-02 16:30:03 -04:00
Syer10
7debb27374 Might not need a updates query 2023-03-31 23:11:18 -04:00
Syer10
05b5a7f598 Add updates 2023-03-31 23:03:26 -04:00
Syer10
3bbda7ba54 More todos 2023-03-31 22:36:01 -04:00
Syer10
9312f5fd14 Add global meta 2023-03-31 22:30:14 -04:00
Syer10
399eb07e35 Fix imports 2023-03-31 22:21:09 -04:00
Syer10
eb197ebcee Switch database logger to SLF4J 2023-03-31 22:19:13 -04:00
Syer10
4c30d8ab05 Some TODOs with ideas 2023-03-31 22:00:01 -04:00
Syer10
3a67ddf0f6 Add Extensions to Graphql 2023-03-31 20:58:18 -04:00
Syer10
6541c7b5b7 Serialize Long as String in graphql 2023-03-31 20:30:24 -04:00
Syer10
37f41ade43 Directly use the database for sources in graphql 2023-03-31 20:29:55 -04:00
Syer10
007d20d417 Add Sources to Graphql 2023-03-31 19:44:21 -04:00
Syer10
00370a81fa Minor cleanup 2023-03-31 19:10:04 -04:00
Syer10
d4599c3331 Use Graphiql with the Explorer plugin for the query builder 2023-03-31 19:09:32 -04:00
Syer10
bce76bbcf3 Use Kotlin Coroutines Flow instead of Project reactor 2023-03-30 18:28:56 -04:00
Valter Martinek
847a5fe71b Subscriptions! 2023-03-30 17:05:41 -04:00
Valter Martinek
e2fa003239 Rewrite graphql controller execute as function without docs 2023-03-30 17:04:01 -04:00
Valter Martinek
0c555e88d3 Update graphql-playground endpoint 2023-03-30 17:04:01 -04:00
Valter Martinek
bf7f1a04b3 Add categories to graphql 2023-03-30 17:04:01 -04:00
Valter Martinek
623172af6d Add mutation for updating chapters 2023-03-30 17:04:01 -04:00
Valter Martinek
4fb689d9e4 Add chapter and manga meta field 2023-03-30 17:04:01 -04:00
Valter Martinek
6054c489c6 Add graphql playground 2023-03-30 17:04:01 -04:00
Valter Martinek
21719f4408 Add basic graphql implementation with manga and chapters loading with data loaders 2023-03-30 17:03:56 -04:00
Aria Moradi
f2a650ba02 fix typo 2023-03-27 21:27:10 +03:30
Aria Moradi
871c28b1ea cleanup notes 2023-03-27 21:26:37 +03:30
schroda
d3aa32147a Add logic to only update specific categories (#520)
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.
2023-03-27 20:15:46 +03:30
schroda
9a50f2e408 Notify clients even if no manga gets updated (#531)
In case no manga gets updated and no update job was running before, the client would never receive an info about its update request
2023-03-27 17:11:19 +03:30
schroda
dcde4947e8 Emit update to clients after adding all mangas to the queue (#521)
Emitting updates before all the mangas were added to the queue could lead to e.g. wrong progress calculation.
2023-03-25 22:08:42 +03:30
schroda
5b61bdc3a8 add size field to Category data class (#519)
Makes it possible to display the size of a category to the user
2023-03-25 22:07:50 +03:30
schroda
ec1d65f4c3 update library grouped by source (#511)
* Update mangas grouped by source

* Limit parallel update requests
2023-03-10 11:03:09 +03:30
akabhirav
a0081dec07 fix manga unread and download count (#509) 2023-02-23 22:04:03 +03:30
akabhirav
783787e514 Send last read chapter in Mangas in Category API (#507)
* Send last read chapter with manga

* optimize query

* introduce new field for better performance
2023-02-21 02:47:45 +03:30
akabhirav
ac99dd55a2 Fix random page sent when manga is downloaded (#508) 2023-02-21 02:40:38 +03:30
Mitchell Syer
c56f984952 Fix SharedPreferences.Editor.clear and SharedPreferences.Editor.remove (#505)
* Fix SharedPreferences.Editor.clear and SharedPreferences.Editor.remove

* UNCHECKED_CAST

* Support removing Set<String>

* Typo

* Remove unneeded OptIn
2023-02-19 07:54:24 +03:30
Aria Moradi
9269ca726e It's not us, I swear ;;; 2023-02-16 10:57:26 +03:30
DattatreyaReddy Panta
eca3205dcf Update winget.yml (#500) 2023-02-14 15:02:41 +03:30
akabhirav
13f5486d0b Fix CBZ download bug for newly added mangas in Library (#499) 2023-02-13 19:17:14 +03:30
Aria Moradi
d4e71274f9 update changelog 2023-02-12 23:33:06 +03:30
Aria Moradi
4cc96de806 v0.7.0 2023-02-12 23:08:05 +03:30
Aria Moradi
d27ef12039 stop using depricated API 2023-02-12 23:03:45 +03:30
Aria Moradi
f3c2ee4c40 re-order config options 2023-02-12 22:50:06 +03:30
akabhirav
555f73b478 Download as CBZ (#490)
* Download as CBZ

* Better error handling for zips (code review changes)
2023-02-12 22:45:58 +03:30
akabhirav
544bf2ea21 fix Page index issues for some providers (#491) 2023-02-12 18:34:30 +03:30
Aria Moradi
54bbb5e384 rethink image cache (#498) 2023-02-12 18:33:36 +03:30
akabhirav
b10062c73d Decouple Cache and Download behaviour (#493)
* 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
2023-02-12 18:26:26 +03:30
Aria Moradi
a027d6df1b disable playwright for v0.6.7 2023-02-12 14:35:11 +03:30
Mitchell Syer
926a53a4b0 add support for Extensions Lib 1.4 (#496)
* Support extensions lib 1.4

* Fix build

* Support UpdateStrategy

* Update extension lib min/max to match Tachiyomi

* Use HttpSource.getMangaUrl and add Chapter.realUrl
2023-02-12 05:49:32 +03:30
Mitchell Syer
406cb46170 Fix logging and update system try (#488)
- Dorkbox SystemTray now automatically adds its shutdown hook, and removed the manual function
2023-02-05 22:21:35 +03:30
akabhirav
acc58dc892 Fixe Dex2Jar and dorkbox dependency issues (#487)
Co-authored-by: akxer <>
2023-02-05 18:43:00 +03:30
Aria Moradi
55894c22a4 upgrade dorkbox stuff 2023-01-15 12:46:50 +03:30
Aria Moradi
476b10b862 update gradle version 2023-01-13 13:05:50 +03:30
Aria Moradi
3cbbe446ab fix ambiguous reference issue on JDK 13+ 2023-01-11 15:46:02 +03:30
Mitchell Syer
4cf7512ee0 Improve Playwright handling (#479)
* Improve playwright

* Move DriverJar.java and Chromium.kt
2023-01-08 01:17:53 +03:30
Mitchell Syer
ee8ec460a1 Improve Gradle Configuration (#478)
* Improve gradle configuration

* Formatting fix

Co-authored-by: Aria Moradi <aria.moradi007@gmail.com>

* Improve asm version lock description

Co-authored-by: Aria Moradi <aria.moradi007@gmail.com>

* Improve image decoder description

Co-authored-by: Aria Moradi <aria.moradi007@gmail.com>

Co-authored-by: Aria Moradi <aria.moradi007@gmail.com>
2023-01-07 20:07:53 +03:30
Aria Moradi
deecab3cca fix typo 2023-01-03 13:39:15 +03:30
Aria Moradi
d2f5c1a195 link to Tachiyomi section 2023-01-03 13:38:20 +03:30
Aria Moradi
dba77e26a3 Clarify and Update 2023-01-03 13:30:58 +03:30
Aria Moradi
fa48bafbc6 Clarify and Update 2023-01-03 13:28:54 +03:30
Aria Moradi
73c48694c7 remove possibly misleading sentence 2023-01-03 13:24:42 +03:30
Aria Moradi
0ff89d039b fix CategoryMetaTable reference to CategoryTable (#473) 2023-01-03 13:19:44 +03:30
Aria Moradi
7a7081ee13 Update CategoryMetaTable.kt 2023-01-02 18:23:01 +03:30
Aria Moradi
874aaf4e93 fix when playwright fails on providing a UA 2022-12-28 17:14:12 +03:30
Mitchell Syer
ebf076d9f6 Use extension list fallback if extensions fail to fetch (#469) 2022-12-25 11:15:37 +03:30
Mitchell Syer
073a041d4c Add better manga thumbnail handling (#465) 2022-12-23 00:43:36 +03:30
Mahor
96a9b4dabd Fix debian release (#463)
* Update debhelper-compat to 13

* Re-enable debian release

* Re-enable debian release
2022-12-16 00:21:42 +03:30
Aria Moradi
8e4cdf2386 disable deb release 2022-12-11 20:05:42 +03:30
Mitchell Syer
ab4d925a5a Get Playwright working (#462)
* 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>
2022-12-09 21:47:26 +03:30
Zero
d9c6f52e21 Basic android.graphics Rect and Canvas implementation (#461)
Some extensions use more Canvas methods, but they don't
really seem to get that far yet, all the others I was
able to test seem to work now.
2022-12-06 07:48:40 +03:30
Zero
0a748cd53b implementation of android.graphics.BitmapFactory (#460)
Only what was needed is implemented, compression method is still untested.
2022-12-05 19:21:16 +03:30
Aria Moradi
07314ef018 get default User Agent from WebView (#457)
* 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>
2022-12-04 21:21:19 +03:30
Aria Moradi
5eaebf678f fix regex 2022-12-04 13:03:23 +03:30
Aria Moradi
80fbfa60de better description 2022-12-04 12:59:33 +03:30
Aria Moradi
fbbcc9e9b6 update issue mod 2022-12-04 12:50:03 +03:30
Aria Moradi
f47dc6b9de WebView based cloudflare interceptor (#456)
* 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>
2022-12-04 12:08:54 +03:30
Aria Moradi
5f8e74f017 fix Changelog typos 2022-11-26 20:45:51 +03:30
Aria Moradi
8c1ca0ac7e add Chagelog TL;DR 2022-11-26 20:37:09 +03:30
Aria Moradi
9018de3c4c v0.6.6 2022-11-26 20:29:51 +03:30
Valter Martinek
e7cb88c757 Download queue missing update fix (#450)
* 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>
2022-11-16 20:03:51 +03:30
Valter Martinek
d6127d6811 Add batch endpoint for removing downloads from download queue (#452) 2022-11-16 20:01:48 +03:30
Aria Moradi
67e09e2e1d make chapters endpoint more unifrom 2022-11-15 15:46:02 +03:30
Valter Martinek
8fbc24c751 Batch editing and deleting any chapter (#449)
* 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
2022-11-15 14:19:20 +03:30
Valter Martinek
c0948209be Fix docs for /server/check-updates (#447) 2022-11-11 16:21:29 +03:30
Valter Martinek
7237161d52 Fix settings/check-update endpoint (#445) 2022-11-10 21:32:27 +03:30
Aria Moradi
94c2e21e2b Future proofing 2022-11-10 04:36:56 +03:30
Aria Moradi
65067e6e01 changes needed for tachiyomi tracker 2022-11-10 02:13:20 +03:30
Valter Martinek
39490ce7ba Add batch chapter update endpoint (#442) 2022-11-09 20:43:29 +03:30
Mitchell Syer
2f3f47c745 Set source preference doc fix (#441) 2022-11-08 10:32:45 +03:30
Mitchell Syer
2195c3df76 Downloader Rewrite (#437)
* 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
2022-11-08 04:39:26 +03:30
Aria Moradi
119b9db6b4 refactor deprecated api 2022-11-07 22:50:20 +03:30
Aria Moradi
fcbc598732 Revert H2 database to v1 2022-11-07 22:50:20 +03:30
Aria Moradi
e850049e8e add category and global meta (#438) 2022-11-07 21:04:34 +03:30
Aria Moradi
907adea73f Migrate to H2 v2 2022-11-07 14:10:33 +03:30
Valter Martinek
2ac5c1362c add batch download api (#436)
* 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
2022-11-07 01:02:18 +03:30
Mitchell Syer
8b20e2b48f Add request body to documentation (#435) 2022-11-06 23:19:11 +03:30
Valter Martinek
c2a9820fc1 POST variant for /{sourceId}/search endpoint (#434)
* 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
2022-11-05 20:48:20 +03:30
Valter Martinek
a9e5bc0c95 Pre-load meta entries for all chapters for optimization (#432)
Load meta entries for all chapters in one query to prevent N+1 queries
2022-10-30 20:18:27 +03:30
Valter Martinek
0fa2834d25 add MangaTable.lastFetchedAt and ChapterTable.chaptersLastFetchedAt (#431)
* 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
2022-10-30 20:16:23 +03:30
Valter Martinek
23f0876c00 Add cache control header to manga page response (#430) 2022-10-29 22:19:19 +03:30
Anurag
6d88d90659 Fix: Error handling for popular/latest api if pageNum was supplied as zero (#424)
* 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
2022-10-28 14:34:22 +03:30
Mitchell Syer
a3c366c360 Lint (#423) 2022-10-22 15:38:14 +03:30
Mitchell Syer
3bef07eeab Update dependencies (#422)
* Update dependencies and lint files

* Revert lint
2022-10-22 03:33:07 +03:30
Aria Moradi
d029e65b8e include list of mangas missing source in restore report (#421) 2022-10-20 00:20:39 +03:30
Aria Moradi
f305ac6905 remove BuildConfig as extensions now use AppInfo 2022-10-19 23:08:08 +03:30
Aria Moradi
4d4a46d2a5 move Tachiyomi's BuildConfig to kotlin dir 2022-10-19 22:44:00 +03:30
Aria Moradi
8218f2f830 ktlint 2022-10-19 16:22:07 +03:30
like
b1bf901eac replace quickjs with Mozilla Rhino (#415)
* 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
2022-10-12 14:03:49 +03:30
Mitchell Syer
06eff55210 Updater cleanup and improvements (#416) 2022-10-11 19:57:15 +03:30
Mitchell Syer
71730fddad Documentation cleanup (#417) 2022-10-11 12:54:45 +03:30
Mitchell Syer
f2d1c6e3cb Fix downloader memory leak (#418) 2022-10-11 12:52:10 +03:30
Marco Ebbinghaus
7ae837ca3c Remove support for Sorayomi web interface (#414)
fixes #392
2022-10-07 22:26:26 +03:30
Vedant
b10908df5e Update winget.yml (#410) 2022-10-02 15:07:16 +03:30
Mahor
4dd4d38d5b Revert back to correct way of handling jre_dir (#408) 2022-09-28 22:44:14 +03:30
Mahor
447c286b56 Add libc++-dev (#405)
Use java8-runtime-headless virtual package which is a superset of default-jre-headless
2022-09-25 18:19:37 +03:30
Aria Moradi
c71898ece9 Update Changelog 2022-09-18 09:20:21 +04:30
Aria Moradi
9473e88ea9 bump version 2022-09-18 09:14:44 +04:30
Mahor
d7663ed56e Fix deb package (#397) 2022-08-29 21:59:23 +04:30
voltrare
da7569e2f5 fix jre path(#396)
use `mv -T` @mahor1221
2022-08-27 16:01:05 +04:30
Vedant
d989940a4d Update winget.yml (#393) 2022-08-21 15:29:18 +04:30
Aria Moradi
bd6a86b135 fix more broken stuff 2022-08-19 00:26:03 +04:30
Aria Moradi
b38eb11503 fix more broken stuff 2022-08-19 00:25:37 +04:30
Aria Moradi
7aef32c13d fix more broken stuff 2022-08-19 00:24:40 +04:30
Aria Moradi
fab64b147c fix broken links 2022-08-19 00:21:23 +04:30
Aria Moradi
cc5a63205c v0.6.4 2022-08-19 00:16:55 +04:30
Aria Moradi
814166a884 Fix mistakes from #384 (#385) 2022-08-10 19:14:16 +04:30
Aria Moradi
55240d9e9b Rename every instance of Tachidesk jar to Tachdidesk-Server.jar (#384) 2022-08-10 18:40:16 +04:30
Mahor
9dc598150f Replace linux-all with linux-assets (#381)
* Move linux package specific files to scripts/resources/pkg

* Replace linux-all with linux-assets

* Fix linux-x64 launchers issue

* Remove -e
2022-08-10 18:20:07 +04:30
Mahor
21c087e273 Tidy up bundler script (#380)
* Tidy up bundler script

* Update paths

* Remove -e

* Revert "Remove -e"

This reverts commit 1e29293dd0.
2022-08-10 18:10:45 +04:30
Mitchell Syer
bdf3a7014f Improve DocumentationDsl, bugfix default values and add queryParams (#378)
* 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
2022-07-30 17:59:27 +04:30
Mahor
dfea6e9b1b Update gradle action (#372)
* Update gradle action

* Update actions in build_pull_request.yml
2022-07-04 23:23:31 -04:00
Mahor
50eef1190e Run workflow jobs toghether (#371)
* Run scripts in parallel

* Re enable deb package builds
2022-07-04 10:06:30 -04:00
Mahor
ed180121ff Refactor scripts (#370)
* 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
2022-07-02 15:42:08 -04:00
Vedant
bdb0ad89d4 Publish to Windows Package Managar (WinGet) (#369)
* Update publish.yml

* Create winget.yml

* Update winget.yml

* Update publish.yml

* Update winget.yml
2022-06-30 08:29:23 +04:30
Mahor
7195a30d55 Add linux-all.tar.gz & systemd service (#366)
* Update my email address

* Add systemd configs to debian package

* Add systemd configs

* Tidy up

* Add linux-all.tar.gz

* Rename Tachidesk.jar to tachidesk-server.jar

* Fix typo

* Fix typo
2022-06-16 17:58:31 +04:30
Mitchell Syer
5b0426a94c Docs improvements (#359)
* Use Array since Javalin OpenAPI requires it to read the list generics

* Use custom Pager class for documentation
2022-05-21 14:42:10 +04:30
Mitchell Syer
a6d012abd9 Fix documentation errors (#358) 2022-05-20 15:54:06 +04:30
Aria Moradi
86f0b3f29f fix WebUI release name 2022-05-06 20:36:42 +04:30
Aria Moradi
85e3aa34ac bump WebUI 2022-05-06 20:19:11 +04:30
Aria Moradi
5bbc1dedef fix formatting by kotlinter 2022-05-06 17:52:16 +04:30
Aria Moradi
39b468ef06 fix copymanga (#354) 2022-05-06 17:45:05 +04:30
Mitchell Syer
fe17176b31 document all endpoints (#350)
* Document all endpoints

* Forgot about global endpoints
2022-04-27 16:01:39 +04:30
abhijeetChawla
84f701c4ab add ChapterCount to manga object in categoryMangas endpoint (#349)
* adds ChapterCount to the Manga returned when accessing the array of Manga is a category

* removed a conflicting expresssion
2022-04-24 13:13:35 +04:30
Mitchell Syer
047f8c176f document manga endpoints (#348) 2022-04-24 13:08:33 +04:30
Mitchell Syer
d82e79b680 Add displayValues json field for select filter (#347) 2022-04-24 13:06:19 +04:30
Aria Moradi
320d1ae9d8 add support for alternative web interfaces (#342)
* add support for alternative web interfaces

* fix naming

* won't bundle sorayomi zip

* clean diff
2022-04-16 21:09:36 +04:30
Aria Moradi
a8892143a2 fix Applications dir dependency (#344) 2022-04-16 20:58:12 +04:30
Aria Moradi
50f4532406 add support for changing downloads dir (#343) 2022-04-16 20:20:57 +04:30
Fidel Selva
844454053d handle solid RAR archives (#339)
* 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).
2022-04-16 18:24:03 +04:30
Mitchell Syer
db5c5ed534 Save categories when manga is unfavorited (#335)
Fixes non-library manga with categories in backups
2022-04-08 06:10:39 +04:30
Aria Moradi
a26b8ecca0 v0.6.3 2022-04-07 15:54:42 +04:30
Aria Moradi
5a32ccfa7a fix auth not actually blocking requests (#333) 2022-04-06 21:30:38 +04:30
Mitchell Syer
f51818b157 Add QuickJS, replaces Duktape for Extensions Lib 1.3 (#331) 2022-04-02 19:43:45 +04:30
Mitchell Syer
31a624db51 Add last bit of code needed for Extensions Lib 1.3 (#330) 2022-04-02 05:02:26 +04:30
DattatreyaReddy Panta
f045b18762 update description for Tachidesk-Sorayomi (#326)
* added Tachidesk-Flutter to readme

* Updated Description for Tachidesk-Sorayomi
2022-03-27 16:41:35 +04:30
Mitchell Syer
f5006cac7d Add thumbnail support for stub sources (#320) 2022-03-22 15:51:58 +04:30
Mitchell Syer
152b193ad5 Improve source handling, fix errors with uninitialized mangas in broken sources (#319) 2022-03-22 15:51:07 +04:30
Mitchell Syer
a27af0b642 Fix sources list of one source throws an exception (#308) 2022-03-20 19:24:09 +03:30
Aria Moradi
44ffed3f7c add support for tachiyomi extensions Lib 1.3 (#316)
* closes #315

* provide real values

* add support for tachiyomi extensions lib 1.3
2022-03-19 02:36:42 +03:30
Aria Moradi
fa035ad9be fix meta update changing all keys (#314) 2022-03-18 00:14:22 +03:30
Mahor
186ace4343 Update README.md (#305)
* Update README.md

* Update README.md again
2022-03-05 09:38:20 +03:30
Aria Moradi
8fb1a0bb1f fix filterlist bugs (#306) 2022-03-05 01:13:48 +03:30
Aria Moradi
05513bf8b9 support array filter changes (#304)
* support array filter changes

* typo

* better formating
2022-03-05 00:06:55 +03:30
Aria Moradi
858784857e v0.6.2 2022-03-04 19:03:23 +03:30
Mahor
291a23949a Refactor debian-packager.sh, rename launcher scripts (#303)
* Improve windows-bundler.sh

* Overhaul debian-packager.sh. Rename base package name to tachidesk-server

* Add -electron-launcher-debian.sh
2022-03-03 13:26:56 +03:30
Aria Moradi
454de23844 fix wrong release name 2022-02-19 05:38:04 +03:30
Aria Moradi
1176092fc6 v0.6.1 2022-02-19 05:29:46 +03:30
Aria Moradi
0fc2c57395 fix mentions 2022-02-19 05:27:34 +03:30
Aria Moradi
0b292f8d74 update WebUI and CHANGELOG 2022-02-19 05:17:56 +03:30
Aria Moradi
4bbe51331f remove gson (#295)
* remove gson

* also remove kotson

* fix build
2022-02-19 05:12:20 +03:30
Aria Moradi
c289786dfa auto-remove duplicate chapters (#294)
* auto-remove duplicate chapters

* Apply suggestions from code review

Co-authored-by: Mitchell Syer <Mitchellptbo@gmail.com>

* Update Chapter.kt

Co-authored-by: Mitchell Syer <Mitchellptbo@gmail.com>
2022-02-19 04:44:17 +03:30
Aria Moradi
9a9752a6a1 no online fetch on backup (#293)
* no online fetch on backup

* Revert "no online fetch on backup"

This reverts commit 09af582b1a.

* alternative solution
2022-02-19 02:57:03 +03:30
DattatreyaReddy Panta
c43b688f8e add Tachidesk-Flutter to readme (#292) 2022-02-01 21:52:58 +03:30
Mahor
a6272d5221 Improve windows-bundler.sh (#290) 2022-01-22 14:10:10 +03:30
Mahor
b440a58d95 Fix build_push.yml Hopefully (#289) 2022-01-18 11:01:39 +03:30
Mahor
ec1589aa2d fix Debian package errors (#288)
* 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
2022-01-17 18:41:58 +03:30
Mahor
8d48e56fa0 Automated debian package building (#287)
* 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
2022-01-16 08:27:59 +03:30
Mahor
df7938037e Automated MSI package building (#277)
* Create msi package instead of zipping stuff

* Keep the zip release, Install wixl inside windows-bundler.sh

* Fix mistakes

* Seprate mv command

* Automate versioning

* Fix syntax mistake

* Fix mistake
2022-01-12 23:48:43 +03:30
Mitchell Syer
c908ee2d49 Allow app compilation on Java 18+ (#286) 2022-01-09 22:30:10 +03:30
Mitchell Syer
b714abddae Handlers must return a result (#282) 2022-01-07 17:03:35 +03:30
Mitchell Syer
63ca189907 Update Gradle and Dependencies (#281) 2022-01-07 17:03:01 +03:30
Aria Moradi
6130fb9ba2 update dex2jar 2021-12-13 17:16:19 +03:30
Aria Moradi
f0edc676fc fix compile erorr 2021-12-13 17:16:03 +03:30
Aria Moradi
b68fdb0772 ignore non image files (#269)
* ignore non image files

* Update server/src/main/kotlin/eu/kanade/tachiyomi/source/local/LocalSource.kt

Co-authored-by: Mitchell Syer <Mitchellptbo@gmail.com>

Co-authored-by: Mitchell Syer <Mitchellptbo@gmail.com>
2021-12-03 20:53:18 +03:30
Sascha Hahne
76c7bdd604 Add Route to stop and reset the updater (#260) 2021-12-01 23:18:32 +03:30
Mitchell Syer
205101568e Improve documentation with Http codes (#261)
* Improve documentation dsl with Http codes

* Fix plaintext requiring T
2021-12-01 23:17:41 +03:30
Aria Moradi
efff68c49b refactor getChapter (#268)
* refactor

* better naming

* fix copytight notice
2021-12-01 22:39:19 +03:30
Aria Moradi
f74f60bb1d Update README.md 2021-11-30 11:18:44 +03:30
Aria Moradi
63ea28a620 Update README.md 2021-11-29 20:22:43 +03:30
Aria Moradi
2c6d043277 bump version 2021-11-29 19:24:07 +03:30
Aria Moradi
9a226f7b64 update 2021-11-29 19:14:40 +03:30
Aria Moradi
3b73a0fd72 empty searchTerm support (#259)
* linter run

* convert search params to queryParams
2021-11-29 18:42:53 +03:30
Aria Moradi
2478aa77cd add support for MultiSelectListPreference (#258)
* 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>
2021-11-28 23:11:56 +03:30
Aria Moradi
a41068dbc9 migrate application directories (#255) 2021-11-28 19:56:06 +03:30
Aria Moradi
5e47b7ae6b Update README.md 2021-11-16 21:37:44 +03:30
Aria Moradi
debf45a7d5 Update README.md 2021-11-16 21:09:16 +03:30
Aria Moradi
e7041e8c8c Fix first page not being detected correctly (#253)
* fix first page not being recognized correctly

* fix first page not being recognized correctly
2021-11-15 23:49:02 +03:30
Aria Moradi
bd960992bc cleanup directory names (#251) 2021-11-15 23:40:49 +03:30
Aria Moradi
0c5f6b432c update 2021-11-15 12:22:49 +03:30
Aria Moradi
49232edbd5 update 2021-11-15 12:06:04 +03:30
Mitchell Syer
b02884f58d Add a Kotlin DSL for endpoint documentation (#249) 2021-11-14 18:16:39 +03:30
Aria Moradi
845b588426 Mention the existence of Mahor's Tachidesk-GTK 2021-11-13 13:51:20 +03:30
Aria Moradi
3a97d7c8be update 2021-11-13 13:27:17 +03:30
Sascha Hahne
2cb2ded2d9 Implement Update of Library/Category (#235)
* Implement Update Controller tests

* Basic Threading and notify

* WIP

* Reworked using coroutines

* Use Map for JobSummary Tracking

* Change Tests

* Clean up

* Changes based on review

* Rethrow cancellationexception

* Clean up

* Fix Merge Error

* Actually handle messages

* Clean up

* Remove useless annotation
2021-11-10 22:38:41 +03:30
Aria Moradi
14e02bee6c update 2021-11-10 12:17:26 +03:30
Aria Moradi
30f7cdc1ba add pagination to recentChapters (#246)
* add pagination to recentChapters

* Use kotlin native library

Co-authored-by: Mitchell Syer <Mitchellptbo@gmail.com>

Co-authored-by: Mitchell Syer <Mitchellptbo@gmail.com>
2021-11-08 18:45:52 +03:30
Mitchell Syer
420d14fc37 Fix Manga Meta, add Manga Meta test (#245)
* Fix Manga Meta, add Manga Meta test

* Tweak assertion strings
2021-11-08 03:08:22 +03:30
Aria Moradi
3d7953d977 add manga data to download queue object (#244)
* add manga data to download queue object

* fix lint erro
2021-11-07 21:32:57 +03:30
Aria Moradi
35238b3da1 stop supporting zero based image storage (#242)
* stop supporting zero based image storage, closes #210

* add test
2021-11-07 21:27:11 +03:30
Aria Moradi
446f4283e0 Update CONTRIBUTING.md 2021-11-02 15:58:30 +03:30
Aria Moradi
8062dd3709 convert request type 2021-11-02 12:14:44 +03:30
Aria Moradi
41c8fde8c5 ignore build artifacts generated by teting 2021-11-02 12:13:33 +03:30
Aria Moradi
d90b986d19 implement Source Filters 2021-11-02 04:15:08 +03:30
Aria Moradi
64ea8416b2 refactor 2021-11-01 23:46:46 +03:30
Aria Moradi
100a4c9d35 refactor 2021-11-01 18:02:06 +03:30
Aria Moradi
4ef6dec89a cleanup 2021-11-01 02:10:51 +03:30
Aria Moradi
a14cdc48bd fix credit 2021-11-01 02:09:14 +03:30
Aria Moradi
8a4ddbc6df update 2021-11-01 02:05:02 +03:30
Aria Moradi
ee33acc561 allow injecting Sources 2021-10-31 18:05:55 +03:30
Aria Moradi
5fe69becf3 improve tests 2021-10-31 17:31:46 +03:30
Aria Moradi
d460d3ccdf change windows bundle names 2021-10-31 14:06:59 +03:30
Sascha Hahne
0ee74943e8 Fix category reorder Endpoint. Added Test for Category Reorder (#232)
* Fix category reorder Endpoint. Added Test for Category Reorder

* Remove streams and use kotlin filtering
2021-10-30 14:46:22 +03:30
Aria Moradi
82837e38d2 update 2021-10-30 14:25:23 +03:30
Sascha Hahne
91df90d760 Fix broken test (#231) 2021-10-29 19:40:20 +03:30
Mitchell Syer
1ee37da720 Fix unread and download counts casing (#230) 2021-10-28 19:11:10 +03:30
Aria Moradi
6f8fc5b69d Update README.md 2021-10-28 12:35:24 +03:30
Sascha Hahne
be1918c769 add Cache Header to Thumbnail Response for improved library performance (#228) 2021-10-26 21:46:38 +03:30
Sascha Hahne
0057b35a0a Expose unread and download count of Manga in category api (#227)
* #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
2021-10-25 13:41:07 +03:30
Sascha Hahne
d12974702a Fix tests (#226) 2021-10-24 23:19:27 +03:30
Aria Moradi
921c41689d update 2021-10-24 23:08:56 +03:30
Aria Moradi
6389899507 remove anime support 2021-10-24 22:58:25 +03:30
Aria Moradi
92ede2a2b3 Update README.md 2021-10-24 17:28:02 +03:30
Aria Moradi
826a63ed71 Update README.md 2021-10-24 16:57:06 +03:30
Aria Moradi
d1576a2a72 Update README.md 2021-10-24 14:27:12 +03:30
Aria Moradi
95f218d704 Update README.md 2021-10-23 20:36:45 +03:30
Aria Moradi
315d3a0ac0 Update CONTRIBUTING.md 2021-10-23 20:04:10 +03:30
Aria Moradi
954818cef2 Update CONTRIBUTING.md 2021-10-23 20:02:42 +03:30
Aria Moradi
5a95ca9b1b Update CONTRIBUTING.md 2021-10-23 20:00:35 +03:30
Aria Moradi
c1e6f4c26e better cleaning algorithm 2021-10-23 19:27:50 +03:30
Aria Moradi
7c603258fb Update README.md 2021-10-21 14:32:58 +03:30
Mahor
fcbc582686 Update README.md (#223)
Add PPA's description for Ubuntu-based distributions
2021-10-20 12:15:46 +03:30
Aria Moradi
9c4906b90b cleanup 2021-10-20 08:34:07 +03:30
Aria Moradi
d35e31e02d bump version 2021-10-18 14:41:01 +03:30
Aria Moradi
6c4ca36c09 update WebUI 2021-10-18 14:37:13 +03:30
Aria Moradi
70355dc505 update 2021-10-11 00:21:10 +03:30
Aria Moradi
20aeaf2a05 update 2021-10-11 00:18:49 +03:30
Mitchell Syer
1f13e1d08b Use a custom task to run electron (#220) 2021-10-11 00:16:32 +03:30
Aria Moradi
eb9d35c123 code cleanup 2021-10-11 00:15:15 +03:30
Mitchell Syer
45808cd530 Support using a CatalogueSource instead of only HttpSources (#219) 2021-10-11 00:01:04 +03:30
Aria Moradi
fd715a3f92 fix workflow 2021-10-10 23:52:35 +03:30
Aria Moradi
e3b32367a7 update 2021-10-10 23:51:21 +03:30
Aria Moradi
bf9554a746 update 2021-10-10 23:32:19 +03:30
Aria Moradi
b9f8ca1488 update 2021-10-10 23:01:58 +03:30
Aria Moradi
e8c4159678 use correct conversion units 2021-10-10 21:31:38 +03:30
Aria Moradi
e57e71629e update 2021-10-10 21:05:24 +03:30
Aria Moradi
2bfd9d24a4 remove isNsfw annotation detection 2021-10-10 21:04:28 +03:30
Aria Moradi
b18b8fe22f update 2021-10-10 20:58:10 +03:30
Aria Moradi
b154ff2f9d fix export chapter ordering, include new props in backup 2021-10-10 20:53:50 +03:30
Aria Moradi
e9b764b63c update 2021-10-10 12:27:50 +03:30
Aria Moradi
7216b97d92 mimic Tachyomi's behaviour more closely, fixes ReadComicOnline (EN) 2021-10-10 12:18:21 +03:30
Aria Moradi
0e9d93b194 prepare CHANGELOG 2021-10-06 21:18:21 +03:30
Aria Moradi
2cbee62f0a update docs 2021-09-28 18:06:20 +03:30
Aria Moradi
379e9da5fe clenup 2021-09-28 18:00:24 +03:30
Aria Moradi
ae7caa4901 merge 2021-09-28 17:57:55 +03:30
Aria Moradi
cd8b4c9dd7 convert android.jar lib to a maven repo 2021-09-28 17:55:50 +03:30
Aria Moradi
60cd61dfd2 Update README.md 2021-09-28 03:42:20 +03:30
Aria Moradi
5a6637d9fc Update README.md 2021-09-28 03:39:45 +03:30
Aria Moradi
dca7ed23f5 Update README.md 2021-09-28 03:36:06 +03:30
Aria Moradi
8cb5791f3b Update README.md 2021-09-28 03:34:14 +03:30
Aria Moradi
9b67f2c58f Update CHANGELOG.md 2021-09-28 03:24:57 +03:30
Aria Moradi
3815810d4f Update for release 2021-09-28 01:11:24 +03:30
Aria Moradi
819ceba17d bump version 2021-09-28 00:52:49 +03:30
Aria Moradi
0aa0d62e03 update changelog file and it's template 2021-09-28 00:51:05 +03:30
Aria Moradi
b3e2a35880 update WebUI 2021-09-28 00:50:33 +03:30
Aria Moradi
15ec20c65d fix sorting 2021-09-27 20:27:40 +03:30
Aria Moradi
d4d6d7e12f add recentChapters endpoint 2021-09-27 18:27:05 +03:30
Aria Moradi
2e7a4f1421 remove no longer relevant comment 2021-09-27 14:44:48 +03:30
Aria Moradi
ab8a52faf3 rename ChapterTable.chapterIndex to ChapterTable.sourceOrder 2021-09-27 14:36:06 +03:30
Aria Moradi
bd465559fb Update README.md 2021-09-26 23:48:29 +03:30
Aria Moradi
13ec45a95c aftermath of adding kotlinter to all modules 2021-09-25 04:34:02 +03:30
Mitchell Syer
13b034875b Workaround StdLib issue and add KtLint to all modules (#206)
* Workaround buildconfig kotlin stdlib issue

* Add KtLint to all modules
2021-09-25 04:31:03 +03:30
Aria Moradi
bb701fb088 fix macOS-arm64 java path 2021-09-24 14:06:19 +03:30
Aria Moradi
b367414865 changes 2021-09-24 13:56:26 +03:30
Aria Moradi
4b00eec608 update CHANGELOG 2021-09-19 18:01:13 +04:30
Aria Moradi
5e11b51152 update CHANGELOG 2021-09-19 17:59:37 +04:30
Aria Moradi
9fb43b996e CHANGELOG update 2021-09-19 17:39:28 +04:30
Aria Moradi
bc2072e81f bump version 2021-09-19 17:36:46 +04:30
Aria Moradi
f36bc3f643 update WebUI 2021-09-19 17:34:18 +04:30
Aria Moradi
f7901ad843 fix windows paths 2021-09-19 16:43:16 +04:30
Aria Moradi
3771030ed6 closes #202 2021-09-19 14:24:13 +04:30
Aria Moradi
57197e58b5 fix Task path 2021-09-19 14:14:42 +04:30
Aria Moradi
ac601399ac update WebUI 2021-09-19 14:14:21 +04:30
Aria Moradi
6a0e221153 fix compile 2021-09-19 01:01:20 +04:30
Aria Moradi
6a949fc851 Minor cleanup 2021-09-19 00:59:04 +04:30
Aria Moradi
f1a077dc2f update CHANGELOG 2021-09-18 22:09:34 +04:30
Mitchell Syer
f20962b02b Gradle Updates (#199)
* Cleanup and update gradle, update dependencies

* Duplicate Jsoup
2021-09-18 22:07:19 +04:30
Mitchell Syer
77e057f244 Update BytecodeEditor to use Java NIO Paths (#200) 2021-09-18 21:57:15 +04:30
Aria Moradi
2c5114c770 bump version 2021-09-18 21:07:38 +04:30
Aria Moradi
a30895a199 update WebUI 2021-09-18 21:03:01 +04:30
Aria Moradi
6d46d4b3da closes #131 2021-09-18 20:30:56 +04:30
Aria Moradi
006efbbb77 add ChapterRecognition from tachiyomi, closes #10 2021-09-18 19:40:44 +04:30
Aria Moradi
52334087ad add support for Archive chapters to Local source 2021-09-18 19:14:06 +04:30
Aria Moradi
ea8fb2c70a add comment 2021-09-18 16:11:25 +04:30
Aria Moradi
531d148718 don't save Local source chapters into disk again! 2021-09-18 14:53:59 +04:30
Aria Moradi
d83ddea323 better URLs 2021-09-18 14:49:38 +04:30
Aria Moradi
b5dea34090 update WebUI 2021-09-18 02:39:15 +04:30
Aria Moradi
7d8e3202b5 lint 2021-09-18 02:28:52 +04:30
Aria Moradi
d956e0af4b add Local Source (#196) 2021-09-18 02:20:30 +04:30
Aria Moradi
9ad70990b5 update WebUI 2021-09-18 02:19:43 +04:30
Aria Moradi
82d711f077 fix typo 2021-09-18 02:19:38 +04:30
Aria Moradi
5fc28ef711 handle when title is changing properly 2021-09-18 02:10:35 +04:30
Aria Moradi
1f3dc682e2 migrate to kotlinx.json 2021-09-18 01:43:10 +04:30
Aria Moradi
cce7768246 clean up imports 2021-09-18 01:03:06 +04:30
Aria Moradi
01172b0664 better exception messages 2021-09-18 01:00:42 +04:30
Aria Moradi
1ca11fdd34 add Local Source 2021-09-18 00:47:50 +04:30
Aria Moradi
52a064ae45 lint 2021-09-17 16:32:14 +04:30
Aria Moradi
6c62ddf927 depricate zero based chapters 2021-09-17 16:31:47 +04:30
Aria Moradi
47e04c08d0 fix lint complain 2021-09-17 15:17:18 +04:30
Aria Moradi
d1601874b4 [SKIP CI] update CHANGELOG.md 2021-09-17 01:31:13 +04:30
Aria Moradi
6bc19af041 add ability to delete downloaded chapters 2021-09-17 01:29:42 +04:30
Aria Moradi
4e72a3886f actaully make sure the chapter exists 2021-09-17 00:38:15 +04:30
Aria Moradi
8e6b219eea update CHANGELOG.md 2021-09-14 04:18:19 +04:30
Aria Moradi
bd638251e4 add BasicAuth support 2021-09-14 04:17:01 +04:30
Aria Moradi
0173d5e4b3 migrate to Javalin 4 2021-09-14 03:23:00 +04:30
Aria Moradi
4f364e134b remove expand char limit on MangaTable columns 2021-09-13 20:57:41 +04:30
Aria Moradi
94d2519717 add CHANGELOG for the next release 2021-09-13 20:14:02 +04:30
Aria Moradi
6a11d2e357 bump version 2021-09-13 19:32:05 +04:30
Aria Moradi
0a9e0bc9e4 update WebUI 2021-09-13 19:31:07 +04:30
Aria Moradi
5914e367d1 better CHANGELOG 2021-09-13 19:29:54 +04:30
Mitchell Syer
aeaed888d4 Update Proto models to match Tachi preview (#192) 2021-09-12 04:04:48 +04:30
Aria Moradi
a0f054b005 CHANGELOG.md 2021-09-11 19:47:06 +04:30
Aria Moradi
4498e9d444 beter handling of uninstalling Extensions 2021-09-11 16:26:04 +04:30
Aria Moradi
43e0763fef fix a bug where if two sources return the same URL, a false duplicate might be detected 2021-09-11 14:47:03 +04:30
Aria Moradi
a519c8a482 better PR links 2021-09-11 03:18:36 +04:30
Aria Moradi
19bc595a2a update CHANGELOG.md 2021-09-11 03:13:26 +04:30
Aria Moradi
db07825c58 remove println instance 2021-09-11 03:09:26 +04:30
Aria Moradi
b199e3bf0e fix installing apk with weird name 2021-09-11 01:21:22 +04:30
Aria Moradi
1f9ea0891e add some logging 2021-09-11 00:48:17 +04:30
Aria Moradi
0a7aa48f1e fix apk log and apk name 2021-09-11 00:14:52 +04:30
Aria Moradi
4b65b7da6c rm dummy 2021-09-10 21:42:52 +04:30
Mosei
183a7dac4b Create docker_build_stable (#184)
* Create docker_build_stable

Add docker build workflow

* Rename docker_build_stable to docker_build_stable.yml

* Update docker_build_stable.yml

* Update docker_build_stable.yml
2021-09-10 21:42:31 +04:30
Aria Moradi
6726f008c1 add dummy file to trigger workflow 2021-09-10 21:22:28 +04:30
Mosei
89cf0c140f Update publish.yml (#190) 2021-09-10 20:49:57 +04:30
Mosei
504025ce80 Update build_push.yml (#191) 2021-09-10 20:49:33 +04:30
Aria Moradi
fee9e914f1 fix exposed crash 2021-09-10 00:45:00 +04:30
Aria Moradi
76efa71c68 update WebUI 2021-09-09 23:05:58 +04:30
Aria Moradi
26e61959ae update WebUI 2021-09-09 16:46:19 +04:30
Aria Moradi
9a8956ef9d update dependencies 2021-09-09 16:41:41 +04:30
Aria Moradi
10d3ffc2f6 better UX 2021-09-09 06:05:09 +04:30
Aria Moradi
090399f61d add support for installing external APK 2021-09-09 05:22:45 +04:30
Aria Moradi
ae7d975a92 run won't get stuck now 2021-09-09 05:15:51 +04:30
Aria Moradi
55ec6bcafe add TODO for changing later 2021-09-09 05:15:08 +04:30
Aria Moradi
f0566d15af fix compiler warning 2021-09-08 20:27:29 +04:30
Aria Moradi
a730b692bc update WebUI 2021-09-08 20:24:22 +04:30
Aria Moradi
826d767423 [SKIP CI] update CHANGELOG.md 2021-09-08 20:23:45 +04:30
Aria Moradi
6d227c7fcd Fix typo 2021-09-06 22:23:26 +04:30
Aria Moradi
7d9d97840e Update README.md 2021-09-06 14:41:00 +04:30
Mosei
110ded45a0 Update README.md (#189)
Remove depreciated arbuilder’s docker link
2021-09-05 21:16:25 +04:30
Aria Moradi
7872b593c7 Credit to @Syer10 2021-09-05 17:50:45 +04:30
Aria Moradi
90be30bddb add support for the new gnere type in WebUI 2021-09-05 01:40:34 +04:30
Mitchell Syer
a298c61dab Change type of Manga.genre to a List<String> (#188) 2021-09-05 01:36:52 +04:30
Aria Moradi
eb416c45bd remove not-code changes from CHANGELOG 2021-09-05 00:54:01 +04:30
Aria Moradi
b05b817aeb Update README.md 2021-09-03 18:52:06 +04:30
Aria Moradi
666602283a update 2021-09-03 07:59:41 +04:30
Aria Moradi
ac040a4bae fix oopsies n'shit 2021-09-03 07:57:53 +04:30
Aria Moradi
b4982c8f22 update 2021-09-03 07:55:15 +04:30
Aria Moradi
ce3ad92095 remove node module cache, won't need it anymore 2021-09-03 07:54:07 +04:30
Aria Moradi
8e1ac8698c bump version 2021-09-03 07:48:31 +04:30
Aria Moradi
b60a39c7cb update 2021-09-03 07:46:11 +04:30
Aria Moradi
3b3e8ba4c8 add new unix bundles to release 2021-09-03 07:45:11 +04:30
Aria Moradi
e387f6d3be update 2021-09-03 07:44:00 +04:30
Aria Moradi
799d469cb6 bump electron version 2021-09-03 07:43:13 +04:30
Aria Moradi
a54a596fa7 fix macOS bundler 2021-09-03 07:39:28 +04:30
Aria Moradi
92d73d0285 add linux and macOS bundler script 2021-09-03 06:50:42 +04:30
Aria Moradi
acb752e4e8 update jre 2021-09-03 05:43:33 +04:30
Aria Moradi
9e377abba6 update CHANGELOG 2021-09-03 04:55:01 +04:30
Aria Moradi
04552c0923 update WebUI 2021-09-03 04:52:34 +04:30
Aria Moradi
2e1fb85b73 [skip ci] update changelog 2021-09-03 04:49:38 +04:30
Aria Moradi
50db32d9b4 this is dumb 2021-09-03 04:48:32 +04:30
Aria Moradi
28743d953e [skip ci] r857 2021-09-03 04:41:00 +04:30
Aria Moradi
b109d26aa7 fixed typo 2021-09-03 04:39:45 +04:30
Aria Moradi
7fd21bd06d [skip ci] r855 2021-09-02 17:45:52 +04:30
Aria Moradi
12e0ffb466 text cleanup 2021-09-02 17:43:43 +04:30
Aria Moradi
9259341df8 missed this changelog 2021-09-02 17:31:30 +04:30
Aria Moradi
8e8aca7e7b Update CONTRIBUTING.md 2021-09-02 17:29:26 +04:30
Aria Moradi
7f0bcd987b Update CONTRIBUTING.md 2021-09-02 17:24:32 +04:30
Aria Moradi
ef21de95cb add continues changelog file 2021-09-02 17:20:53 +04:30
Aria Moradi
ca3246de02 bump version 2021-09-02 15:21:27 +04:30
Aria Moradi
f0940b7926 bump version 2021-08-31 17:43:23 +04:30
Aria Moradi
0066e0b901 suppress warnings 2021-08-31 17:33:29 +04:30
Aria Moradi
9771f566b0 better comments 2021-08-30 02:48:10 +04:30
Aria Moradi
38ad4c6dec refactor 2021-08-30 02:44:35 +04:30
Aria Moradi
37cf80a188 code cleanup 2021-08-30 02:38:15 +04:30
Aria Moradi
c86ee53f66 resolve compiler warnings 2021-08-29 22:25:43 +04:30
Aria Moradi
c2cea7e797 can serialize Search Filters 2021-08-29 22:19:44 +04:30
Aria Moradi
a8ef6cdd4f change category re-order url 2021-08-29 21:52:23 +04:30
Aria Moradi
53d157fee8 update 2021-08-29 21:47:09 +04:30
Aria Moradi
c2e07b13f6 fix categories not being normalized 2021-08-29 20:09:17 +04:30
Aria Moradi
2e8cc48311 update WebUI 2021-08-29 02:11:11 +04:30
Aria Moradi
f6f811eb77 update WebUI 2021-08-29 01:59:36 +04:30
Aria Moradi
ac5528fb15 add when the statement was true 2021-08-27 04:49:53 +04:30
Aria Moradi
940d2b7862 bump version 2021-08-26 22:31:06 +04:30
Aria Moradi
835fe3dad3 sorround with try, catch as it might throw an exception 2021-08-26 22:24:54 +04:30
Aria Moradi
dfaecc08c5 add realUrl to Manga, reperesents open in WebView URL 2021-08-26 22:11:51 +04:30
Aria Moradi
87f5e9b847 fix migration number 2021-08-26 22:10:51 +04:30
Aria Moradi
3d3939e808 better logs 2021-08-26 22:10:27 +04:30
Aria Moradi
90822e3858 merge manga data while restoring backup 2021-08-26 16:28:45 +04:30
Aria Moradi
14eec47e9c correct value for inLibrary 2021-08-26 01:34:56 +04:30
Aria Moradi
15ed3fcc69 actual fix for source order 2021-08-26 01:31:59 +04:30
Aria Moradi
fd8fa9f3ef fix chapter restore order 2021-08-26 01:28:42 +04:30
Aria Moradi
b81075f4a7 fix docker builds faling? 2021-08-24 22:23:39 +04:30
Aria Moradi
f11a52e8e1 we don't need that feild anymore 2021-08-24 22:23:00 +04:30
Aria Moradi
9c007483d4 better method of detemining if a source is Nsfw 2021-08-24 02:44:13 +04:30
Aria Moradi
ff4e818e4c add some comments 2021-08-23 21:48:27 +04:30
Aria Moradi
45a50ca0c1 add isNsfw to SourceDataClass 2021-08-23 21:46:28 +04:30
Aria Moradi
65d9021c37 close response 2021-08-23 06:10:31 +04:30
Aria Moradi
66481a0391 NPE fix suggested by @syer10 2021-08-23 06:05:04 +04:30
Aria Moradi
a14a82bc9a fix oppsie, sync dependencies with tachiyomi 2021-08-23 05:27:39 +04:30
Aria Moradi
756c57a16e also intercept on 403 2021-08-23 04:56:27 +04:30
Aria Moradi
8b19e34dc5 Update README.md 2021-08-23 04:38:32 +04:30
Aria Moradi
50083019ee add copyright notices 2021-08-23 04:37:30 +04:30
Aria Moradi
155272e638 add new keys 2021-08-23 04:28:07 +04:30
Aria Moradi
08443ceb3d remove comment 2021-08-23 04:20:04 +04:30
Aria Moradi
c215696f04 have a lighter log level 2021-08-23 04:17:40 +04:30
Aria Moradi
5ca42bf9b6 make it compile 2021-08-23 04:02:55 +04:30
Aria Moradi
3272b9dec5 add CloudflareInterceptor from TachiWeb-Server 2021-08-23 03:45:10 +04:30
Aria Moradi
2ebd5da4aa bump kotlinter version 2021-08-22 19:00:33 +04:30
Aria Moradi
34f024ace2 migrate dex2jar dependency to @ThexXTURBOXx version 2021-08-21 16:36:34 +04:30
Aria Moradi
b31f2d50f6 No more legacy backup 2021-08-21 06:39:12 +04:30
475 changed files with 30810 additions and 7278 deletions

11
.editorconfig Normal file
View File

@@ -0,0 +1,11 @@
[*.{kt,kts}]
indent_size=4
insert_final_newline=true
ij_kotlin_allow_trailing_comma=true
ij_kotlin_allow_trailing_comma_on_call_site=true
ij_kotlin_name_count_to_use_star_import=2147483647
ij_kotlin_name_count_to_use_star_import_for_members=2147483647
ktlint_standard_discouraged-comment-location=disabled
ktlint_standard_if-else-wrapping=disabled
ktlint_standard_no-consecutive-comments=disabled

5
.gitattributes vendored
View File

@@ -25,4 +25,7 @@
*.pyc binary
*.swp binary
*.pdf binary
*.exe binary
*.exe binary
*.avif binary
*.heif binary
*.jxl binary

View File

@@ -11,7 +11,7 @@ I acknowledge that:
- 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 a request for adding/changing an extension it should be brought up to your extension repo.
- 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
@@ -23,7 +23,7 @@ Note that the issue will be automatically closed if you do not fill out the titl
---
## Device information
- Tachidesk version: (Example: v0.2.3-r255-win32)
- Suwayomi-Server version: (Example: v1.0.0-r1438-win32)
- Server Operating System: (Example: Ubuntu 20.04)
- Server Desktop Environment: N/A or (Example: Gnome 40)
- Server JVM version: bundled with win32 or (Example: Java 8 Update 281 or OpenJDK 8u281)

View File

@@ -11,7 +11,7 @@ I acknowledge that:
- 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 a request for adding/changing an extension it should be brought up to your extension repo.
- 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
@@ -22,7 +22,7 @@ Note that the issue will be automatically closed if you do not fill out the titl
---
## What feature should be added to Tachidesk?
## What feature should be added to Suwayomi?
Explain What the feature is and how it should work in detail. Remove this line after you are done.
## Why/Project's Benefit/Existing Problem

View File

@@ -3,6 +3,10 @@ name: CI Pull Request
on:
pull_request:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
check_wrapper:
name: Validate Gradle Wrapper
@@ -10,7 +14,7 @@ jobs:
steps:
- name: Clone repo
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Validate Gradle Wrapper
uses: gradle/wrapper-validation-action@v1
@@ -18,26 +22,21 @@ jobs:
build:
name: Build pull request
needs: check_wrapper
if: "!startsWith(github.event.head_commit.message, '[SKIP CI]')"
runs-on: ubuntu-latest
steps:
- name: Cancel previous runs
uses: styfle/cancel-workflow-action@0.9.0
with:
access_token: ${{ github.token }}
- name: Checkout pull request
uses: actions/checkout@v2
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
path: master
fetch-depth: 0
- name: Set up JDK 1.8
uses: actions/setup-java@v1
uses: actions/setup-java@v4
with:
java-version: 1.8
java-version: 8
distribution: 'temurin'
- name: Copy CI gradle.properties
run: |
@@ -45,17 +44,9 @@ jobs:
mkdir -p ~/.gradle
cp .github/runner-files/ci-gradle.properties ~/.gradle/gradle.properties
- name: Download android.jar
run: |
cd master
curl https://raw.githubusercontent.com/Suwayomi/Tachidesk/android-jar/android.jar -o AndroidCompat/lib/android.jar
- name: Build Jar
uses: eskatos/gradle-command-action@v1
uses: gradle/gradle-build-action@v2
with:
build-root-directory: master
wrapper-directory: master
arguments: :server:shadowJar --stacktrace
wrapper-cache-enabled: true
dependencies-cache-enabled: true
configuration-cache-enabled: true
arguments: ktlintCheck :server:shadowJar --stacktrace

View File

@@ -5,41 +5,38 @@ on:
branches:
- master
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
check_wrapper:
name: Validate Gradle Wrapper
runs-on: ubuntu-latest
steps:
- name: Clone repo
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Validate Gradle Wrapper
uses: gradle/wrapper-validation-action@v1
build:
name: Build artifacts and deploy preview
name: Build Jar
needs: check_wrapper
if: "!startsWith(github.event.head_commit.message, '[SKIP CI]')"
runs-on: ubuntu-latest
steps:
- name: Cancel previous runs
uses: styfle/cancel-workflow-action@0.9.0
with:
access_token: ${{ github.token }}
- name: Checkout master branch
uses: actions/checkout@v2
uses: actions/checkout@v4
with:
ref: master
path: master
fetch-depth: 0
- name: Set up JDK 1.8
uses: actions/setup-java@v1
uses: actions/setup-java@v4
with:
java-version: 1.8
java-version: 8
distribution: 'temurin'
- name: Copy CI gradle.properties
run: |
@@ -47,55 +44,137 @@ jobs:
mkdir -p ~/.gradle
cp .github/runner-files/ci-gradle.properties ~/.gradle/gradle.properties
- name: Download android.jar
run: |
cd master
curl https://raw.githubusercontent.com/Suwayomi/Tachidesk/android-jar/android.jar -o AndroidCompat/lib/android.jar
- name: Build Jar
uses: eskatos/gradle-command-action@v1
uses: gradle/gradle-build-action@v2
env:
ProductBuildType: "Preview"
with:
build-root-directory: master
wrapper-directory: master
arguments: :server:shadowJar --stacktrace
wrapper-cache-enabled: true
dependencies-cache-enabled: true
configuration-cache-enabled: true
# - name: Mock Build and copy webUI, Build Jar
# run: |
# mkdir -p master/server/build
# cd master/server/build
# echo "test" > Tachidesk-v0.3.8-r583.jar
- name: Upload Jar
uses: actions/upload-artifact@v3
with:
name: jar
path: master/server/build/*.jar
if-no-files-found: error
- name: Upload icons
uses: actions/upload-artifact@v3
with:
name: icon
path: master/server/src/main/resources/icon
if-no-files-found: error
- name: Tar scripts dir to maintain file permissions
run: tar -cvzf scripts.tar.gz -C master/ scripts/
- name: Upload scripts.tar.gz
uses: actions/upload-artifact@v3
with:
name: scripts
path: scripts.tar.gz
if-no-files-found: error
bundle:
strategy:
fail-fast: false
matrix:
os:
- debian-all
- linux-assets
- linux-x64
- macOS-x64
- macOS-arm64
- windows-x64
- windows-x86
name: Make ${{ matrix.os }} release
needs: build
runs-on: ubuntu-latest
steps:
- name: Download Jar
uses: actions/download-artifact@v3
with:
name: jar
path: server/build
- name: Download icons
uses: actions/download-artifact@v3
with:
name: icon
path: server/src/main/resources/icon
- name: Download scripts.tar.gz
uses: actions/download-artifact@v3
with:
name: scripts
- name: Make ${{ matrix.os }} release
run: |
mkdir upload
tar -xvpf scripts.tar.gz
scripts/bundler.sh -o upload/ ${{ matrix.os }}
- name: Upload ${{ matrix.os }} release
uses: actions/upload-artifact@v3
with:
name: ${{ matrix.os }}
path: upload/*
if-no-files-found: error
release:
needs: bundle
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v3
with:
name: jar
path: release
- uses: actions/download-artifact@v3
with:
name: debian-all
path: release
- uses: actions/download-artifact@v3
with:
name: linux-assets
path: release
- uses: actions/download-artifact@v3
with:
name: linux-x64
path: release
- uses: actions/download-artifact@v3
with:
name: macOS-x64
path: release
- uses: actions/download-artifact@v3
with:
name: macOS-arm64
path: release
- uses: actions/download-artifact@v3
with:
name: windows-x64
path: release
- uses: actions/download-artifact@v3
with:
name: windows-x86
path: release
- name: Checkout Preview branch
uses: actions/checkout@v3
with:
repository: "Suwayomi/Suwayomi-Server-preview"
ref: main
path: preview
token: ${{ secrets.DEPLOY_PREVIEW_TOKEN }}
- name: Generate Tag Name
id: GenTagName
run: |
cd master/server/build
genTag=$(ls *.jar | sed -e's/Tachidesk-Server-\|.jar//g')
cd release
genTag=$(ls *.jar | sed -e's/Suwayomi-Server-\|.jar//g')
echo "$genTag"
echo "::set-output name=value::$genTag"
- name: make windows packages
run: |
cd master/scripts
./windows-bundler.sh win32
./windows-bundler.sh win64
# - name: Mock make windows packages
# run: |
# cd master/server/build
# echo test > Tachidesk-v0.3.8-r580-win32.zip
- name: Checkout preview branch
uses: actions/checkout@v2
with:
repository: 'Suwayomi/Tachidesk-Server-preview'
ref: main
path: preview
token: ${{ secrets.DEPLOY_PREVIEW_TOKEN }}
echo "value=$genTag" >> $GITHUB_OUTPUT
- name: Create Tag
run: |
@@ -104,7 +183,8 @@ jobs:
cd preview
echo "{ \"latest\": \"$TAG\" }" > index.json
git add index.json
git config --global user.email "github-actions[bot]@users.noreply.github.com"
git config --global user.email \
"github-actions[bot]@users.noreply.github.com"
git config --global user.name "github-actions[bot]"
git commit -m "Updated to $TAG"
git push origin main
@@ -113,14 +193,10 @@ jobs:
git push origin $TAG
- name: Upload Preview Release
uses: ncipollo/release-action@v1
uses: softprops/action-gh-release@v1
with:
token: ${{ secrets.DEPLOY_PREVIEW_TOKEN }}
artifacts: "master/server/build/*.jar,master/server/build/*.zip"
owner: "Suwayomi"
repo: "Tachidesk-Server-preview"
tag: ${{ steps.GenTagName.outputs.value }}
repository: "Suwayomi/Suwayomi-Server-preview"
tag_name: ${{ steps.GenTagName.outputs.value }}
files: release/*
- name: Run Docker build workflow
run: |
curl -X POST -H "Accept: application/vnd.github.v3+json" -H "Authorization: token ${{ secrets.DEPLOY_PREVIEW_TOKEN }}" -d '{"ref":"main", "inputs":{"tachidesk_release_type": "preview"}}' https://api.github.com/repos/suwayomi/docker-tachidesk/actions/workflows/build_container_images.yml/dispatches

View File

@@ -0,0 +1,15 @@
name: Docker Build Stable
on:
release:
types: [published]
jobs:
build_publish_docker_container:
runs-on: ubuntu-latest
steps:
- name: run docker build and publish script
run: |
curl -X POST -H "Accept: application/vnd.github.v3+json" -H "Authorization: token ${{ secrets.DEPLOY_PREVIEW_TOKEN }}" -d '{"ref":"main", "inputs":{"tachidesk_release_type": "stable"}}' https://api.github.com/repos/suwayomi/docker-tachidesk/actions/workflows/build_container_images.yml/dispatches

View File

@@ -1,24 +1,35 @@
name: Issue closer
name: Issue moderator
on:
issues:
types: [opened, edited, reopened]
issue_comment:
types: [created]
jobs:
autoclose:
runs-on: ubuntu-latest
steps:
- name: Autoclose issues
uses: arkon/issue-closer-action@v3.0
- name: Moderate issues
uses: tachiyomiorg/issue-moderator-action@v1
with:
repo-token: ${{ github.token }}
rules: |
duplicate-check-enabled: true
duplicate-check-label: Source request
existing-check-enabled: true
existing-check-label: Source request
auto-close-rules: |
[
{
"type": "title",
"regex": ".*<short description>*",
"regex": ".*<short description>.*",
"message": "You did not fill out the description in the title"
},
{
"type": "title",
"regex": ".*(<|>)+.*",
"message": "You did not remove Angle brackets(< and >) from the title"
},
{
"type": "body",
"regex": ".*DELETE THIS SECTION IF YOU HAVE READ AND ACKNOWLEDGED IT.*",
@@ -26,7 +37,7 @@ jobs:
},
{
"type": "body",
"regex": "(Tachidesk version|Server Operating System|Server Desktop Environment|Server JVM version|Client Operating System|Client Web Browser):.*(\\(Example:|<usually).*",
"regex": ".*(Suwayomi-Server version|Server Operating System|Server Desktop Environment|Server JVM version|Client Operating System|Client Web Browser):.*(\\(Example:|<usually).*",
"message": "The requested information was not filled out"
},
{

View File

@@ -1,92 +1,174 @@
name: CI Publish
on:
workflow_dispatch:
push:
tags:
- 'v*'
- "v*"
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
check_wrapper:
name: Validate Gradle Wrapper
runs-on: ubuntu-latest
steps:
- name: Clone repo
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Validate Gradle Wrapper
uses: gradle/wrapper-validation-action@v1
build:
name: Build artifacts and release
name: Build Jar
needs: check_wrapper
runs-on: ubuntu-latest
steps:
- name: Cancel previous runs
uses: styfle/cancel-workflow-action@0.9.0
with:
access_token: ${{ github.token }}
- name: Checkout ${{ github.ref }}
uses: actions/checkout@v2
uses: actions/checkout@v4
with:
ref: ${{ github.ref }}
path: master
fetch-depth: 0
- name: Set up JDK 1.8
uses: actions/setup-java@v1
uses: actions/setup-java@v4
with:
java-version: 1.8
java-version: 8
distribution: 'temurin'
- name: Copy CI gradle.properties
run: |
cd master
mkdir -p ~/.gradle
cp .github/runner-files/ci-gradle.properties ~/.gradle/gradle.properties
- name: Download android.jar
run: |
cd master
curl https://raw.githubusercontent.com/Suwayomi/Tachidesk/android-jar/android.jar -o AndroidCompat/lib/android.jar
- name: Cache node_modules
uses: actions/cache@v2
with:
path: |
**/webUI/node_modules
key: ${{ runner.os }}-${{ hashFiles('**/webUI/yarn.lock') }}
cp .github/runner-files/ci-gradle.properties \
~/.gradle/gradle.properties
- name: Build and copy webUI, Build Jar
uses: eskatos/gradle-command-action@v1
uses: gradle/gradle-build-action@v2
env:
ProductBuildType: "Stable"
with:
build-root-directory: master
wrapper-directory: master
arguments: :server:downloadWebUI :server:shadowJar --stacktrace
wrapper-cache-enabled: true
dependencies-cache-enabled: true
configuration-cache-enabled: true
- name: make windows packages
run: |
cd master/scripts
./windows-bundler.sh win32
./windows-bundler.sh win64
- name: Upload Release
uses: xresloader/upload-to-github-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Upload Jar
uses: actions/upload-artifact@v3
with:
file: "master/server/build/*.jar;master/server/build/*.zip"
tags: true
draft: true
verbose: true
name: jar
path: master/server/build/*.jar
if-no-files-found: error
- name: Run Docker build workflow
- name: Upload icons
uses: actions/upload-artifact@v3
with:
name: icon
path: master/server/src/main/resources/icon
if-no-files-found: error
- name: Tar scripts dir to maintain file permissions
run: tar -cvzf scripts.tar.gz -C master/ scripts/
- name: Upload scripts.tar.gz
uses: actions/upload-artifact@v3
with:
name: scripts
path: scripts.tar.gz
if-no-files-found: error
bundle:
strategy:
fail-fast: false
matrix:
os:
- debian-all
- linux-assets
- linux-x64
- macOS-x64
- macOS-arm64
- windows-x64
- windows-x86
name: Make ${{ matrix.os }} release
needs: build
runs-on: ubuntu-latest
steps:
- name: Download Jar
uses: actions/download-artifact@v3
with:
name: jar
path: server/build
- name: Download icons
uses: actions/download-artifact@v3
with:
name: icon
path: server/src/main/resources/icon
- name: Download scripts.tar.gz
uses: actions/download-artifact@v3
with:
name: scripts
- name: Make ${{ matrix.os }} release
run: |
curl -X POST -H "Accept: application/vnd.github.v3+json" -H "Authorization: token ${{ secrets.DEPLOY_PREVIEW_TOKEN }}" -d '{"ref":"main", "inputs":{"tachidesk_release_type": "stable"}}' https://api.github.com/repos/suwayomi/docker-tachidesk/actions/workflows/build_container_images.yml/dispatches
mkdir upload/
tar -xvpf scripts.tar.gz
scripts/bundler.sh -o upload/ ${{ matrix.os }}
- name: Upload ${{ matrix.os }} files
uses: actions/upload-artifact@v3
with:
name: ${{ matrix.os }}
path: upload/*
if-no-files-found: error
release:
if: startsWith(github.ref, 'refs/tags/v')
needs: bundle
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v3
with:
name: jar
path: release
- uses: actions/download-artifact@v3
with:
name: debian-all
path: release
- uses: actions/download-artifact@v3
with:
name: linux-assets
path: release
- uses: actions/download-artifact@v3
with:
name: linux-x64
path: release
- uses: actions/download-artifact@v3
with:
name: macOS-x64
path: release
- uses: actions/download-artifact@v3
with:
name: macOS-arm64
path: release
- uses: actions/download-artifact@v3
with:
name: windows-x64
path: release
- uses: actions/download-artifact@v3
with:
name: windows-x86
path: release
- name: Generate checksums
run: cd release && sha256sum * > Checksums.sha256
- name: Release
uses: softprops/action-gh-release@v1
with:
token: ${{ secrets.WINGET_PUBLISH_PAT }}
draft: true
files: release/*

15
.github/workflows/winget.yml vendored Normal file
View File

@@ -0,0 +1,15 @@
name: Publish to WinGet
on:
workflow_run:
workflows: ["CI Publish"]
types:
- completed
jobs:
publish:
runs-on: windows-latest # action can only be run on windows
steps:
- uses: vedantmgoyal2009/winget-releaser@v2
with:
identifier: Suwayomi.Tachidesk-Server
installers-regex: '.*x64.msi$'
token: ${{ secrets.WINGET_PUBLISH_PAT }}

19
.gitignore vendored
View File

@@ -1,16 +1,21 @@
# Ignore Gradle project-specific cache directory
# Ignore project-specific local files and dirs
.gradle
.idea
gradle.properties
.fleet
# But we need these
!.idea/runConfigurations
# Ignore Gradle build output directory
build
server/out
AndroidCompat/out
# WebUI is either to be downloaded on-demand or is a dynamic build asset
server/src/main/resources/WebUI.zip
server/tmp/
server/tachiserver-data/
# bundle asset downlaods
OpenJDK*.zip
electron-*.zip
rcedit-*
# bundling stage downlaoded assets
scripts/OpenJDK*
scripts/zulu*
scripts/electron-*
scripts/rcedit-*

View File

@@ -0,0 +1,11 @@
plugins {
id(libs.plugins.kotlin.jvm.get().pluginId)
id(libs.plugins.kotlin.serialization.get().pluginId)
id(libs.plugins.ktlint.get().pluginId)
}
dependencies {
// Shared
implementation(libs.bundles.shared)
testImplementation(libs.bundles.sharedTest)
}

View File

@@ -9,11 +9,12 @@ package xyz.nulldev.ts.config
import net.harawata.appdirs.AppDirsFactory
const val CONFIG_PREFIX = "suwayomi.tachidesk.config"
val ApplicationRootDir: String
get(): String {
return System.getProperty(
"suwayomi.tachidesk.server.rootDir",
AppDirsFactory.getInstance().getUserDataDir("Tachidesk", null, null)
"$CONFIG_PREFIX.server.rootDir",
AppDirsFactory.getInstance().getUserDataDir("Tachidesk", null, null),
)
}
}

View File

@@ -5,8 +5,9 @@ import org.kodein.di.bind
import org.kodein.di.singleton
class ConfigKodeinModule {
fun create() = DI.Module("ConfigManager") {
//Config module
bind<ConfigManager>() with singleton { GlobalConfigManager }
}
}
fun create() =
DI.Module("ConfigManager") {
// Config module
bind<ConfigManager>() with singleton { GlobalConfigManager }
}
}

View File

@@ -10,7 +10,12 @@ package xyz.nulldev.ts.config
import ch.qos.logback.classic.Level
import com.typesafe.config.Config
import com.typesafe.config.ConfigFactory
import com.typesafe.config.ConfigRenderOptions
import com.typesafe.config.ConfigValue
import com.typesafe.config.ConfigValueFactory
import com.typesafe.config.parser.ConfigDocument
import com.typesafe.config.parser.ConfigDocumentFactory
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import mu.KotlinLogging
import java.io.File
@@ -18,14 +23,18 @@ import java.io.File
* Manages app config.
*/
open class ConfigManager {
val logger = KotlinLogging.logger {}
private val generatedModules = mutableMapOf<Class<out ConfigModule>, ConfigModule>()
val config by lazy { loadConfigs() }
private val userConfigFile = File(ApplicationRootDir, "server.conf")
private var internalConfig = loadConfigs()
val config: Config
get() = internalConfig
//Public read-only view of modules
// Public read-only view of modules
val loadedModules: Map<Class<out ConfigModule>, ConfigModule>
get() = generatedModules
val logger = KotlinLogging.logger {}
private val mutex = Mutex()
/**
* Get a config module
@@ -38,28 +47,32 @@ open class ConfigManager {
@Suppress("UNCHECKED_CAST")
fun <T : ConfigModule> module(type: Class<T>): T = loadedModules[type] as T
private fun getUserConfig(): Config {
return userConfigFile.let {
ConfigFactory.parseFile(it)
}
}
/**
* Load configs
*/
fun loadConfigs(): Config {
//Load reference configs
// Load reference configs
val compatConfig = ConfigFactory.parseResources("compat-reference.conf")
val serverConfig = ConfigFactory.parseResources("server-reference.conf")
val baseConfig =
ConfigFactory.parseMap(
mapOf(
"ts.server.rootDir" to ApplicationRootDir
)
)
ConfigFactory.parseMap(
mapOf(
// override AndroidCompat's rootDir
"androidcompat.rootDir" to "$ApplicationRootDir/android-compat",
),
)
//Load user config
val userConfig =
File(ApplicationRootDir, "server.conf").let {
ConfigFactory.parseFile(it)
}
// Load user config
val userConfig = getUserConfig()
val config = ConfigFactory.empty()
val config =
ConfigFactory.empty()
.withFallback(baseConfig)
.withFallback(userConfig)
.withFallback(compatConfig)
@@ -68,11 +81,7 @@ open class ConfigManager {
// set log level early
if (debugLogsEnabled(config)) {
setLogLevel(Level.DEBUG)
}
logger.debug {
"Loaded config:\n" + config.root().render(ConfigRenderOptions.concise().setFormatted(true))
setLogLevelFor(BASE_LOGGER_NAME, Level.DEBUG)
}
return config
@@ -87,6 +96,71 @@ open class ConfigManager {
registerModule(it)
}
}
private fun updateUserConfigFile(
path: String,
value: ConfigValue,
) {
val userConfigDoc = ConfigDocumentFactory.parseFile(userConfigFile)
val updatedConfigDoc = userConfigDoc.withValue(path, value)
val newFileContent = updatedConfigDoc.render()
userConfigFile.writeText(newFileContent)
}
suspend fun updateValue(
path: String,
value: Any,
) {
mutex.withLock {
val configValue = ConfigValueFactory.fromAnyRef(value)
updateUserConfigFile(path, configValue)
internalConfig = internalConfig.withValue(path, configValue)
}
}
fun resetUserConfig(updateInternalConfig: Boolean = true): ConfigDocument {
val serverConfigFileContent = this::class.java.getResource("/server-reference.conf")?.readText()
val serverConfigDoc = ConfigDocumentFactory.parseString(serverConfigFileContent)
userConfigFile.writeText(serverConfigDoc.render())
if (updateInternalConfig) {
getUserConfig().entrySet().forEach { internalConfig = internalConfig.withValue(it.key, it.value) }
}
return serverConfigDoc
}
/**
* Makes sure the "UserConfig" is up-to-date.
*
* - adds missing settings
* - removes outdated settings
*/
fun updateUserConfig() {
val serverConfig = ConfigFactory.parseResources("server-reference.conf")
val userConfig = getUserConfig()
val hasMissingSettings = serverConfig.entrySet().any { !userConfig.hasPath(it.key) }
val hasOutdatedSettings = userConfig.entrySet().any { !serverConfig.hasPath(it.key) }
val isUserConfigOutdated = hasMissingSettings || hasOutdatedSettings
if (!isUserConfigOutdated) {
return
}
logger.debug {
"user config is out of date, updating... (missingSettings= $hasMissingSettings, outdatedSettings= $hasOutdatedSettings"
}
var newUserConfigDoc: ConfigDocument = resetUserConfig(false)
userConfig.entrySet().filter {
serverConfig.hasPath(
it.key,
)
}.forEach { newUserConfigDoc = newUserConfigDoc.withValue(it.key, it.value) }
userConfigFile.writeText(newUserConfigDoc.render())
}
}
object GlobalConfigManager : ConfigManager()

View File

@@ -8,32 +8,50 @@ package xyz.nulldev.ts.config
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
import com.typesafe.config.Config
import com.typesafe.config.ConfigFactory
import com.typesafe.config.ConfigValueFactory
import io.github.config4k.getValue
import kotlin.reflect.KProperty
/**
* Abstract config module.
*/
abstract class ConfigModule(config: Config, moduleName: String = "") {
val overridableWithSysProperty = SystemPropertyOverrideDelegate(config, moduleName)
@Suppress("UNUSED_PARAMETER")
abstract class ConfigModule(getConfig: () -> Config)
/**
* Abstract jvm-commandline-argument-overridable config module.
*/
abstract class SystemPropertyOverridableConfigModule(getConfig: () -> Config, moduleName: String) : ConfigModule(getConfig) {
val overridableConfig = SystemPropertyOverrideDelegate(getConfig, moduleName)
}
class SystemPropertyOverrideDelegate(val config: Config, val moduleName: String) {
inline operator fun <R, reified T> getValue(thisRef: R, property: KProperty<*>): T {
/** Defines a config property that is overridable with jvm `-D` commandline arguments prefixed with [CONFIG_PREFIX] */
class SystemPropertyOverrideDelegate(val getConfig: () -> Config, val moduleName: String) {
inline operator fun <R, reified T> getValue(
thisRef: R,
property: KProperty<*>,
): T {
val config = getConfig()
val configValue: T = config.getValue(thisRef, property)
val combined = System.getProperty(
"suwayomi.tachidesk.config.$moduleName.${property.name}",
configValue.toString()
)
val combined =
System.getProperty(
"$CONFIG_PREFIX.$moduleName.${property.name}",
if (T::class.simpleName == "List") {
ConfigValueFactory.fromAnyRef(configValue).render()
} else {
configValue.toString()
},
)
val asT = when(T::class.simpleName) {
return when (T::class.simpleName) {
"Int" -> combined.toInt()
"Boolean" -> combined.toBoolean()
"Double" -> combined.toDouble()
"List" -> ConfigFactory.parseString("internal=" + combined).getStringList("internal").orEmpty()
// add more types as needed
else -> combined
}
return asT as T
else -> combined // covers String
} as T
}
}

View File

@@ -8,13 +8,89 @@ package xyz.nulldev.ts.config
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
import ch.qos.logback.classic.Level
import ch.qos.logback.classic.LoggerContext
import ch.qos.logback.classic.encoder.PatternLayoutEncoder
import ch.qos.logback.classic.spi.ILoggingEvent
import ch.qos.logback.core.rolling.RollingFileAppender
import ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy
import ch.qos.logback.core.util.FileSize
import com.typesafe.config.Config
import mu.KotlinLogging
import org.slf4j.Logger
import org.slf4j.LoggerFactory
fun setLogLevel(level: Level) {
(KotlinLogging.logger(Logger.ROOT_LOGGER_NAME).underlyingLogger as ch.qos.logback.classic.Logger).level = level
private fun createRollingFileAppender(
logContext: LoggerContext,
logDirPath: String,
): RollingFileAppender<ILoggingEvent> {
val logFilename = "application"
val logEncoder =
PatternLayoutEncoder().apply {
pattern = "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n"
context = logContext
start()
}
val appender =
RollingFileAppender<ILoggingEvent>().apply {
name = "FILE"
context = logContext
encoder = logEncoder
file = "$logDirPath/$logFilename.log"
}
val rollingPolicy =
SizeAndTimeBasedRollingPolicy<ILoggingEvent>().apply {
context = logContext
setParent(appender)
fileNamePattern = "$logDirPath/${logFilename}_%d{yyyy-MM-dd}_%i.log.gz"
setMaxFileSize(FileSize.valueOf("10mb"))
maxHistory = 14
setTotalSizeCap(FileSize.valueOf("1gb"))
start()
}
appender.rollingPolicy = rollingPolicy
appender.start()
return appender
}
fun debugLogsEnabled(config: Config)
= System.getProperty("suwayomi.tachidesk.config.server.debugLogsEnabled", config.getString("server.debugLogsEnabled")).toBoolean()
private fun getBaseLogger(): ch.qos.logback.classic.Logger {
return (KotlinLogging.logger(Logger.ROOT_LOGGER_NAME).underlyingLogger as ch.qos.logback.classic.Logger)
}
private fun getLogger(name: String): ch.qos.logback.classic.Logger {
val context = LoggerFactory.getILoggerFactory() as LoggerContext
return context.getLogger(name)
}
fun initLoggerConfig(appRootPath: String) {
val context = LoggerFactory.getILoggerFactory() as LoggerContext
val logger = getBaseLogger()
// logback logs to the console by default (at least when adding a console appender logs in the console are duplicated)
logger.addAppender(createRollingFileAppender(context, "$appRootPath/logs"))
// set "kotlin exposed" log level
setLogLevelFor("Exposed", Level.ERROR)
}
const val BASE_LOGGER_NAME = "_BaseLogger"
fun setLogLevelFor(
name: String,
level: Level,
) {
val logger =
if (name == BASE_LOGGER_NAME) {
getBaseLogger()
} else {
getLogger(name)
}
logger.level = level
}
fun debugLogsEnabled(config: Config) =
System.getProperty("suwayomi.tachidesk.config.server.debugLogsEnabled", config.getString("server.debugLogsEnabled")).toBoolean()

View File

@@ -2,5 +2,6 @@ package xyz.nulldev.ts.config.util
import com.typesafe.config.Config
operator fun Config.get(key: String) = getString(key)
operator fun Config.get(key: String) =
getString(key)
?: throw IllegalStateException("Could not find value for config entry: $key!")

View File

@@ -1,68 +1,38 @@
plugins {
application
kotlin("plugin.serialization")
}
repositories {
mavenCentral()
maven {
url = uri("https://jitpack.io")
}
maven {
url = uri("https://maven.google.com")
}
id(libs.plugins.kotlin.jvm.get().pluginId)
id(libs.plugins.kotlin.serialization.get().pluginId)
id(libs.plugins.ktlint.get().pluginId)
}
dependencies {
// Android stub library
implementation(fileTree("lib/"))
// Shared
implementation(libs.bundles.shared)
testImplementation(libs.bundles.sharedTest)
// JSON
compileOnly("com.google.code.gson:gson:2.8.6")
// Android stub library
implementation(libs.android.stubs)
// XML
compileOnly(group= "xmlpull", name= "xmlpull", version= "1.1.3.1")
compileOnly(libs.xmlpull)
// Config API
implementation(project(":AndroidCompat:Config"))
implementation(projects.androidCompat.config)
// APK sig verifier
compileOnly("com.android.tools.build:apksig:4.2.0-alpha13")
compileOnly(libs.apksig)
// AndroidX annotations
compileOnly("androidx.annotation:annotation:1.2.0-alpha01")
compileOnly(libs.android.annotations)
// substitute for duktape-android
implementation("org.mozilla:rhino-runtime:1.7.13") // slimmer version of 'org.mozilla:rhino'
implementation("org.mozilla:rhino-engine:1.7.13") // provides the same interface as 'javax.script' a.k.a Nashorn
implementation(libs.bundles.rhino)
// Kotlin wrapper around Java Preferences, makes certain things easier
val multiplatformSettingsVersion = "0.7.7"
implementation("com.russhwolf:multiplatform-settings-jvm:$multiplatformSettingsVersion")
implementation("com.russhwolf:multiplatform-settings-serialization-jvm:$multiplatformSettingsVersion")
implementation(libs.bundles.settings)
// Android version of SimpleDateFormat
implementation("com.ibm.icu:icu4j:69.1")
}
implementation(libs.icu4j)
tasks {
withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
kotlinOptions.freeCompilerArgs = listOf("-Xopt-in=kotlin.RequiresOptIn")
}
// OpenJDK lacks native JPEG encoder and native WEBP decoder
implementation(libs.bundles.twelvemonkeys)
}
//def fatJarTask = tasks.getByPath(':AndroidCompat:JVMPatch:fatJar')
//
//// Copy JVM core patches
//task copyJVMPatches(type: Copy) {
// from fatJarTask.outputs.files
// into 'src/main/resources/patches'
//}
//
//compileOnly(Java.dependsOn gradle.includedBuild('dex2jar').task(':dex-translator:assemble')
//compileOnly(Java.dependsOn copyJVMPatches
//copyJVMPatches.dependsOn fatJarTask
//

View File

@@ -1 +0,0 @@
android.jar

View File

@@ -0,0 +1,235 @@
package android.graphics;
import android.annotation.ColorInt;
import android.annotation.NonNull;
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.stream.ImageOutputStream;
import java.awt.image.BufferedImage;
import java.awt.image.Raster;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Iterator;
public final class Bitmap {
private final int width;
private final int height;
private final BufferedImage image;
public Bitmap(BufferedImage image) {
this.image = image;
this.width = image.getWidth();
this.height = image.getHeight();
}
public BufferedImage getImage() {
return image;
}
public int getHeight() {
return height;
}
public int getWidth() {
return width;
}
public enum CompressFormat {
JPEG (0),
PNG (1),
WEBP (2),
WEBP_LOSSY (3),
WEBP_LOSSLESS (4);
CompressFormat(int nativeInt) {
this.nativeInt = nativeInt;
}
final int nativeInt;
}
public enum Config {
ALPHA_8(1),
RGB_565(3),
ARGB_4444(4),
ARGB_8888(5),
RGBA_F16(6),
HARDWARE(7),
RGBA_1010102(8);
final int nativeInt;
private static final Config[] sConfigs = {
null, ALPHA_8, null, RGB_565, ARGB_4444, ARGB_8888, RGBA_F16, HARDWARE, RGBA_1010102
};
Config(int ni) {
this.nativeInt = ni;
}
static Config nativeToConfig(int ni) {
return sConfigs[ni];
}
}
/**
* Common code for checking that x and y are >= 0
*
* @param x x coordinate to ensure is >= 0
* @param y y coordinate to ensure is >= 0
*/
private static void checkXYSign(int x, int y) {
if (x < 0) {
throw new IllegalArgumentException("x must be >= 0");
}
if (y < 0) {
throw new IllegalArgumentException("y must be >= 0");
}
}
/**
* Common code for checking that width and height are > 0
*
* @param width width to ensure is > 0
* @param height height to ensure is > 0
*/
private static void checkWidthHeight(int width, int height) {
if (width <= 0) {
throw new IllegalArgumentException("width must be > 0");
}
if (height <= 0) {
throw new IllegalArgumentException("height must be > 0");
}
}
public static Bitmap createBitmap(int width, int height, Config config) {
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
return new Bitmap(image);
}
public static Bitmap createBitmap(@NonNull Bitmap source, int x, int y, int width, int height) {
checkXYSign(x, y);
checkWidthHeight(width, height);
if (x + width > source.getWidth()) {
throw new IllegalArgumentException("x + width must be <= bitmap.width()");
}
if (y + height > source.getHeight()) {
throw new IllegalArgumentException("y + height must be <= bitmap.height()");
}
// Android will make a copy when creating a sub image,
// so we do the same here
BufferedImage subImage = source.image.getSubimage(x, y, width, height);
BufferedImage newImage = new BufferedImage(subImage.getWidth(), subImage.getHeight(), subImage.getType());
newImage.setData(subImage.getData());
return new Bitmap(newImage);
}
public boolean compress(CompressFormat format, int quality, OutputStream stream) {
if (stream == null) {
throw new NullPointerException();
}
if (quality < 0 || quality > 100) {
throw new IllegalArgumentException("quality must be 0..100");
}
float qualityFloat = ((float) quality) / 100;
String formatString;
if (format == Bitmap.CompressFormat.PNG) {
formatString = "png";
} else if (format == Bitmap.CompressFormat.JPEG) {
formatString = "jpg";
} else {
throw new IllegalArgumentException("unsupported compression format!");
}
Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName(formatString);
if (!writers.hasNext()) {
throw new IllegalStateException("no image writers found for this format!");
}
ImageWriter writer = writers.next();
ImageOutputStream ios;
try {
ios = ImageIO.createImageOutputStream(stream);
} catch (IOException ex) {
throw new RuntimeException(ex);
}
writer.setOutput(ios);
ImageWriteParam param = writer.getDefaultWriteParam();
if ("jpg".equals(formatString)) {
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionQuality(qualityFloat);
}
try {
writer.write(null, new IIOImage(image, null, null), param);
ios.close();
writer.dispose();
} catch (IOException ex) {
throw new RuntimeException(ex);
}
return true;
}
/**
* Shared code to check for illegal arguments passed to getPixels()
* or setPixels()
*
* @param x left edge of the area of pixels to access
* @param y top edge of the area of pixels to access
* @param width width of the area of pixels to access
* @param height height of the area of pixels to access
* @param offset offset into pixels[] array
* @param stride number of elements in pixels[] between each logical row
* @param pixels array to hold the area of pixels being accessed
*/
private void checkPixelsAccess(int x, int y, int width, int height,
int offset, int stride, int[] pixels) {
checkXYSign(x, y);
if (width < 0) {
throw new IllegalArgumentException("width must be >= 0");
}
if (height < 0) {
throw new IllegalArgumentException("height must be >= 0");
}
if (x + width > getWidth()) {
throw new IllegalArgumentException(
"x + width must be <= bitmap.width()");
}
if (y + height > getHeight()) {
throw new IllegalArgumentException(
"y + height must be <= bitmap.height()");
}
if (Math.abs(stride) < width) {
throw new IllegalArgumentException("abs(stride) must be >= width");
}
int lastScanline = offset + (height - 1) * stride;
int length = pixels.length;
if (offset < 0 || (offset + width > length)
|| lastScanline < 0
|| (lastScanline + width > length)) {
throw new ArrayIndexOutOfBoundsException();
}
}
public void getPixels(@ColorInt int[] pixels, int offset, int stride,
int x, int y, int width, int height) {
checkPixelsAccess(x, y, width, height, offset, stride, pixels);
Raster raster = image.getData();
int[] rasterPixels = raster.getPixels(x, y, width, height, (int[]) null);
for (int ht = 0; ht < height; ht++) {
int rowOffset = offset + stride * ht;
System.arraycopy(rasterPixels, ht * width, pixels, rowOffset, width);
}
}
}

View File

@@ -0,0 +1,51 @@
package android.graphics;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.IOException;
import java.util.Iterator;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
public class BitmapFactory {
public static Bitmap decodeStream(InputStream inputStream) {
Bitmap bitmap = null;
try {
ImageInputStream imageInputStream = ImageIO.createImageInputStream(inputStream);
Iterator<ImageReader> imageReaders = ImageIO.getImageReaders(imageInputStream);
if (!imageReaders.hasNext()) {
throw new IllegalArgumentException("no reader for image");
}
ImageReader imageReader = imageReaders.next();
imageReader.setInput(imageInputStream);
BufferedImage image = imageReader.read(0, imageReader.getDefaultReadParam());
bitmap = new Bitmap(image);
imageReader.dispose();
} catch (IOException ex) {
throw new RuntimeException(ex);
}
return bitmap;
}
public static Bitmap decodeByteArray(byte[] data, int offset, int length) {
Bitmap bitmap = null;
ByteArrayInputStream byteArrayStream = new ByteArrayInputStream(data);
try {
BufferedImage image = ImageIO.read(byteArrayStream);
bitmap = new Bitmap(image);
} catch (IOException ex) {
throw new RuntimeException(ex);
}
return bitmap;
}
}

View File

@@ -0,0 +1,21 @@
package android.graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
public final class Canvas {
private BufferedImage canvasImage;
private Graphics2D canvas;
public Canvas(Bitmap bitmap) {
canvasImage = bitmap.getImage();
canvas = canvasImage.createGraphics();
}
public void drawBitmap(Bitmap sourceBitmap, Rect src, Rect dst, Paint paint) {
BufferedImage sourceImage = sourceBitmap.getImage();
BufferedImage sourceImageCropped = sourceImage.getSubimage(src.left, src.top, src.getWidth(), src.getHeight());
canvas.drawImage(sourceImageCropped, null, dst.left, dst.top);
}
}

View File

@@ -0,0 +1,122 @@
package android.graphics;
import android.os.Parcel;
import android.os.Parcelable;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public final class Rect {
int left;
int top;
int right;
int bottom;
private static final class UnflattenHelper {
private static final Pattern FLATTENED_PATTERN = Pattern.compile(
"(-?\\d+) (-?\\d+) (-?\\d+) (-?\\d+)");
static Matcher getMatcher(String str) {
return FLATTENED_PATTERN.matcher(str);
}
}
public Rect() {
}
public Rect(int left, int top, int right, int bottom) {
this.left = left;
this.top = top;
this.right = right;
this.bottom = bottom;
}
public Rect(Rect r) {
if (r == null) {
this.left = 0;
this.top = 0;
this.right = 0;
this.bottom = 0;
} else {
this.left = left;
this.top = top;
this.right = right;
this.bottom = bottom;
}
}
public final int getWidth() {
return right - left;
}
public final int getHeight() {
return bottom - top;
}
public static Rect unflattenFromString(String str) {
if (str.isEmpty()) {
return null;
}
Matcher matcher = UnflattenHelper.getMatcher(str);
if (!matcher.matches()) {
return null;
}
return new Rect(Integer.parseInt(matcher.group(1)),
Integer.parseInt(matcher.group(2)),
Integer.parseInt(matcher.group(3)),
Integer.parseInt(matcher.group(4)));
}
public String toShortString() {
return toShortString(new StringBuilder(32));
}
public String toShortString(StringBuilder sb) {
sb.setLength(0);
sb.append('['); sb.append(left); sb.append(',');
sb.append(top); sb.append("]["); sb.append(right);
sb.append(','); sb.append(bottom); sb.append(']');
return sb.toString();
}
public String flattenToString() {
StringBuilder sb = new StringBuilder(32);
sb.append(left);
sb.append(' ');
sb.append(top);
sb.append(' ');
sb.append(right);
sb.append(' ');
sb.append(bottom);
return sb.toString();
}
public void writeToParcel(Parcel out, int flags) {
out.writeInt(left);
out.writeInt(top);
out.writeInt(right);
out.writeInt(bottom);
}
public static final Parcelable.Creator<Rect> CREATOR = new Parcelable.Creator<Rect>() {
@Override
public Rect createFromParcel(Parcel in) {
Rect r = new Rect();
r.readFromParcel(in);
return r;
}
@Override
public Rect[] newArray(int size) {
return new Rect[size];
}
};
public void readFromParcel(Parcel in) {
left = in.readInt();
top = in.readInt();
right = in.readInt();
bottom = in.readInt();
}
}

View File

@@ -9,8 +9,10 @@ import android.content.Context
class PreferenceManager {
companion object {
@JvmStatic
fun getDefaultSharedPreferences(context: Context)
= context.getSharedPreferences(context.applicationInfo.packageName,
Context.MODE_PRIVATE)!!
fun getDefaultSharedPreferences(context: Context) =
context.getSharedPreferences(
context.applicationInfo.packageName,
Context.MODE_PRIVATE,
)!!
}
}

View File

@@ -4,7 +4,7 @@ package android.text;
import android.graphics.drawable.Drawable;
import org.jetbrains.annotations.NotNull;
import org.jsoup.Jsoup;
import org.jsoup.safety.Whitelist;
import org.jsoup.safety.Safelist;
import org.xml.sax.XMLReader;
/**
@@ -18,7 +18,7 @@ import org.xml.sax.XMLReader;
public class Html {
public static Spanned fromHtml(String source) {
return new FakeSpanned(Jsoup.clean(source, Whitelist.none()));
return new FakeSpanned(Jsoup.clean(source, Safelist.none()));
}
public static Spanned fromHtml(String source, Html.ImageGetter imageGetter, Html.TagHandler tagHandler) {

View File

@@ -0,0 +1,247 @@
package android.webkit;
import android.annotation.Nullable;
import xyz.nulldev.androidcompat.webkit.CookieManagerImpl;
public abstract class CookieManager {
/**
* @deprecated This class should not be constructed by applications, use {@link #getInstance}
* instead to fetch the singleton instance.
*/
// TODO(ntfschr): mark this as @SystemApi after a year.
@Deprecated
public CookieManager() {}
@Override
protected Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException("doesn't implement Cloneable");
}
private static CookieManager INSTANCE = null;
private static final Object lock = new Object();
/**
* Gets the singleton CookieManager instance.
*
* @return the singleton CookieManager instance
*/
public static CookieManager getInstance() {
if (INSTANCE != null) {
return INSTANCE;
} else {
synchronized (lock) {
if (INSTANCE == null) {
INSTANCE = new CookieManagerImpl();
}
return INSTANCE;
}
}
}
/**
* Sets whether the application's {@link WebView} instances should send and
* accept cookies.
* By default this is set to {@code true} and the WebView accepts cookies.
* <p>
* When this is {@code true}
* {@link CookieManager#setAcceptThirdPartyCookies setAcceptThirdPartyCookies} and
* {@link CookieManager#setAcceptFileSchemeCookies setAcceptFileSchemeCookies}
* can be used to control the policy for those specific types of cookie.
*
* @param accept whether {@link WebView} instances should send and accept
* cookies
*/
public abstract void setAcceptCookie(boolean accept);
/**
* Gets whether the application's {@link WebView} instances send and accept
* cookies.
*
* @return {@code true} if {@link WebView} instances send and accept cookies
*/
public abstract boolean acceptCookie();
/**
* Sets whether the {@link WebView} should allow third party cookies to be set.
* Allowing third party cookies is a per WebView policy and can be set
* differently on different WebView instances.
* <p>
* Apps that target {@link android.os.Build.VERSION_CODES#KITKAT} or below
* default to allowing third party cookies. Apps targeting
* {@link android.os.Build.VERSION_CODES#LOLLIPOP} or later default to disallowing
* third party cookies.
*
* @param webview the {@link WebView} instance to set the cookie policy on
* @param accept whether the {@link WebView} instance should accept
* third party cookies
*/
public abstract void setAcceptThirdPartyCookies(WebView webview, boolean accept);
/**
* Gets whether the {@link WebView} should allow third party cookies to be set.
*
* @param webview the {@link WebView} instance to get the cookie policy for
* @return {@code true} if the {@link WebView} accepts third party cookies
*/
public abstract boolean acceptThirdPartyCookies(WebView webview);
/**
* Sets a single cookie (key-value pair) for the given URL. Any existing cookie with the same
* host, path and name will be replaced with the new cookie. The cookie being set
* will be ignored if it is expired. To set multiple cookies, your application should invoke
* this method multiple times.
*
* <p>The {@code value} parameter must follow the format of the {@code Set-Cookie} HTTP
* response header defined by
* <a href="https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-03">RFC6265bis</a>.
* This is a key-value pair of the form {@code "key=value"}, optionally followed by a list of
* cookie attributes delimited with semicolons (ex. {@code "key=value; Max-Age=123"}). Please
* consult the RFC specification for a list of valid attributes.
*
* <p class="note"><b>Note:</b> if specifying a {@code value} containing the {@code "Secure"}
* attribute, {@code url} must use the {@code "https://"} scheme.
*
* @param url the URL for which the cookie is to be set
* @param value the cookie as a string, using the format of the 'Set-Cookie'
* HTTP response header
*/
public abstract void setCookie(String url, String value);
/**
* Sets a single cookie (key-value pair) for the given URL. Any existing cookie with the same
* host, path and name will be replaced with the new cookie. The cookie being set
* will be ignored if it is expired. To set multiple cookies, your application should invoke
* this method multiple times.
*
* <p>The {@code value} parameter must follow the format of the {@code Set-Cookie} HTTP
* response header defined by
* <a href="https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-03">RFC6265bis</a>.
* This is a key-value pair of the form {@code "key=value"}, optionally followed by a list of
* cookie attributes delimited with semicolons (ex. {@code "key=value; Max-Age=123"}). Please
* consult the RFC specification for a list of valid attributes.
*
* <p>This method is asynchronous. If a {@link ValueCallback} is provided,
* {@link ValueCallback#onReceiveValue} will be called on the current
* thread's {@link android.os.Looper} once the operation is complete.
* The value provided to the callback indicates whether the cookie was set successfully.
* You can pass {@code null} as the callback if you don't need to know when the operation
* completes or whether it succeeded, and in this case it is safe to call the method from a
* thread without a Looper.
*
* <p class="note"><b>Note:</b> if specifying a {@code value} containing the {@code "Secure"}
* attribute, {@code url} must use the {@code "https://"} scheme.
*
* @param url the URL for which the cookie is to be set
* @param value the cookie as a string, using the format of the 'Set-Cookie'
* HTTP response header
* @param callback a callback to be executed when the cookie has been set
*/
public abstract void setCookie(String url, String value, @Nullable ValueCallback<Boolean>
callback);
/**
* Gets all the cookies for the given URL. This may return multiple key-value pairs if multiple
* cookies are associated with this URL, in which case each cookie will be delimited by {@code
* "; "} characters (semicolon followed by a space). Each key-value pair will be of the form
* {@code "key=value"}.
*
* @param url the URL for which the cookies are requested
* @return value the cookies as a string, using the format of the 'Cookie'
* HTTP request header
*/
public abstract String getCookie(String url);
/**
* Removes all session cookies, which are cookies without an expiration
* date.
* @deprecated use {@link #removeSessionCookies(ValueCallback)} instead.
*/
@Deprecated
public abstract void removeSessionCookie();
/**
* Removes all session cookies, which are cookies without an expiration
* date.
* <p>
* This method is asynchronous.
* If a {@link ValueCallback} is provided,
* {@link ValueCallback#onReceiveValue(Object)} will be called on the current
* thread's {@link android.os.Looper} once the operation is complete.
* The value provided to the callback indicates whether any cookies were removed.
* You can pass {@code null} as the callback if you don't need to know when the operation
* completes or whether any cookie were removed, and in this case it is safe to call the
* method from a thread without a Looper.
* @param callback a callback which is executed when the session cookies have been removed
*/
public abstract void removeSessionCookies(@Nullable ValueCallback<Boolean> callback);
/**
* Removes all cookies.
* @deprecated Use {@link #removeAllCookies(ValueCallback)} instead.
*/
@Deprecated
public abstract void removeAllCookie();
/**
* Removes all cookies.
* <p>
* This method is asynchronous.
* If a {@link ValueCallback} is provided,
* {@link ValueCallback#onReceiveValue(Object)} will be called on the current
* thread's {@link android.os.Looper} once the operation is complete.
* The value provided to the callback indicates whether any cookies were removed.
* You can pass {@code null} as the callback if you don't need to know when the operation
* completes or whether any cookies were removed, and in this case it is safe to call the
* method from a thread without a Looper.
* @param callback a callback which is executed when the cookies have been removed
*/
public abstract void removeAllCookies(@Nullable ValueCallback<Boolean> callback);
/**
* Gets whether there are stored cookies.
*
* @return {@code true} if there are stored cookies
*/
public abstract boolean hasCookies();
/**
* Removes all expired cookies.
* @deprecated The WebView handles removing expired cookies automatically.
*/
@Deprecated
public abstract void removeExpiredCookie();
/**
* Ensures all cookies currently accessible through the getCookie API are
* written to persistent storage.
* This call will block the caller until it is done and may perform I/O.
*/
public abstract void flush();
/**
* Gets whether the application's {@link WebView} instances send and accept
* cookies for file scheme URLs.
*
* @return {@code true} if {@link WebView} instances send and accept cookies for
* file scheme URLs
*/
// Static for backward compatibility.
public static boolean allowFileSchemeCookies() {
return getInstance().allowFileSchemeCookiesImpl();
}
public abstract boolean allowFileSchemeCookiesImpl();
/**
* Sets whether the application's {@link WebView} instances should send and accept cookies for
* file scheme URLs.
* <p>
* Use of cookies with file scheme URLs is potentially insecure and turned off by default. All
* {@code file://} URLs share all their cookies, which may lead to leaking private app cookies
* (ex. any malicious file can access cookies previously set by other (trusted) files).
* <p class="note">
* Loading content via {@code file://} URLs is generally discouraged. See the note in
* {@link WebSettings#setAllowFileAccess}.
* Using <a href="{@docRoot}reference/androidx/webkit/WebViewAssetLoader.html">
* androidx.webkit.WebViewAssetLoader</a> to load files over {@code http(s)://} URLs allows
* the standard web security model to be used for setting and sharing cookies for local files.
* <p>
* Note that calls to this method will have no effect if made after calling other
* {@link CookieManager} APIs.
*
* @deprecated This setting is not secure, please use
* <a href="{@docRoot}reference/androidx/webkit/WebViewAssetLoader.html">
* androidx.webkit.WebViewAssetLoader</a> instead.
*/
// Static for backward compatibility.
@Deprecated
public static void setAcceptFileSchemeCookies(boolean accept) {
getInstance().setAcceptFileSchemeCookiesImpl(accept);
}
public abstract void setAcceptFileSchemeCookiesImpl(boolean accept);
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@file:Suppress("NOTHING_TO_INLINE") // Aliases to public API.
package androidx.core.net
import android.net.Uri
import java.io.File
/**
* Creates a Uri from the given encoded URI string.
*
* @see Uri.parse
*/
public inline fun String.toUri(): Uri = Uri.parse(this)
/**
* Creates a Uri from the given file.
*
* @see Uri.fromFile
*/
public inline fun File.toUri(): Uri = Uri.fromFile(this)
/**
* Creates a [File] from the given [Uri]. Note that this will throw an
* [IllegalArgumentException] when invoked on a [Uri] that lacks `file` scheme.
*/
public fun Uri.toFile(): File {
require(scheme == "file") { "Uri lacks 'file' scheme: $this" }
return File(requireNotNull(path) { "Uri path is null: $this" })
}

View File

@@ -13,33 +13,49 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
import java.util.Set;
public class MultiSelectListPreference extends DialogPreference {
// reference: https://android.googlesource.com/platform/frameworks/support/+/996971f962fcd554339a7cb2859cef9ca89dbcb7/preference/preference/src/main/java/androidx/preference/MultiSelectListPreference.java
// Note: remove @JsonIgnore and implement methods if any extension ever uses these methods or the variables behind them
public MultiSelectListPreference(Context context) { super(context); }
private CharSequence[] entries;
private CharSequence[] entryValues;
public MultiSelectListPreference(Context context) {
super(context);
}
public void setEntries(CharSequence[] entries) {
this.entries = entries;
}
public CharSequence[] getEntries() {
return entries;
}
public void setEntryValues(CharSequence[] entryValues) {
this.entryValues = entryValues;
}
public CharSequence[] getEntryValues() {
return entryValues;
}
@JsonIgnore
public void setEntries(CharSequence[] entries) { throw new RuntimeException("Stub!"); }
public void setValues(Set<String> values) {
throw new RuntimeException("Stub!");
}
@JsonIgnore
public CharSequence[] getEntries() { throw new RuntimeException("Stub!"); }
public Set<String> getValues() {
throw new RuntimeException("Stub!");
}
@JsonIgnore
public void setEntryValues(CharSequence[] entryValues) { throw new RuntimeException("Stub!"); }
@JsonIgnore
public CharSequence[] getEntryValues() { throw new RuntimeException("Stub!"); }
@JsonIgnore
public void setValues(Set<String> values) { throw new RuntimeException("Stub!"); }
@JsonIgnore
public Set<String> getValues() { throw new RuntimeException("Stub!"); }
public int findIndexOfValue(String value) { throw new RuntimeException("Stub!"); }
public int findIndexOfValue(String value) {
throw new RuntimeException("Stub!");
}
/** Tachidesk specific API */
@Override
public String getDefaultValueType() {
return "Set";
return "Set<String>";
}
}

View File

@@ -10,6 +10,7 @@ package androidx.preference;
import android.content.Context;
import android.content.SharedPreferences;
import com.fasterxml.jackson.annotation.JsonIgnore;
import java.util.Set;
/**
* A minimal implementation of androidx.preference.Preference
@@ -21,6 +22,7 @@ public class Preference {
@JsonIgnore
protected Context context;
private boolean isVisible;
private String key;
private CharSequence title;
private CharSequence summary;
@@ -99,6 +101,14 @@ public class Preference {
return sharedPreferences;
}
public void setVisible(boolean visible) {
isVisible = visible;
}
public boolean getVisible() {
return isVisible;
}
/** Tachidesk specific API */
public void setSharedPreferences(SharedPreferences sharedPreferences) {
this.sharedPreferences = sharedPreferences;
@@ -113,18 +123,22 @@ public class Preference {
}
/** Tachidesk specific API */
@SuppressWarnings("unchecked")
public Object getCurrentValue() {
switch (getDefaultValueType()) {
case "String":
return sharedPreferences.getString(key, (String)defaultValue);
case "Boolean":
return sharedPreferences.getBoolean(key, (Boolean)defaultValue);
case "Set<String>":
return sharedPreferences.getStringSet(key, (Set<String>)defaultValue);
default:
throw new RuntimeException("Unsupported type");
}
}
/** Tachidesk specific API */
@SuppressWarnings("unchecked")
public void saveNewValue(Object value) {
switch (getDefaultValueType()) {
case "String":
@@ -133,6 +147,9 @@ public class Preference {
case "Boolean":
sharedPreferences.edit().putBoolean(key, (Boolean)value).apply();
break;
case "Set<String>":
sharedPreferences.edit().putStringSet(key, (Set<String>)value).apply();
break;
default:
throw new RuntimeException("Unsupported type");
}

View File

@@ -13,7 +13,10 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
public class TwoStatePreference extends Preference {
// Note: remove @JsonIgnore and implement methods if any extension ever uses these methods or the variables behind them
public TwoStatePreference(Context context) { super(context); }
public TwoStatePreference(Context context) {
super(context);
setDefaultValue(false);
}
@JsonIgnore
public boolean isChecked() { throw new RuntimeException("Stub!"); }

View File

@@ -0,0 +1,69 @@
package app.cash.quickjs;
import org.mozilla.javascript.ConsString;
import org.mozilla.javascript.NativeArray;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import java.io.Closeable;
public final class QuickJs implements Closeable {
private ScriptEngine engine;
public static QuickJs create() {
return new QuickJs(new ScriptEngineManager());
}
public QuickJs(ScriptEngineManager manager) {
this.engine = manager.getEngineByName("rhino");
}
public Object evaluate(String script, String fileName) {
return this.evaluate(script);
}
public Object evaluate(String script) {
try {
Object value = engine.eval(script);
return translateType(value);
} catch (Exception exception) {
throw new QuickJsException(exception.getMessage(), exception);
}
}
private Object translateType(Object obj) {
if (obj instanceof NativeArray) {
NativeArray array = (NativeArray) obj;
long length = array.getLength();
Object[] objects = new Object[(int) length];
for (int i = 0; i < (int) length; i++) {
objects[i] = translateType(array.get(i));
}
return objects;
}
if (obj instanceof ConsString) {
ConsString consString = (ConsString) obj;
return consString.toString();
}
if (obj instanceof Long) {
Long value = (Long) obj;
return value.intValue();
}
return obj;
}
public byte[] compile(String sourceCode, String fileName) {
return sourceCode.getBytes();
}
public Object execute(byte[] bytecode) {
return this.evaluate(new String(bytecode));
}
@Override
public void close() {
this.engine = null;
}
}

View File

@@ -0,0 +1,7 @@
package app.cash.quickjs;
public final class QuickJsException extends RuntimeException {
public QuickJsException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@@ -14,9 +14,10 @@
* limitations under the License.
*/
package com.android.internal.util;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -25,19 +26,14 @@ import android.util.Xml;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ProtocolException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.*;
/** {@hide} */
public class XmlUtils {
private static final String STRING_ARRAY_SEPARATOR = ":";
@@ -1396,9 +1392,9 @@ public class XmlUtils {
} else if (tagName.equals("long")) {
return Long.valueOf(parser.getAttributeValue(null, "value"));
} else if (tagName.equals("float")) {
return new Float(parser.getAttributeValue(null, "value"));
return Float.valueOf(parser.getAttributeValue(null, "value"));
} else if (tagName.equals("double")) {
return new Double(parser.getAttributeValue(null, "value"));
return Double.valueOf(parser.getAttributeValue(null, "value"));
} else if (tagName.equals("boolean")) {
return Boolean.valueOf(parser.getAttributeValue(null, "value"));
} else {

View File

@@ -5,4 +5,4 @@ import android.arch.persistence.db.framework.FrameworkSQLiteOpenHelperFactory
class RequerySQLiteOpenHelperFactory {
fun create(configuration: SupportSQLiteOpenHelper.Configuration) = FrameworkSQLiteOpenHelperFactory().create(configuration)
}
}

View File

@@ -7,11 +7,10 @@ import org.kodein.di.instance
import xyz.nulldev.androidcompat.androidimpl.CustomContext
class AndroidCompat {
val context: CustomContext by DI.global.instance()
fun startApp(application: Application) {
application.attach(context)
application.onCreate()
}
}
}

View File

@@ -14,14 +14,17 @@ class AndroidCompatInitializer {
fun init() {
DI.global.addImport(AndroidCompatModule().create())
//Register config modules
// Register config modules
GlobalConfigManager.registerModules(
FilesConfigModule.register(GlobalConfigManager.config),
ApplicationInfoConfigModule.register(GlobalConfigManager.config),
SystemConfigModule.register(GlobalConfigManager.config)
SystemConfigModule.register(GlobalConfigManager.config),
)
// Set some properties extensions use
System.setProperty("http.agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36")
System.setProperty(
"http.agent",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
)
}
}

View File

@@ -18,22 +18,24 @@ import xyz.nulldev.androidcompat.service.ServiceSupport
*/
class AndroidCompatModule {
fun create() = DI.Module("AndroidCompat") {
bind<AndroidFiles>() with singleton { AndroidFiles() }
fun create() =
DI.Module("AndroidCompat") {
bind<AndroidFiles>() with singleton { AndroidFiles() }
bind<ApplicationInfoImpl>() with singleton { ApplicationInfoImpl() }
bind<ApplicationInfoImpl>() with singleton { ApplicationInfoImpl() }
bind<ServiceSupport>() with singleton { ServiceSupport() }
bind<ServiceSupport>() with singleton { ServiceSupport() }
bind<FakePackageManager>() with singleton { FakePackageManager() }
bind<FakePackageManager>() with singleton { FakePackageManager() }
bind<PackageController>() with singleton { PackageController() }
bind<PackageController>() with singleton { PackageController() }
//Context
bind<CustomContext>() with singleton { CustomContext() }
bind<Context>() with singleton {
val context: Context by DI.global.instance<CustomContext>()
context
// Context
bind<CustomContext>() with singleton { CustomContext() }
bind<Context>() with
singleton {
val context: Context by DI.global.instance<CustomContext>()
context
}
}
}
}

View File

@@ -1,18 +1,18 @@
package xyz.nulldev.androidcompat.config
import com.typesafe.config.Config
import io.github.config4k.getValue
import xyz.nulldev.ts.config.ConfigModule
/**
* Application info config.
*/
class ApplicationInfoConfigModule(config: Config) : ConfigModule(config) {
val packageName = config.getString("packageName")!!
val debug = config.getBoolean("debug")
class ApplicationInfoConfigModule(getConfig: () -> Config) : ConfigModule(getConfig) {
val packageName: String by getConfig()
val debug: Boolean by getConfig()
companion object {
fun register(config: Config)
= ApplicationInfoConfigModule(config.getConfig("android.app"))
fun register(config: Config) = ApplicationInfoConfigModule { config.getConfig("android.app") }
}
}

View File

@@ -1,33 +1,33 @@
package xyz.nulldev.androidcompat.config
import com.typesafe.config.Config
import io.github.config4k.getValue
import xyz.nulldev.ts.config.ConfigModule
/**
* Files configuration modules. Specifies where to store the Android files.
*/
class FilesConfigModule(config: Config) : ConfigModule(config) {
val dataDir = config.getString("dataDir")!!
val filesDir = config.getString("filesDir")!!
val noBackupFilesDir = config.getString("noBackupFilesDir")!!
val externalFilesDirs: MutableList<String> = config.getStringList("externalFilesDirs")!!
val obbDirs: MutableList<String> = config.getStringList("obbDirs")!!
val cacheDir = config.getString("cacheDir")!!
val codeCacheDir = config.getString("codeCacheDir")!!
val externalCacheDirs: MutableList<String> = config.getStringList("externalCacheDirs")!!
val externalMediaDirs: MutableList<String> = config.getStringList("externalMediaDirs")!!
val rootDir = config.getString("rootDir")!!
val externalStorageDir = config.getString("externalStorageDir")!!
val downloadCacheDir = config.getString("downloadCacheDir")!!
val databasesDir = config.getString("databasesDir")!!
class FilesConfigModule(getConfig: () -> Config) : ConfigModule(getConfig) {
val dataDir: String by getConfig()
val filesDir: String by getConfig()
val noBackupFilesDir: String by getConfig()
val externalFilesDirs: MutableList<String> by getConfig()
val obbDirs: MutableList<String> by getConfig()
val cacheDir: String by getConfig()
val codeCacheDir: String by getConfig()
val externalCacheDirs: MutableList<String> by getConfig()
val externalMediaDirs: MutableList<String> by getConfig()
val rootDir: String by getConfig()
val externalStorageDir: String by getConfig()
val downloadCacheDir: String by getConfig()
val databasesDir: String by getConfig()
val prefsDir = config.getString("prefsDir")!!
val prefsDir: String by getConfig()
val packageDir = config.getString("packageDir")!!
val packageDir: String by getConfig()
companion object {
fun register(config: Config)
= FilesConfigModule(config.getConfig("android.files"))
fun register(config: Config) = FilesConfigModule { config.getConfig("android.files") }
}
}
}

View File

@@ -1,21 +1,25 @@
package xyz.nulldev.androidcompat.config
import com.typesafe.config.Config
import io.github.config4k.getValue
import xyz.nulldev.ts.config.ConfigModule
class SystemConfigModule(val config: Config) : ConfigModule(config) {
val isDebuggable = config.getBoolean("isDebuggable")
class SystemConfigModule(val getConfig: () -> Config) : ConfigModule(getConfig) {
val isDebuggable: Boolean by getConfig()
val propertyPrefix = "properties."
fun getStringProperty(property: String) = config.getString("$propertyPrefix$property")!!
fun getIntProperty(property: String) = config.getInt("$propertyPrefix$property")
fun getLongProperty(property: String) = config.getLong("$propertyPrefix$property")
fun getBooleanProperty(property: String) = config.getBoolean("$propertyPrefix$property")
fun hasProperty(property: String) = config.hasPath("$propertyPrefix$property")
fun getStringProperty(property: String) = getConfig().getString("$propertyPrefix$property")!!
fun getIntProperty(property: String) = getConfig().getInt("$propertyPrefix$property")
fun getLongProperty(property: String) = getConfig().getLong("$propertyPrefix$property")
fun getBooleanProperty(property: String) = getConfig().getBoolean("$propertyPrefix$property")
fun hasProperty(property: String) = getConfig().hasPath("$propertyPrefix$property")
companion object {
fun register(config: Config)
= SystemConfigModule(config.getConfig("android.system"))
fun register(config: Config) = SystemConfigModule { config.getConfig("android.system") }
}
}

View File

@@ -9,30 +9,77 @@ package xyz.nulldev.androidcompat.io.sharedprefs
import android.content.SharedPreferences
import com.russhwolf.settings.ExperimentalSettingsApi
import com.russhwolf.settings.ExperimentalSettingsImplementation
import com.russhwolf.settings.JvmPreferencesSettings
import com.russhwolf.settings.PropertiesSettings
import com.russhwolf.settings.Settings
import com.russhwolf.settings.serialization.decodeValue
import com.russhwolf.settings.serialization.decodeValueOrNull
import com.russhwolf.settings.serialization.encodeValue
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.SerializationException
import kotlinx.serialization.builtins.SetSerializer
import kotlinx.serialization.builtins.nullable
import kotlinx.serialization.builtins.serializer
import java.util.prefs.PreferenceChangeListener
import java.util.prefs.Preferences
import mu.KotlinLogging
import xyz.nulldev.androidcompat.util.SafePath
import xyz.nulldev.ts.config.ApplicationRootDir
import java.util.Properties
import kotlin.io.path.Path
import kotlin.io.path.createParentDirectories
import kotlin.io.path.deleteIfExists
import kotlin.io.path.exists
import kotlin.io.path.inputStream
import kotlin.io.path.outputStream
@OptIn(ExperimentalSettingsImplementation::class, ExperimentalSerializationApi::class, ExperimentalSettingsApi::class)
@OptIn(ExperimentalSerializationApi::class, ExperimentalSettingsApi::class)
class JavaSharedPreferences(key: String) : SharedPreferences {
private val javaPreferences = Preferences.userRoot().node("suwayomi/tachidesk/$key")
private val preferences = JvmPreferencesSettings(javaPreferences)
private val listeners = mutableMapOf<SharedPreferences.OnSharedPreferenceChangeListener, PreferenceChangeListener>()
companion object {
private val logger = KotlinLogging.logger {}
}
private val file =
Path(
ApplicationRootDir,
"settings",
"${SafePath.buildValidFilename(key)}.xml",
)
private val properties =
Properties().also { properties ->
try {
if (file.exists()) {
file.inputStream().use { properties.loadFromXML(it) }
}
} catch (e: Exception) {
logger.error(e) { "Error loading settings from $key" }
}
}
private val preferences =
PropertiesSettings(
properties,
onModify = { properties ->
try {
if (properties.isEmpty) {
file.deleteIfExists()
} else {
file.createParentDirectories()
file.outputStream().use {
properties.storeToXML(it, null)
}
}
} catch (e: Exception) {
logger.error(e) { "Error saving settings in $key" }
}
},
)
private val listeners = mutableMapOf<SharedPreferences.OnSharedPreferenceChangeListener, (String) -> Unit>()
// TODO: 2021-05-29 Need to find a way to get this working with all pref types
override fun getAll(): MutableMap<String, *> {
return preferences.keys.associateWith { preferences.getStringOrNull(it) }.toMutableMap()
}
override fun getString(key: String, defValue: String?): String? {
override fun getString(
key: String,
defValue: String?,
): String? {
return if (defValue != null) {
preferences.getString(key, defValue)
} else {
@@ -40,31 +87,46 @@ class JavaSharedPreferences(key: String) : SharedPreferences {
}
}
override fun getStringSet(key: String, defValues: MutableSet<String>?): MutableSet<String>? {
override fun getStringSet(
key: String,
defValues: Set<String>?,
): Set<String>? {
try {
return if (defValues != null) {
preferences.decodeValue(SetSerializer(String.serializer()).nullable, key, defValues)
preferences.decodeValue(SetSerializer(String.serializer()), key, defValues)
} else {
preferences.decodeValue(SetSerializer(String.serializer()).nullable, key, null)
}?.toMutableSet()
preferences.decodeValueOrNull(SetSerializer(String.serializer()), key)
}
} catch (e: SerializationException) {
throw ClassCastException("$key was not a StringSet")
}
}
override fun getInt(key: String, defValue: Int): Int {
override fun getInt(
key: String,
defValue: Int,
): Int {
return preferences.getInt(key, defValue)
}
override fun getLong(key: String, defValue: Long): Long {
override fun getLong(
key: String,
defValue: Long,
): Long {
return preferences.getLong(key, defValue)
}
override fun getFloat(key: String, defValue: Float): Float {
override fun getFloat(
key: String,
defValue: Float,
): Float {
return preferences.getFloat(key, defValue)
}
override fun getBoolean(key: String, defValue: Boolean): Boolean {
override fun getBoolean(
key: String,
defValue: Boolean,
): Boolean {
return preferences.getBoolean(key, defValue)
}
@@ -73,60 +135,86 @@ class JavaSharedPreferences(key: String) : SharedPreferences {
}
override fun edit(): SharedPreferences.Editor {
return Editor(preferences)
return Editor(preferences) { key ->
listeners.forEach { (_, listener) ->
listener(key)
}
}
}
class Editor(private val preferences: JvmPreferencesSettings) : SharedPreferences.Editor {
val itemsToAdd = mutableMapOf<String, Any>()
class Editor(private val preferences: Settings, private val notify: (String) -> Unit) : SharedPreferences.Editor {
private val actions = mutableListOf<Action>()
override fun putString(key: String, value: String?): SharedPreferences.Editor {
private sealed class Action {
data class Add(val key: String, val value: Any) : Action()
data class Remove(val key: String) : Action()
data object Clear : Action()
}
override fun putString(
key: String,
value: String?,
): SharedPreferences.Editor {
if (value != null) {
itemsToAdd[key] = value
actions += Action.Add(key, value)
} else {
remove(key)
actions += Action.Remove(key)
}
return this
}
override fun putStringSet(
key: String,
values: MutableSet<String>?
values: MutableSet<String>?,
): SharedPreferences.Editor {
if (values != null) {
itemsToAdd[key] = values
actions += Action.Add(key, values)
} else {
remove(key)
actions += Action.Remove(key)
}
return this
}
override fun putInt(key: String, value: Int): SharedPreferences.Editor {
itemsToAdd[key] = value
override fun putInt(
key: String,
value: Int,
): SharedPreferences.Editor {
actions += Action.Add(key, value)
return this
}
override fun putLong(key: String, value: Long): SharedPreferences.Editor {
itemsToAdd[key] = value
override fun putLong(
key: String,
value: Long,
): SharedPreferences.Editor {
actions += Action.Add(key, value)
return this
}
override fun putFloat(key: String, value: Float): SharedPreferences.Editor {
itemsToAdd[key] = value
override fun putFloat(
key: String,
value: Float,
): SharedPreferences.Editor {
actions += Action.Add(key, value)
return this
}
override fun putBoolean(key: String, value: Boolean): SharedPreferences.Editor {
itemsToAdd[key] = value
override fun putBoolean(
key: String,
value: Boolean,
): SharedPreferences.Editor {
actions += Action.Add(key, value)
return this
}
override fun remove(key: String): SharedPreferences.Editor {
itemsToAdd.remove(key)
actions += Action.Remove(key)
return this
}
override fun clear(): SharedPreferences.Editor {
itemsToAdd.clear()
actions.add(Action.Clear)
return this
}
@@ -140,38 +228,56 @@ class JavaSharedPreferences(key: String) : SharedPreferences {
}
private fun addToPreferences() {
itemsToAdd.forEach { (key, value) ->
actions.forEach {
@Suppress("UNCHECKED_CAST")
when (value) {
is Set<*> -> preferences.encodeValue(SetSerializer(String.serializer()), key, value as Set<String>)
is String -> preferences.putString(key, value)
is Int -> preferences.putInt(key, value)
is Long -> preferences.putLong(key, value)
is Float -> preferences.putFloat(key, value)
is Double -> preferences.putDouble(key, value)
is Boolean -> preferences.putBoolean(key, value)
when (it) {
is Action.Add -> {
when (val value = it.value) {
is Set<*> -> preferences.encodeValue(SetSerializer(String.serializer()), it.key, value as Set<String>)
is String -> preferences.putString(it.key, value)
is Int -> preferences.putInt(it.key, value)
is Long -> preferences.putLong(it.key, value)
is Float -> preferences.putFloat(it.key, value)
is Double -> preferences.putDouble(it.key, value)
is Boolean -> preferences.putBoolean(it.key, value)
}
notify(it.key)
}
is Action.Remove -> {
preferences.remove(it.key)
/**
* Set<String> are stored like
* key.0 = value1
* key.1 = value2
* key.size = 2
*/
preferences.keys.forEach { key ->
if (key.startsWith(it.key + ".")) {
preferences.remove(key)
}
}
notify(it.key)
}
Action.Clear -> preferences.clear()
}
}
}
}
override fun registerOnSharedPreferenceChangeListener(listener: SharedPreferences.OnSharedPreferenceChangeListener) {
val javaListener = PreferenceChangeListener {
listener.onSharedPreferenceChanged(this, it.key)
val javaListener: (String) -> Unit = {
listener.onSharedPreferenceChanged(this, it)
}
listeners[listener] = javaListener
javaPreferences.addPreferenceChangeListener(javaListener)
}
override fun unregisterOnSharedPreferenceChangeListener(listener: SharedPreferences.OnSharedPreferenceChangeListener) {
val registeredListener = listeners.remove(listener)
if (registeredListener != null) {
javaPreferences.removePreferenceChangeListener(registeredListener)
}
listeners.remove(listener)
}
fun deleteAll(): Boolean {
javaPreferences.removeNode()
preferences.clear()
return true
}
}
}

View File

@@ -14,44 +14,51 @@ import java.io.File
import javax.imageio.ImageIO
import javax.xml.parsers.DocumentBuilderFactory
data class InstalledPackage(val root: File) {
val apk = File(root, "package.apk")
val jar = File(root, "translated.jar")
val icon = File(root, "icon.png")
val info: PackageInfo
get() = ApkParsers.getMetaInfo(apk).toPackageInfo(apk).also {
val parsed = ApkFile(apk)
val dbFactory = DocumentBuilderFactory.newInstance()
val dBuilder = dbFactory.newDocumentBuilder()
val doc = parsed.manifestXml.byteInputStream().use {
dBuilder.parse(it)
get() =
ApkParsers.getMetaInfo(apk).toPackageInfo(apk).also {
val parsed = ApkFile(apk)
val dbFactory = DocumentBuilderFactory.newInstance()
val dBuilder = dbFactory.newDocumentBuilder()
val doc =
parsed.manifestXml.byteInputStream().use {
dBuilder.parse(it)
}
it.applicationInfo.metaData =
Bundle().apply {
val appTag = doc.getElementsByTagName("application").item(0)
appTag?.childNodes?.toList()?.filter {
it.nodeType == Node.ELEMENT_NODE
}?.map {
it as Element
}?.filter {
it.tagName == "meta-data"
}?.map {
putString(
it.attributes.getNamedItem("android:name").nodeValue,
it.attributes.getNamedItem("android:value").nodeValue,
)
}
}
it.signatures =
(
parsed.apkSingers.flatMap { it.certificateMetas }
// + parsed.apkV2Singers.flatMap { it.certificateMetas }
) // Blocked by: https://github.com/hsiafan/apk-parser/issues/72
.map { Signature(it.data) }.toTypedArray()
}
it.applicationInfo.metaData = Bundle().apply {
val appTag = doc.getElementsByTagName("application").item(0)
appTag?.childNodes?.toList()?.filter {
it.nodeType == Node.ELEMENT_NODE
}?.map {
it as Element
}?.filter {
it.tagName == "meta-data"
}?.map {
putString(it.attributes.getNamedItem("android:name").nodeValue,
it.attributes.getNamedItem("android:value").nodeValue)
}
}
it.signatures = (parsed.apkSingers.flatMap { it.certificateMetas }
/*+ parsed.apkV2Singers.flatMap { it.certificateMetas }*/) // Blocked by: https://github.com/hsiafan/apk-parser/issues/72
.map { Signature(it.data) }.toTypedArray()
}
fun verify(): Boolean {
val res = ApkVerifier.Builder(apk)
val res =
ApkVerifier.Builder(apk)
.build()
.verify()
@@ -62,14 +69,15 @@ data class InstalledPackage(val root: File) {
try {
val icons = ApkFile(apk).allIcons
val read = icons.filter { it.isFile }.map {
it.data.inputStream().use {
ImageIO.read(it)
}
}.sortedByDescending { it.width * it.height }.firstOrNull() ?: return
val read =
icons.filter { it.isFile }.map {
it.data.inputStream().use {
ImageIO.read(it)
}
}.sortedByDescending { it.width * it.height }.firstOrNull() ?: return
ImageIO.write(read, "png", icon)
} catch(e: Exception) {
} catch (e: Exception) {
icon.delete()
}
}
@@ -77,7 +85,7 @@ data class InstalledPackage(val root: File) {
fun writeJar() {
try {
Dex2jar.from(apk).to(jar.toPath())
} catch(e: Exception) {
} catch (e: Exception) {
jar.delete()
}
}
@@ -92,4 +100,4 @@ data class InstalledPackage(val root: File) {
return out
}
}
}
}

View File

@@ -25,7 +25,10 @@ class PackageController {
return File(androidFiles.packagesDir, pn)
}
fun installPackage(apk: File, allowReinstall: Boolean) {
fun installPackage(
apk: File,
allowReinstall: Boolean,
) {
val root = findRoot(apk)
if (root.exists()) {
@@ -48,7 +51,7 @@ class PackageController {
if (!installed.jar.exists()) {
throw IllegalStateException("Failed to translate APK dex!")
}
} catch(t: Throwable) {
} catch (t: Throwable) {
root.deleteRecursively()
throw t
}
@@ -63,7 +66,7 @@ class PackageController {
}
fun deletePackage(pack: InstalledPackage) {
if(!pack.root.exists()) error("Package was never installed!")
if (!pack.root.exists()) error("Package was never installed!")
val packageName = pack.info.packageName
pack.root.deleteRecursively()
@@ -74,14 +77,15 @@ class PackageController {
fun findPackage(packageName: String): InstalledPackage? {
val file = File(androidFiles.packagesDir, packageName)
return if(file.exists())
return if (file.exists()) {
InstalledPackage(file)
else
} else {
null
}
}
fun findJarFromApk(apkFile: File): File? {
val pkgName = ApkParsers.getMetaInfo(apkFile).packageName
return findPackage(pkgName)?.jar
}
}
}

View File

@@ -12,16 +12,18 @@ fun ApkMeta.toPackageInfo(apk: File): PackageInfo {
it.versionCode = versionCode.toInt()
it.versionName = versionName
it.reqFeatures = usesFeatures.map {
FeatureInfo().apply {
name = it.name
}
}.toTypedArray()
it.reqFeatures =
usesFeatures.map {
FeatureInfo().apply {
name = it.name
}
}.toTypedArray()
it.applicationInfo = ApplicationInfo().apply {
packageName = it.packageName
nonLocalizedLabel = label
sourceDir = apk.absolutePath
}
it.applicationInfo =
ApplicationInfo().apply {
packageName = it.packageName
nonLocalizedLabel = label
sourceDir = apk.absolutePath
}
}
}
}

View File

@@ -24,4 +24,4 @@ interface Resource {
fun getType(): Class<out Resource>
fun getValue(): Any?
}
}

View File

@@ -18,7 +18,10 @@ class ServiceSupport {
private val logger = KotlinLogging.logger {}
fun startService(@Suppress("UNUSED_PARAMETER") context: Context, intent: Intent) {
fun startService(
@Suppress("UNUSED_PARAMETER") context: Context,
intent: Intent,
) {
val name = intentToClassName(intent)
logger.debug { "Starting service: $name" }
@@ -27,15 +30,18 @@ class ServiceSupport {
runningServices[name] = service
//Setup service
// Setup service
thread {
callOnCreate(service)
//TODO Handle more complex cases
// TODO Handle more complex cases
service.onStartCommand(intent, 0, 0)
}
}
fun stopService(@Suppress("UNUSED_PARAMETER") context: Context, intent: Intent) {
fun stopService(
@Suppress("UNUSED_PARAMETER") context: Context,
intent: Intent,
) {
val name = intentToClassName(intent)
stopService(name)
}
@@ -43,7 +49,7 @@ class ServiceSupport {
fun stopService(name: String) {
logger.debug { "Stopping service: $name" }
val service = runningServices.remove(name)
if(service == null) {
if (service == null) {
logger.warn { "An attempt was made to stop a service that is not running: $name" }
} else {
thread {
@@ -63,6 +69,6 @@ class ServiceSupport {
fun serviceInstanceFromClass(className: String): Service {
val clazzObj = Class.forName(className)
return clazzObj.getDeclaredConstructor().newInstance() as? Service
?: throw IllegalArgumentException("$className is not a Service!")
?: throw IllegalArgumentException("$className is not a Service!")
}
}

View File

@@ -26,8 +26,11 @@ object KodeinGlobalHelper {
*/
@JvmStatic
@Suppress("UNCHECKED_CAST")
fun <T : Any> instance(type: Class<T>, kodein: DI? = null): T {
return when(type) {
fun <T : Any> instance(
type: Class<T>,
kodein: DI? = null,
): T {
return when (type) {
AndroidFiles::class.java -> {
val instance: AndroidFiles by (kodein ?: kodein()).instance()
instance as T
@@ -64,5 +67,4 @@ object KodeinGlobalHelper {
fun <T : Any> instance(type: Class<T>): T {
return instance(type, null)
}
}

View File

@@ -1,4 +1,4 @@
package suwayomi.tachidesk.manga.impl.util.storage
package xyz.nulldev.androidcompat.util
/*
* Copyright (C) Contributors to the Suwayomi project

View File

@@ -24,5 +24,7 @@ import java.net.URI
* Utilites to convert between Java and Android Uris.
*/
fun Uri.java() = URI(this.toString())
fun Uri.file() = File(this.path)
fun URI.android() = Uri.parse(this.toString())!!

View File

@@ -0,0 +1,103 @@
package xyz.nulldev.androidcompat.webkit
import android.webkit.CookieManager
import android.webkit.ValueCallback
import android.webkit.WebView
import java.net.CookieHandler
import java.net.HttpCookie
import java.net.URI
@Suppress("DEPRECATION")
class CookieManagerImpl : CookieManager() {
private val cookieHandler = CookieHandler.getDefault() as java.net.CookieManager
private var acceptCookie = true
private var acceptThirdPartyCookies = true
private var allowFileSchemeCookies = false
override fun setAcceptCookie(accept: Boolean) {
acceptCookie = accept
}
override fun acceptCookie(): Boolean {
return acceptCookie
}
override fun setAcceptThirdPartyCookies(
webview: WebView?,
accept: Boolean,
) {
acceptThirdPartyCookies = accept
}
override fun acceptThirdPartyCookies(webview: WebView?): Boolean {
return acceptThirdPartyCookies
}
override fun setCookie(
url: String,
value: String?,
) {
val uri =
if (url.startsWith("http")) {
URI(url)
} else {
URI("http://$url")
}
HttpCookie.parse(value).forEach {
cookieHandler.cookieStore.add(uri, it)
}
}
override fun setCookie(
url: String,
value: String?,
callback: ValueCallback<Boolean>?,
) {
setCookie(url, value)
callback?.onReceiveValue(true)
}
override fun getCookie(url: String): String {
val uri =
if (url.startsWith("http")) {
URI(url)
} else {
URI("http://$url")
}
return cookieHandler.cookieStore.get(uri)
.joinToString("; ") { "${it.name}=${it.value}" }
}
@Deprecated("Deprecated in Java")
override fun removeSessionCookie() {}
override fun removeSessionCookies(callback: ValueCallback<Boolean>?) {}
@Deprecated("Deprecated in Java")
override fun removeExpiredCookie() {}
@Deprecated("Deprecated in Java")
override fun removeAllCookie() {
cookieHandler.cookieStore.removeAll()
}
override fun removeAllCookies(callback: ValueCallback<Boolean>?) {
val removedCookies = cookieHandler.cookieStore.removeAll()
callback?.onReceiveValue(removedCookies)
}
override fun hasCookies(): Boolean {
return cookieHandler.cookieStore.cookies.isNotEmpty()
}
override fun flush() {}
override fun allowFileSchemeCookiesImpl(): Boolean {
return allowFileSchemeCookies
}
override fun setAcceptFileSchemeCookiesImpl(accept: Boolean) {
allowFileSchemeCookies = acceptCookie
}
}

View File

@@ -1,36 +1,12 @@
# AndroidComapt Root dir
androidcompat.rootDir = androidcompat-root
# Allow/disallow preference changes (useful for demos)
ts.server.allowConfigChanges = true
# Enable the WebUI? Note: The API and multi-user sync server ui will remain available even if the WebUI is disabled
ts.server.enableWebUi = true
# 'true' to use the old, buggy/memory-leaking WebUI
ts.server.useOldWebUi = false
# 'true' to pretty print all JSON API responses
ts.server.prettyPrintApi = false
# List of blacklisted/whitelisted API endpoints/operation IDs
ts.server.disabledApiEndpoints = []
ts.server.enabledApiEndpoints = []
# Message to print in the console when the API has finished booting
ts.server.httpInitializedPrintMessage = ""
# Use external folder for static files
ts.server.useExternalStaticFiles = false
ts.server.externalStaticFilesFolder = ""
# Root storage dir
ts.server.rootDir = tachiserver-data
# Dir to store JVM patches
ts.server.patchesDir = ${ts.server.rootDir}/patches
####################### `android.files` (FilesConfigModule) #######################
# Storage dir for the emulated Android app
android.files.rootDir = ${ts.server.rootDir}/android-compat/appdata
android.files.rootDir = ${androidcompat.rootDir}/appdata
# External storage dir for the emulated Android app's
android.files.externalStorageDir = ${ts.server.rootDir}/android-compat/extappdata
android.files.externalStorageDir = ${androidcompat.rootDir}/extappdata
# Internal Android directories
android.files.dataDir = ${android.files.rootDir}/data
@@ -48,37 +24,16 @@ android.files.externalCacheDirs = [${android.files.externalStorageDir}/cache]
android.files.externalMediaDirs = [${android.files.externalStorageDir}/media]
android.files.downloadCacheDir = ${android.files.externalStorageDir}/downloadCache
android.files.packageDir = ${ts.server.rootDir}/android-compat/packages
android.files.packageDir = ${androidcompat.rootDir}/android-compat/packages
####################### `android.app` (ApplicationInfoConfigModule) #######################
# Emulated Android app package name
android.app.packageName = eu.kanade.tachiyomi
# Debug mode for the emulated Android app
android.app.debug = true
####################### `android.system` (SystemConfigModule) #######################
# Whether or not the emulated Android system is debuggable
android.system.isDebuggable = true
# Is the multi-user sync server enabled? Does not affect the single-user sync server included in the API.
ts.syncd.enable = false
# The URL of this server (displayed in the sync server web ui)
ts.syncd.baseUrl = "http://example.com"
# 'true' to disable the API and only enable the multi-user sync server
ts.syncd.syncOnlyMode = false
# The root directory to store synchronized data
ts.syncd.rootDir = ${ts.server.rootDir}/sync/accounts
# Location to store config files for the sandbox
ts.syncd.sandboxedConfig = ${ts.server.rootDir}/sync/sandboxed_config.config
# Recaptcha stuff for signup/login
ts.syncd.recaptcha.siteKey = ""
ts.syncd.recaptcha.secret = ""
# Sync server display name
ts.syncd.name = "Tachiyomi sync server"
# Header used to forward the IP to the multi-user sync server if the server is behind a reverse proxy
ts.syncd.ipHeader = ""

11
CHANGELOG-TEMPLATE.md Normal file
View File

@@ -0,0 +1,11 @@
# Server: v0.X.Y-next + WebUI: rXXX
## TL;DR
- N/A
## Suwayomi-Server Changelog
- N/A
## Suwayomi-WebUI Changelog
- N/A

727
CHANGELOG.md Normal file
View File

@@ -0,0 +1,727 @@
# Server: v0.7.0 + WebUI: r983
## TL;DR
- CBZ downloads support
- Webview implementation based on Microsoft playwright, disabled for this release
- Fixed compatibility with some chinese extensions
- Support for Tachiyomi extensions lib 1.4
- WebUI changes:
- Uhh, idk, find out yourself...
## Suwayomi-Server Changelog
- (r1159) v0.6.6 (by @AriaMoradi)
- (r1160) add Chagelog TL;DR (by @AriaMoradi)
- (r1161) fix Changelog typos (by @AriaMoradi)
- (r1162) WebView based cloudflare interceptor ([#456](https://github.com/Suwayomi/Suwayomi-Server/pull/456) by @AriaMoradi)
- (r1163) update issue mod (by @AriaMoradi)
- (r1164) better description (by @AriaMoradi)
- (r1165) fix regex (by @AriaMoradi)
- (r1166) get default User Agent from WebView ([#457](https://github.com/Suwayomi/Suwayomi-Server/pull/457) by @AriaMoradi)
- (r1167) implementation of android.graphics.BitmapFactory ([#460](https://github.com/Suwayomi/Suwayomi-Server/pull/460) by @animeavi)
- (r1168) Basic android.graphics Rect and Canvas implementation ([#461](https://github.com/Suwayomi/Suwayomi-Server/pull/461) by @animeavi)
- (r1169) Get Playwright working ([#462](https://github.com/Suwayomi/Suwayomi-Server/pull/462) by @Syer10)
- (r1170) disable deb release (by @AriaMoradi)
- (r1171) Fix debian release ([#463](https://github.com/Suwayomi/Suwayomi-Server/pull/463) by @mahor1221)
- (r1172) Add better manga thumbnail handling ([#465](https://github.com/Suwayomi/Suwayomi-Server/pull/465) by @Syer10)
- (r1173) Use extension list fallback if extensions fail to fetch ([#469](https://github.com/Suwayomi/Suwayomi-Server/pull/469) by @Syer10)
- (r1174) fix when playwright fails on providing a UA (by @AriaMoradi)
- (r1175) Update CategoryMetaTable.kt (by @AriaMoradi)
- (r1176) fix CategoryMetaTable reference to CategoryTable ([#473](https://github.com/Suwayomi/Suwayomi-Server/pull/473) by @AriaMoradi)
- (r1177) remove possibly misleading sentence (by @AriaMoradi)
- (r1178) Clarify and Update (by @AriaMoradi)
- (r1179) Clarify and Update (by @AriaMoradi)
- (r1180) link to Tachiyomi section (by @AriaMoradi)
- (r1181) fix typo (by @AriaMoradi)
- (r1182) Improve Gradle Configuration ([#478](https://github.com/Suwayomi/Suwayomi-Server/pull/478) by @Syer10)
- (r1183) Improve Playwright handling ([#479](https://github.com/Suwayomi/Suwayomi-Server/pull/479) by @Syer10)
- (r1184) fix ambiguous reference issue on JDK 13+ (by @AriaMoradi)
- (r1185) update gradle version (by @AriaMoradi)
- (r1186) upgrade dorkbox stuff (by @AriaMoradi)
- (r1187) Fixe Dex2Jar and dorkbox dependency issues ([#487](https://github.com/Suwayomi/Suwayomi-Server/pull/487) by @akabhirav)
- (r1188) Fix logging and update system try ([#488](https://github.com/Suwayomi/Suwayomi-Server/pull/488) by @Syer10)
- (r1189) add support for Extensions Lib 1.4 ([#496](https://github.com/Suwayomi/Suwayomi-Server/pull/496) by @Syer10)
- (r1190) disable playwright for v0.6.7 (by @AriaMoradi)
- (r1191) Decouple Cache and Download behaviour ([#493](https://github.com/Suwayomi/Suwayomi-Server/pull/493) by @akabhirav)
- (r1192) rethink image cache ([#498](https://github.com/Suwayomi/Suwayomi-Server/pull/498) by @AriaMoradi)
- (r1193) fix Page index issues for some providers ([#491](https://github.com/Suwayomi/Suwayomi-Server/pull/491) by @akabhirav)
- (r1194) Download as CBZ ([#490](https://github.com/Suwayomi/Suwayomi-Server/pull/490) by @akabhirav)
- (r1195) re-order config options (by @AriaMoradi)
- (r1196) stop using depricated API (by @AriaMoradi)
## Suwayomi-WebUI Changelog
- (r964) Created a GridLayout enum and updated all locations to use it. ([#208](https://github.com/Suwayomi/Suwayomi-WebUI/pull/208) by @infix)
- (r965) fix library update progress rendering ([#210](https://github.com/Suwayomi/Suwayomi-WebUI/pull/210) by @schroda)
- (r966) Save reader settings per manga in Meta ([#216](https://github.com/Suwayomi/Suwayomi-WebUI/pull/216) by @schroda)
- (r967) make default reader settings changeable ([#217](https://github.com/Suwayomi/Suwayomi-WebUI/pull/217) by @schroda)
- (r968) [#211] Refresh Library after a update ([#212](https://github.com/Suwayomi/Suwayomi-WebUI/pull/212) by @schroda)
- (r969) add logic for metadata migration ([#218](https://github.com/Suwayomi/Suwayomi-WebUI/pull/218) by @schroda)
- (r970) set browser tab title ([#220](https://github.com/Suwayomi/Suwayomi-WebUI/pull/220) by @schroda)
- (r971) Add tooltip containing full manga title to title of manga ([#221](https://github.com/Suwayomi/Suwayomi-WebUI/pull/221) by @schroda)
- (r972) show more detailed upload dates for today and yesterday ([#222](https://github.com/Suwayomi/Suwayomi-WebUI/pull/222) by @schroda)
- (r973) add GitHub action on pushing to run lint ([#224](https://github.com/Suwayomi/Suwayomi-WebUI/pull/224) by @schroda)
- (r974) Ignore filters while searching ([#226](https://github.com/Suwayomi/Suwayomi-WebUI/pull/226) by @schroda)
- (r975) force absolute import path ([#223](https://github.com/Suwayomi/Suwayomi-WebUI/pull/223) by @schroda)
- (r976) add prettier for auto formatting ([#231](https://github.com/Suwayomi/Suwayomi-WebUI/pull/231) by @schroda)
- (r977) Fix import path ([#228](https://github.com/Suwayomi/Suwayomi-WebUI/pull/228) by @schroda)
- (r978) increase prettier line length to 120 ([#233](https://github.com/Suwayomi/Suwayomi-WebUI/pull/233) by @schroda)
- (r979) Add chapter page dropdown ([#230](https://github.com/Suwayomi/Suwayomi-WebUI/pull/230) by @schroda)
- (r980) add chapter dropdown to reader nav bar ([#229](https://github.com/Suwayomi/Suwayomi-WebUI/pull/229) by @schroda)
- (r981) Fix lint error ([#235](https://github.com/Suwayomi/Suwayomi-WebUI/pull/235) by @schroda)
- (r982) Fix reader nav bar scroll to page ([#236](https://github.com/Suwayomi/Suwayomi-WebUI/pull/236) by @schroda)
- (r964) Created a GridLayout enum and updated all locations to use it. ([#208](https://github.com/Suwayomi/Suwayomi-WebUI/pull/208) by @infix)
# Server: v0.6.6 + WebUI: r963
## TL;DR
- Batch actions for chapters
- Improved the downloader
- WebUI changes:
- Support for chapter actions
- a lot of code cleanup
- some bugfixes
## Suwayomi-Server Changelog
- (r1114) fix broken links (by @AriaMoradi)
- (r1115) fix more broken stuff (by @AriaMoradi)
- (r1116) fix more broken stuff (by @AriaMoradi)
- (r1117) fix more broken stuff (by @AriaMoradi)
- (r1118) Update winget.yml ([#393](https://github.com/Suwayomi/Suwayomi-Server/pull/393) by @vedantmgoyal2009)
- (r1119) fix jre path([#396](https://github.com/Suwayomi/Suwayomi-Server/pull/396) by @vedantmgoyal2009)
- (r1120) Fix deb package ([#397](https://github.com/Suwayomi/Suwayomi-Server/pull/397) by @mahor1221)
- (r1121) bump version (by @AriaMoradi)
- (r1122) Update Changelog (by @AriaMoradi)
- (r1123) Add libc++-dev ([#405](https://github.com/Suwayomi/Suwayomi-Server/pull/405) by @mahor1221)
- (r1124) Revert back to correct way of handling jre_dir ([#408](https://github.com/Suwayomi/Suwayomi-Server/pull/408) by @mahor1221)
- (r1125) Update winget.yml ([#410](https://github.com/Suwayomi/Suwayomi-Server/pull/410) by @vedantmgoyal2009)
- (r1126) Remove support for Sorayomi web interface ([#414](https://github.com/Suwayomi/Suwayomi-Server/pull/414) by @marcoebbinghaus)
- (r1127) Fix downloader memory leak ([#418](https://github.com/Suwayomi/Suwayomi-Server/pull/418) by @Syer10)
- (r1128) Documentation cleanup ([#417](https://github.com/Suwayomi/Suwayomi-Server/pull/417) by @Syer10)
- (r1129) Updater cleanup and improvements ([#416](https://github.com/Suwayomi/Suwayomi-Server/pull/416) by @Syer10)
- (r1130) replace quickjs with Mozilla Rhino ([#415](https://github.com/Suwayomi/Suwayomi-Server/pull/415) by @xhzhe)
- (r1131) ktlint (by @AriaMoradi)
- (r1132) move Tachiyomi's BuildConfig to kotlin dir (by @AriaMoradi)
- (r1133) remove BuildConfig as extensions now use AppInfo (by @AriaMoradi)
- (r1134) include list of mangas missing source in restore report ([#421](https://github.com/Suwayomi/Suwayomi-Server/pull/421) by @AriaMoradi)
- (r1135) Update dependencies ([#422](https://github.com/Suwayomi/Suwayomi-Server/pull/422) by @Syer10)
- (r1136) Lint ([#423](https://github.com/Suwayomi/Suwayomi-Server/pull/423) by @Syer10)
- (r1137) Fix: Error handling for popular/latest api if pageNum was supplied as zero ([#424](https://github.com/Suwayomi/Suwayomi-Server/pull/424) by @meta-boy)
- (r1138) Add cache control header to manga page response ([#430](https://github.com/Suwayomi/Suwayomi-Server/pull/430) by @martinek)
- (r1139) add MangaTable.lastFetchedAt and ChapterTable.chaptersLastFetchedAt ([#431](https://github.com/Suwayomi/Suwayomi-Server/pull/431) by @martinek)
- (r1140) Pre-load meta entries for all chapters for optimization ([#432](https://github.com/Suwayomi/Suwayomi-Server/pull/432) by @martinek)
- (r1141) POST variant for `/{sourceId}/search` endpoint ([#434](https://github.com/Suwayomi/Suwayomi-Server/pull/434) by @martinek)
- (r1142) Add request body to documentation ([#435](https://github.com/Suwayomi/Suwayomi-Server/pull/435) by @Syer10)
- (r1143) add batch download api ([#436](https://github.com/Suwayomi/Suwayomi-Server/pull/436) by @martinek)
- (r1144) Migrate to H2 v2 (by @AriaMoradi)
- (r1145) add category and global meta ([#438](https://github.com/Suwayomi/Suwayomi-Server/pull/438) by @AriaMoradi)
- (r1146) Revert H2 database to v1 (by @AriaMoradi)
- (r1147) refactor deprecated api (by @AriaMoradi)
- (r1148) Downloader Rewrite ([#437](https://github.com/Suwayomi/Suwayomi-Server/pull/437) by @Syer10)
- (r1149) Set source preference doc fix ([#441](https://github.com/Suwayomi/Suwayomi-Server/pull/441) by @Syer10)
- (r1150) Add batch chapter update endpoint ([#442](https://github.com/Suwayomi/Suwayomi-Server/pull/442) by @martinek)
- (r1151) changes needed for tachiyomi tracker (by @AriaMoradi)
- (r1152) Future proofing (by @AriaMoradi)
- (r1153) Fix settings/check-update endpoint ([#445](https://github.com/Suwayomi/Suwayomi-Server/pull/445) by @martinek)
- (r1154) Fix docs for /server/check-updates ([#447](https://github.com/Suwayomi/Suwayomi-Server/pull/447) by @martinek)
- (r1155) Batch editing and deleting any chapter ([#449](https://github.com/Suwayomi/Suwayomi-Server/pull/449) by @martinek)
- (r1156) make chapters endpoint more unifrom (by @AriaMoradi)
- (r1157) Add batch endpoint for removing downloads from download queue ([#452](https://github.com/Suwayomi/Suwayomi-Server/pull/452) by @martinek)
- (r1158) Download queue missing update fix ([#450](https://github.com/Suwayomi/Suwayomi-Server/pull/450) by @martinek)
## Suwayomi-WebUI Changelog
- (r947) Feature/swr for library screens ([#186](https://github.com/Suwayomi/Suwayomi-WebUI/pull/186) by @martinek)
- (r948) Feature/swr for simple queries ([#187](https://github.com/Suwayomi/Suwayomi-WebUI/pull/187) by @martinek)
- (r949) Check download queue for changes and reload chapters if any chapter download changes state. ([#189](https://github.com/Suwayomi/Suwayomi-WebUI/pull/189) by @martinek)
- (r950) Update typescript dependency ([#190](https://github.com/Suwayomi/Suwayomi-WebUI/pull/190) by @martinek)
- (r951) update browserlist (by @AriaMoradi)
- (r952) Feature/batch chapter download ([#191](https://github.com/Suwayomi/Suwayomi-WebUI/pull/191) by @martinek)
- (r953) Memoize empty view face so it does not change on rerender ([#193](https://github.com/Suwayomi/Suwayomi-WebUI/pull/193) by @martinek)
- (r954) Feature/batch chapter actions ([#194](https://github.com/Suwayomi/Suwayomi-WebUI/pull/194) by @martinek)
- (r955) Fix navbar back button behavior ([#195](https://github.com/Suwayomi/Suwayomi-WebUI/pull/195) by @martinek)
- (r956) Options panels refactoring ([#196](https://github.com/Suwayomi/Suwayomi-WebUI/pull/196) by @martinek)
- (r957) Refactor and fix sorting in library ([#197](https://github.com/Suwayomi/Suwayomi-WebUI/pull/197) by @martinek)
- (r958) Scroll window to top when PagedPager changes page ([#198](https://github.com/Suwayomi/Suwayomi-WebUI/pull/198) by @martinek)
- (r959) Verticall scroll navigation and fix ([#200](https://github.com/Suwayomi/Suwayomi-WebUI/pull/200) by @martinek)
- (r960) Hide overflowing text in reader title if text can't be wrapped ([#199](https://github.com/Suwayomi/Suwayomi-WebUI/pull/199) by @martinek)
- (r961) Add safezone to scroll end detection to prevent edge cases when scrolling to the end would not detect end ([#201](https://github.com/Suwayomi/Suwayomi-WebUI/pull/201) by @martinek)
- (r962) Refactor/download queue and cleanup visuals overall ([#202](https://github.com/Suwayomi/Suwayomi-WebUI/pull/202) by @martinek)
- (r963) Fix "back" pagination on double page layout in reader for spread pages ([#203](https://github.com/Suwayomi/Suwayomi-WebUI/pull/203) by @martinek)
# Server: v0.6.5 + WebUI: r946
## TL;DR
- Fixed Windows bundler
## Suwayomi-Server Changelog
- (r1113) v0.6.4 (by @AriaMoradi)
- (r1114) fix broken links (by @AriaMoradi)
- (r1115) fix more broken stuff (by @AriaMoradi)
- (r1116) fix more broken stuff (by @AriaMoradi)
- (r1117) fix more broken stuff (by @AriaMoradi)
- (r1118) Update winget.yml ([#393](https://github.com/Suwayomi/Suwayomi-Server/pull/393) by @vedantmgoyal2009)
- (r1119) fix jre path([#396](https://github.com/Suwayomi/Suwayomi-Server/pull/396) by @voltrare)
- (r1120) Fix deb package ([#397](https://github.com/Suwayomi/Suwayomi-Server/pull/397) by @mahor1221)
- (r1121) bump version (by @AriaMoradi)
## Suwayomi-WebUI Changelog
- None
# Server: v0.6.4 + WebUI: r946
## TL;DR
- No new major features
- Bug fixes and changes for packaging
- Documentation changes
## Suwayomi-Server Changelog
- (r1087) v0.6.3 (by @AriaMoradi)
- (r1088) Save categories when manga is unfavorited ([#335](https://github.com/Suwayomi/Suwayomi-Server/pull/335) by @Syer10)
- (r1089) handle solid RAR archives ([#339](https://github.com/Suwayomi/Suwayomi-Server/pull/339)) cfso100@gmail.com
- (r1090) add support for changing downloads dir ([#343](https://github.com/Suwayomi/Suwayomi-Server/pull/343) by @AriaMoradi)
- (r1091) fix Applications dir dependency ([#344](https://github.com/Suwayomi/Suwayomi-Server/pull/344) by @AriaMoradi)
- (r1092) add support for alternative web interfaces ([#342](https://github.com/Suwayomi/Suwayomi-Server/pull/342) by @AriaMoradi)
- (r1093) Add displayValues json field for select filter ([#347](https://github.com/Suwayomi/Suwayomi-Server/pull/347) by @Syer10)
- (r1094) document manga endpoints ([#348](https://github.com/Suwayomi/Suwayomi-Server/pull/348) by @Syer10)
- (r1095) add ChapterCount to manga object in categoryMangas endpoint ([#349](https://github.com/Suwayomi/Suwayomi-Server/pull/349) by @abhijeetChawla)
- (r1096) document all endpoints ([#350](https://github.com/Suwayomi/Suwayomi-Server/pull/350) by @Syer10)
- (r1097) fix copymanga ([#354](https://github.com/Suwayomi/Suwayomi-Server/pull/354) by @AriaMoradi)
- (r1098) fix formatting by kotlinter (by @AriaMoradi)
- (r1099) bump WebUI (by @AriaMoradi)
- (r1100) fix WebUI release name (by @AriaMoradi)
- (r1101) Fix documentation errors ([#358](https://github.com/Suwayomi/Suwayomi-Server/pull/358) by @Syer10)
- (r1102) Docs improvements ([#359](https://github.com/Suwayomi/Suwayomi-Server/pull/359) by @Syer10)
- (r1103) Add linux-all.tar.gz & systemd service ([#366](https://github.com/Suwayomi/Suwayomi-Server/pull/366) by @mahor1221)
- (r1104) Publish to Windows Package Managar (WinGet) ([#369](https://github.com/Suwayomi/Suwayomi-Server/pull/369) by @vedantmgoyal2009)
- (r1105) Refactor scripts ([#370](https://github.com/Suwayomi/Suwayomi-Server/pull/370) by @mahor1221)
- (r1106) Run workflow jobs toghether ([#371](https://github.com/Suwayomi/Suwayomi-Server/pull/371) by @mahor1221)
- (r1107) Update gradle action ([#372](https://github.com/Suwayomi/Suwayomi-Server/pull/372) by @mahor1221)
- (r1108) Improve DocumentationDsl, bugfix default values and add queryParams ([#378](https://github.com/Suwayomi/Suwayomi-Server/pull/378) by @Syer10)
- (r1109) Tidy up bundler script ([#380](https://github.com/Suwayomi/Suwayomi-Server/pull/380) by @mahor1221)
- (r1110) Replace linux-all with linux-assets ([#381](https://github.com/Suwayomi/Suwayomi-Server/pull/381) by @mahor1221)
- (r1111) Rename every instance of Suwayomi jar to Suwayomi-Server.jar ([#384](https://github.com/Suwayomi/Suwayomi-Server/pull/384) by @AriaMoradi)
- (r1112) Fix mistakes from #384 ([#385](https://github.com/Suwayomi/Suwayomi-Server/pull/385) by @AriaMoradi)
## Suwayomi-WebUI Changelog
- (r943) fix default width ([#171](https://github.com/Suwayomi/Suwayomi-WebUI/pull/171) by @Robonau)
- (r944) added an update checker button for library ([#172](https://github.com/Suwayomi/Suwayomi-WebUI/pull/172) by @infix)
- (r945) fix download queue delete button ([#176](https://github.com/Suwayomi/Suwayomi-WebUI/pull/176) by @Kreach37)
- (r946) fix mangadex filters ([#177](https://github.com/Suwayomi/Suwayomi-WebUI/pull/177) by @Robonau)
# Server: v0.6.3 + WebUI: r942
## TL;DR
- Changes in Server
- Support for array search filter changes list
- Support for Tachiyomi extensions lib 1.3
- Changes in WebUI
- Better search filter support
- Fluid manga grid
- Library comfortable grid
- Sources view layouts
- Various other changes...
## Suwayomi-Server Changelog
- (r1074) v0.6.2 (by @AriaMoradi)
- (r1075) support array filter changes ([#304](https://github.com/Suwayomi/Suwayomi-Server/pull/304) by @AriaMoradi)
- (r1076) fix filterlist bugs ([#306](https://github.com/Suwayomi/Suwayomi-Server/pull/306) by @AriaMoradi)
- (r1077) Update README.md ([#305](https://github.com/Suwayomi/Suwayomi-Server/pull/305) by @mahor1221)
- (r1078) fix meta update changing all keys ([#314](https://github.com/Suwayomi/Suwayomi-Server/pull/314) by @AriaMoradi)
- (r1079) add support for tachiyomi extensions Lib 1.3 ([#316](https://github.com/Suwayomi/Suwayomi-Server/pull/316) by @AriaMoradi)
- (r1080) Fix sources list of one source throws an exception ([#308](https://github.com/Suwayomi/Suwayomi-Server/pull/308) by @Syer10)
- (r1081) Improve source handling, fix errors with uninitialized mangas in broken sources ([#319](https://github.com/Suwayomi/Suwayomi-Server/pull/319) by @Syer10)
- (r1082) Add thumbnail support for stub sources ([#320](https://github.com/Suwayomi/Suwayomi-Server/pull/320) by @Syer10)
- (r1083) update description for Tachidesk-Sorayomi ([#326](https://github.com/Suwayomi/Suwayomi-Server/pull/326) by @DattatreyaReddy)
- (r1084) Add last bit of code needed for Extensions Lib 1.3 ([#330](https://github.com/Suwayomi/Suwayomi-Server/pull/330) by @Syer10)
- (r1085) Add QuickJS, replaces Duktape for Extensions Lib 1.3 ([#331](https://github.com/Suwayomi/Suwayomi-Server/pull/331) by @Syer10)
- (r1086) fix auth not actually blocking requests ([#333](https://github.com/Suwayomi/Suwayomi-Server/pull/333) by @AriaMoradi)
## Suwayomi-WebUI Changelog
- (r930) Source filter scroll fix (array of filters on submit [#149](https://github.com/Suwayomi/Suwayomi-WebUI/pull/149) by @Robonau)
- (r931) fix manga badges setting menu that turns the update/download badges on and off ([#150](https://github.com/Suwayomi/Suwayomi-WebUI/pull/150) by @Robonau)
- (r932) move sorts to copy tachiyomi ([#151](https://github.com/Suwayomi/Suwayomi-WebUI/pull/151) by @Robonau)
- (r933) add comfortable grid option ([#152](https://github.com/Suwayomi/Suwayomi-WebUI/pull/152) by @Robonau)
- (r934) source layouts ([#153](https://github.com/Suwayomi/Suwayomi-WebUI/pull/153) by @Robonau)
- (r935) List layout ([#154](https://github.com/Suwayomi/Suwayomi-WebUI/pull/154) by @Robonau)
- (r936) in library badge to manga in sources ([#156](https://github.com/Suwayomi/Suwayomi-WebUI/pull/156) by @Robonau)
- (r937) mass search ([#157](https://github.com/Suwayomi/Suwayomi-WebUI/pull/157) by @Robonau)
- (r938) 18+ tag on source/extension cards ([#160](https://github.com/Suwayomi/Suwayomi-WebUI/pull/160) by @Robonau)
- (r939) fix search source click ([#164](https://github.com/Suwayomi/Suwayomi-WebUI/pull/164) by @Robonau)
- (r940) items per row setting ([#165](https://github.com/Suwayomi/Suwayomi-WebUI/pull/165) by @Robonau)
- (r941) fix the grid width thing ([#169](https://github.com/Suwayomi/Suwayomi-WebUI/pull/169) by @Robonau)
- (r942) unified library options ([#168](https://github.com/Suwayomi/Suwayomi-WebUI/pull/168) by @infix)
# Server: v0.6.2 + WebUI: r929
## TL;DR
- Changes in WebUI
- Moved search to Browse
- Support for Source Filters
- Better visuals for Download Queue
- A live version of WebUI is now available [at this link](https://tachidesk-webui-preview.github.io/).
## Suwayomi-Server Changelog
- (r1073) Refactor debian-packager.sh, rename launcher scripts ([#303](https://github.com/Suwayomi/Suwayomi-Server/pull/303) by @mahor1221)
## Suwayomi-WebUI Changelog
- (r912) show locale date, less confusing ([#131](https://github.com/Suwayomi/Suwayomi-WebUI/pull/131) by @AriaMoradi)
- (r913) fix links to work on a bare host ([#132](https://github.com/Suwayomi/Suwayomi-WebUI/pull/132) by @AriaMoradi)
- (r914) fix direct links ([#133](https://github.com/Suwayomi/Suwayomi-WebUI/pull/133) by @AriaMoradi)
- (r915) deploy to github pages (by @AriaMoradi)
- (r916) fix typo (by @AriaMoradi)
- (r917) better naming (by @AriaMoradi)
- (r918) update notice about github pages (by @AriaMoradi)
- (r919) move text (by @AriaMoradi)
- (r920) make all links work by catching 404 (by @AriaMoradi)
- (r921) fix scrolling 8px ([#135](https://github.com/Suwayomi/Suwayomi-WebUI/pull/135) by @Robonau)
- (r922) sorting ([#136](https://github.com/Suwayomi/Suwayomi-WebUI/pull/136) by @Robonau)
- (r923) Close button fix ([#141](https://github.com/Suwayomi/Suwayomi-WebUI/pull/141)) z14942744@gmail.com
- (r924) add NavBarContextProvider ([#128](https://github.com/Suwayomi/Suwayomi-WebUI/pull/128) by @abhijeetChawla)
- (r925) Resolved Merged Conflicts ([#127](https://github.com/Suwayomi/Suwayomi-WebUI/pull/127) by @abhijeetChawla)
- (r926) more Download Queue info ([#138](https://github.com/Suwayomi/Suwayomi-WebUI/pull/138) by @Robonau)
- (r927) Source filters, move search to SourceMangas ([#142](https://github.com/Suwayomi/Suwayomi-WebUI/pull/142) by @Robonau)
- (r928) Source genre sorts design ([#147](https://github.com/Suwayomi/Suwayomi-WebUI/pull/147) by @Robonau)
- (r929) Update LibraryOptions.tsx ([#146](https://github.com/Suwayomi/Suwayomi-WebUI/pull/146) by @Robonau)
# Server: v0.6.1 + WebUI: r911
## TL;DR
- msi and deb packages thanks to @mahor1221
- [Tachidesk-Flutter](https://github.com/Suwayomi/Tachidesk-Flutter) exists now!
## Suwayomi-Server Changelog
- (r1047) update (by @AriaMoradi)
- (r1048) bump version (by @AriaMoradi)
- (r1049) Update README.md (by @AriaMoradi)
- (r1050) Update README.md (by @AriaMoradi)
- (r1051) refactor getChapter ([#268](https://github.com/Suwayomi/Suwayomi-Server/pull/268) by @AriaMoradi)
- (r1052) Improve documentation with Http codes ([#261](https://github.com/Suwayomi/Suwayomi-Server/pull/261) by @Syer10)
- (r1053) Add Route to stop and reset the updater ([#260](https://github.com/Suwayomi/Suwayomi-Server/pull/260) by @ntbm)
- (r1054) ignore non image files ([#269](https://github.com/Suwayomi/Suwayomi-Server/pull/269) by @AriaMoradi)
- (r1055) fix compile erorr (by @AriaMoradi)
- (r1056) update dex2jar (by @AriaMoradi)
- (r1057) Update Gradle and Dependencies ([#281](https://github.com/Suwayomi/Suwayomi-Server/pull/281) by @Syer10)
- (r1058) Handlers must return a result ([#282](https://github.com/Suwayomi/Suwayomi-Server/pull/282) by @Syer10)
- (r1059) Allow app compilation on Java 18+ ([#286](https://github.com/Suwayomi/Suwayomi-Server/pull/286) by @Syer10)
- (r1060) Automated MSI package building ([#277](https://github.com/Suwayomi/Suwayomi-Server/pull/277) by @mahor1221)
- (r1061) Automated debian package building ([#287](https://github.com/Suwayomi/Suwayomi-Server/pull/287) by @mahor1221)
- (r1062) fix Debian package errors ([#288](https://github.com/Suwayomi/Suwayomi-Server/pull/288) by @mahor1221)
- (r1063) Fix build_push.yml Hopefully ([#289](https://github.com/Suwayomi/Suwayomi-Server/pull/289) by @mahor1221)
- (r1064) Improve windows-bundler.sh ([#290](https://github.com/Suwayomi/Suwayomi-Server/pull/290) by @mahor1221)
- (r1065) add Tachidesk-Flutter to readme ([#292](https://github.com/Suwayomi/Suwayomi-Server/pull/292)) @DattatreyaReddy)
- (r1066) no online fetch on backup ([#293](https://github.com/Suwayomi/Suwayomi-Server/pull/293) by @AriaMoradi)
- (r1067) auto-remove duplicate chapters ([#294](https://github.com/Suwayomi/Suwayomi-Server/pull/294) by @AriaMoradi)
- (r1068) remove gson ([#295](https://github.com/Suwayomi/Suwayomi-Server/pull/295) by @AriaMoradi)
## Suwayomi-WebUI Changelog
- (r894) migrate ReaderNavbar to Mui 5 ([#84](https://github.com/Suwayomi/Suwayomi-WebUI/pull/84) by @AriaMoradi)
- (r895) migrate SpinnerImage to Mui 5 ([#97](https://github.com/Suwayomi/Suwayomi-WebUI/pull/97) by @AriaMoradi)
- (r896) migrate VerticalPager to Mui 5 ([#94](https://github.com/Suwayomi/Suwayomi-WebUI/pull/94) by @AriaMoradi)
- (r897) migrate PagedPager to Mui 5 ([#93](https://github.com/Suwayomi/Suwayomi-WebUI/pull/93) by @AriaMoradi)
- (r898) MangaCard imges don't stretch now ([#110](https://github.com/Suwayomi/Suwayomi-WebUI/pull/110) by @abhijeetChawla)
- (r899) show correct title ([#111](https://github.com/Suwayomi/Suwayomi-WebUI/pull/111) by @AriaMoradi)
- (r900) migrate DoublePage to Mui 5 ([#88](https://github.com/Suwayomi/Suwayomi-WebUI/pull/88) by @AriaMoradi)
- (r901) migrate DoublePagedPager to Mui 5 ([#91](https://github.com/Suwayomi/Suwayomi-WebUI/pull/91) by @AriaMoradi)
- (r902) migrate Reader to Mui 5 ([#100](https://github.com/Suwayomi/Suwayomi-WebUI/pull/100) by @AriaMoradi)
- (r903) migrate HorizantalPager to Mui 5 ([#92](https://github.com/Suwayomi/Suwayomi-WebUI/pull/92) by @AriaMoradi)
- (r904) migrate PageNumber to Mui 5 ([#90](https://github.com/Suwayomi/Suwayomi-WebUI/pull/90) by @AriaMoradi)
- (r905) Chapter filter is woking ([#114](https://github.com/Suwayomi/Suwayomi-WebUI/pull/114) by @abhijeetChawla)
- (r906) added extension search ([#115](https://github.com/Suwayomi/Suwayomi-WebUI/pull/115) by @abhijeetChawla)
- (r907) cleanup ([#117](https://github.com/Suwayomi/Suwayomi-WebUI/pull/117) by @AriaMoradi)
- (r908) handle search shortcuts ([#116](https://github.com/Suwayomi/Suwayomi-WebUI/pull/116) by @AriaMoradi)
- (r909) Refactor for Removing unnecesary UseEffect ([#118](https://github.com/Suwayomi/Suwayomi-WebUI/pull/118) by @abhijeetChawla)
- (r910) refactor ChapterList ([#125](https://github.com/Suwayomi/Suwayomi-WebUI/pull/125) by @abhijeetChawla)
- (r911) refactor ChapterOptions ([#126](https://github.com/Suwayomi/Suwayomi-WebUI/pull/126) by @abhijeetChawla)
# Server: v0.6.0 + WebUI: r893
## TL;DR
- WebUI design went through a whole lot of changes, including
- Got rid of hamburger menu, now we have a custom mobile navbar
- Unread and Download count badges
- Back button so better electron experience
- There's a whole lot more that I'm too lazy to explore.
- Completely removed anime support
- Fixed category reordering
- Added support for search filters(Server side only)
- Added support for updating library(Server side only)
- A bunch of API breaking changes(hence why bumping to v0.6.0)!
## Suwayomi-Server Changelog
- (r996) cleanup (by @AriaMoradi)
- (r999) better cleaning algorithm (by @AriaMoradi)
- (r1007) remove anime support (by @AriaMoradi)
- (r1009) Fix tests ([#226](https://github.com/Suwayomi/Suwayomi-Server/pull/226) by @ntbm)
- (r1010) Expose unread and download count of Manga in category api ([#227](https://github.com/Suwayomi/Suwayomi-Server/pull/227) by @ntbm)
- (r1011) add Cache Header to Thumbnail Response for improved library performance ([#228](https://github.com/Suwayomi/Suwayomi-Server/pull/228) by @ntbm)
- (r1013) Fix unread and download counts casing ([#230](https://github.com/Suwayomi/Suwayomi-Server/pull/230) by @Syer10)
- (r1014) Fix broken test ([#231](https://github.com/Suwayomi/Suwayomi-Server/pull/231) by @ntbm)
- (r1016) Fix category reorder Endpoint. Added Test for Category Reorder ([#232](https://github.com/Suwayomi/Suwayomi-Server/pull/232) by @ntbm)
- (r1017) change windows bundle names (by @AriaMoradi)
- (r1018) improve tests (by @AriaMoradi)
- (r1019) allow injecting Sources (by @AriaMoradi)
- (r1020) update (by @AriaMoradi)
- (r1021) fix credit (by @AriaMoradi)
- (r1022) cleanup (by @AriaMoradi)
- (r1023) refactor (by @AriaMoradi)
- (r1024) refactor (by @AriaMoradi)
- (r1025) implement Source Filters (by @AriaMoradi)
- (r1026) ignore build artifacts generated by teting (by @AriaMoradi)
- (r1027) convert request type (by @AriaMoradi)
- (r1028) Update CONTRIBUTING.md (by @AriaMoradi)
- (r1029) stop supporting zero based image storage ([#242](https://github.com/Suwayomi/src/pull/242) by @AriaMoradi)
- (r1030) add manga data to download queue object ([#244](https://github.com/Suwayomi/src/pull/244) by @AriaMoradi)
- (r1031) Fix Manga Meta, add Manga Meta test ([#245](https://github.com/Suwayomi/src/pull/245) by @Syer10)
- (r1032) add pagination to recentChapters ([#246](https://github.com/Suwayomi/src/pull/246) by @AriaMoradi)
- (r1033) update (by @AriaMoradi)
- (r1034) Implement Update of Library/Category ([#235](https://github.com/Suwayomi/src/pull/235) by @ntbm)
- (r1035) update (by @AriaMoradi)
- (r1036) Mention the existence of Mahor's Tachidesk-GTK (by @AriaMoradi)
- (r1037) Add a Kotlin DSL for endpoint documentation ([#249](https://github.com/Suwayomi/Suwayomi-Server/pull/249) by @Syer10)
- (r1038) update (by @AriaMoradi)
- (r1039) update (by @AriaMoradi)
- (r1040) cleanup directory names ([#251](https://github.com/Suwayomi/Suwayomi-Server/pull/251) by @AriaMoradi)
- (r1041) Fix first page not being detected correctly ([#253](https://github.com/Suwayomi/Suwayomi-Server/pull/253) by @AriaMoradi)
- (r1042) Update README.md (by @AriaMoradi)
- (r1043) Update README.md (by @AriaMoradi)
- (r1044) migrate application directories ([#255](https://github.com/Suwayomi/Suwayomi-Server/pull/255) by @AriaMoradi)
- (r1045) add support for MultiSelectListPreference ([#258](https://github.com/Suwayomi/Suwayomi-Server/pull/258) by @AriaMoradi)
- (r1046) empty searchTerm support ([#259](https://github.com/Suwayomi/Suwayomi-Server/pull/259) by @AriaMoradi)
## Suwayomi-WebUI
- (r821) add Permanent sidebar for desktop widths([#46](https://github.com/Suwayomi/Suwayomi-WebUI/pull/46) by @abhijeetChawla)
- (r822) Fix Local Source being missing (by @AriaMoradi)
- (r823) fix the ugliness of bare messages (by @AriaMoradi)
- (r824) add pull request template (by @AriaMoradi)
- (r825) add Unread badges ([#48](https://github.com/Suwayomi/Suwayomi-WebUI/pull/48) by @ntbm)
- (r826) Back button implementation ([#47](https://github.com/Suwayomi/Suwayomi-WebUI/pull/47) by @abhijeetChawla)
- (r827) remove redundant '/manga' prefix from paths (by @AriaMoradi)
- (r828) refactor (by @AriaMoradi)
- (r829) put Sources and Extensions in the same screen (by @AriaMoradi)
- (r830) Set Fallback Image for broken Thumbnails ([#50](https://github.com/Suwayomi/Suwayomi-WebUI/pull/50) by @ntbm)
- (r833) Apply Api changes for unread badges ([#52](https://github.com/Suwayomi/Suwayomi-WebUI/pull/52) by @ntbm)
- (r834) add EmptyView to DownloadQueue, refactro strings ([#53](https://github.com/Suwayomi/Suwayomi-WebUI/pull/53) by @abhijeetChawla)
- (r835) Bottom navbar for mobile ([#51](https://github.com/Suwayomi/Suwayomi-WebUI/pull/51) by @abhijeetChawla)
- (r836) Implement Unread Filter for Library ([#54](https://github.com/Suwayomi/Suwayomi-WebUI/pull/54) by @ntbm)
- (r837) fix navbar broken logic (by @AriaMoradi)
- (r838) fix navbar (by @AriaMoradi)
- (r839) refactor (by @AriaMoradi)
- (r840) refactor (by @AriaMoradi)
- (r841) refactor (by @AriaMoradi)
- (r842) show different NavbarItems depending on device width (by @AriaMoradi)
- (r843) remove text decoration (by @AriaMoradi)
- (r844) fancy icon based on if path selected (by @AriaMoradi)
- (r845) custom Extension icon, google's version is shit (by @AriaMoradi)
- (r846) refactor (by @AriaMoradi)
- (r848) move info (by @AriaMoradi)
- (r849) add Search to Library ([#55](https://github.com/Suwayomi/Suwayomi-WebUI/pull/55) by @ntbm)
- (r850) add aspect ratio to the manga card. ([#56](https://github.com/Suwayomi/Suwayomi-WebUI/pull/56) by @abhijeetChawla)
- (r851) better wording (by @AriaMoradi)
- (r852) reorder nav buttons (by @AriaMoradi)
- (r853) nicer gradient (by @AriaMoradi)
- (r854) refactor MangaCard (by @AriaMoradi)
- (r855) closes #58 (by @AriaMoradi
- (r856) Add Resume Reading FAB Manga screen ([#59](https://github.com/Suwayomi/Suwayomi-WebUI/pull/59) by @abhijeetChawla)
- (r857) add filter and badge for `downloadCount` ([#62](https://github.com/Suwayomi/Suwayomi-WebUI/pull/62) by @abhijeetChawla)
- (r858) add issue template (by @AriaMoradi)
- (r859) Change color of navbar in light mode ([#65](https://github.com/Suwayomi/Suwayomi-WebUI/pull/65) by @abhijeetChawla)
- (r860) fix manga FAB margins ([#66](https://github.com/Suwayomi/Suwayomi-WebUI/pull/66) by @AriaMoradi)
- (r861) remove extra scrollbar on mobile ([#67](https://github.com/Suwayomi/Suwayomi-WebUI/pull/67) by @AriaMoradi)
- (r862) Fix Bad messages in Library Appbar search ([#70](https://github.com/Suwayomi/Suwayomi-WebUI/pull/70) by @ntbm)
- (r863) ban the style prop (by @AriaMoradi)
- (r864) Updates pagination update ([#68](https://github.com/Suwayomi/Suwayomi-WebUI/pull/68) by @AriaMoradi)
- (r865) make the whole chapter card into a button ([#73](https://github.com/Suwayomi/Suwayomi-WebUI/pull/73) by @AriaMoradi)
- (r866) fix chapter actions not working if manga is not fetched online ([#74](https://github.com/Suwayomi/Suwayomi-WebUI/pull/74) by @AriaMoradi)
- (r867) migrate some components to Mui5 new styling system ([#72](https://github.com/Suwayomi/Suwayomi-WebUI/pull/72) by @abhijeetChawla)
- (r868) load first page on read manga ([#76](https://github.com/Suwayomi/Suwayomi-WebUI/pull/76) by @AriaMoradi)
- (r869) Revert "migrate some components to Mui5 new styling system ([#72](https://github.com/Suwayomi/Suwayomi-WebUI/pull/72))" (by @AriaMoradi)
- (r870) migrate Backup to Mui 5 ([#106](https://github.com/Suwayomi/Suwayomi-WebUI/pull/106) by @AriaMoradi)
- (r871) migrate EmptyView to Mui 5 ([#95](https://github.com/Suwayomi/Suwayomi-WebUI/pull/95) by @AriaMoradi)
- (r872) migrate CategorySelect to Mui 5 ([#85](https://github.com/Suwayomi/Suwayomi-WebUI/pull/85) by @AriaMoradi)
- (r873) migrate LibraryOptions to Mui 5 ([#83](https://github.com/Suwayomi/Suwayomi-WebUI/pull/83) by @AriaMoradi)
- (r874) migrate ChapterCard.tsx to Mui 5 ([#80](https://github.com/Suwayomi/Suwayomi-WebUI/pull/80) by @AriaMoradi)
- (r875) migrate App.tsx to Mui 5 ([#79](https://github.com/Suwayomi/Suwayomi-WebUI/pull/79) by @AriaMoradi)
- (r876) migrate SourceConfigure to Mui 5 ([#103](https://github.com/Suwayomi/Suwayomi-WebUI/pull/103) by @AriaMoradi)
- (r877) migrate Settings to Mui 5 ([#102](https://github.com/Suwayomi/Suwayomi-WebUI/pull/102) by @AriaMoradi)
- (r878) migrate Updates to Mui 5 ([#104](https://github.com/Suwayomi/Suwayomi-WebUI/pull/104) by @AriaMoradi)
- (r879) Save tabs number in Url to persist tab when go to other paths ([#78](https://github.com/Suwayomi/Suwayomi-WebUI/pull/78) by @abhijeetChawla)
- (r880) migrate LangSelect to Mui 5 ([#86](https://github.com/Suwayomi/Suwayomi-WebUI/pull/86) by @AriaMoradi)
- (r881) migrate ExtensionCard.tsx to Mui 5 ([#81](https://github.com/Suwayomi/Suwayomi-WebUI/pull/81) by @AriaMoradi)
- (r882) migrate SingleSearch to Mui 5 ([#101](https://github.com/Suwayomi/Suwayomi-WebUI/pull/101) by @AriaMoradi)
- (r883) migrate LoadingPlaceholder to Mui 5 ([#96](https://github.com/Suwayomi/Suwayomi-WebUI/pull/96) by @AriaMoradi)
- (r884) migrate About to Mui 5 ([#105](https://github.com/Suwayomi/Suwayomi-WebUI/pull/105) by @AriaMoradi)
- (r885) migrate SourceCard to Mui 5 ([#82](https://github.com/Suwayomi/Suwayomi-WebUI/pull/82) by @AriaMoradi)
- (r886) migrate Manga to Mui 5 ([#99](https://github.com/Suwayomi/Suwayomi-WebUI/pull/99) by @AriaMoradi)
- (r887) migrate Browse to Mui 5 ([#98](https://github.com/Suwayomi/Suwayomi-WebUI/pull/98) by @AriaMoradi)
- (r888) migrate DesktopSideBar to Mui 5 ([#87](https://github.com/Suwayomi/Suwayomi-WebUI/pull/87) by @AriaMoradi)
- (r889) cleanup library ([#107](https://github.com/Suwayomi/Suwayomi-WebUI/pull/107) by @AriaMoradi)
- (r890) support for new searchTerm (by @AriaMoradi)
- (r891) Revert "support for new searchTerm" (by @AriaMoradi)
- (r892) add support for emptySearch ([#109](https://github.com/Suwayomi/Suwayomi-WebUI/pull/109) by @AriaMoradi)
- (r893) add support for MultiSelectListPreference ([#108](https://github.com/Suwayomi/Suwayomi-WebUI/pull/108) by @AriaMoradi)
# Server: v0.5.4 + WebUI: r820
## TL;DR
- Fixed ReadComicOnline, Toonily and possibly other sources not working
- Backup and Restore now includes Updates tab data
- Removed Anime support from WebUI, Anime support will also be removed from Suwayomi-Server in a future update
## Suwayomi-Server Changelog
- (r973) convert android.jar lib to a maven repo
- (r978) mimic Tachiyomi's behaviour more closely, fixes ReadComicOnline (EN)
- (r980) fix export chapter ordering, include new props in backup
- (r982) remove isNsfw annotation detection
- (r984) use correct time conversion units when doing backups
- (r989) Support using a CatalogueSource instead of only HttpSources ([#219](https://github.com/Suwayomi/Suwayomi-Server/pull/219) by @Syer10)
- (r991) Use a custom task to run electron ([#220](https://github.com/Suwayomi/Suwayomi-Server/pull/220) by @Syer10)
## Suwayomi-WebUI Changelog
- (r810) fix wrong strings in set Server Address dialog, fixes [#39](https://github.com/Suwayomi/Suwayomi-WebUI/issues/39)
- (r811) fix chapterFetch loop
- (r812) fix overlapping requests
- (r813) fix typo
- (r814) Better portrait support ([#41](https://github.com/Suwayomi/Suwayomi-WebUI/issues/41) by @minhe7735)
- (r815) fixes Reader navbar colors when in light mode ([#43](https://github.com/Suwayomi/Suwayomi-WebUI/issues/43) by @abhijeetChawla)
- (r816) default languages cleanup, force Local source enabled
- (r817) force Local source at LangSelect
- (r818) rename ExtensionLangSelect: generic name for generic use
- (r819) don't show anime anymore
- (r820) Remove Anime support
# Server: v0.5.3 + WebUI: r809
## TL;DR
- added support for a equivalent page to Tachiyomi's Updates tab
- fix launchers not working on macOS M1/arm64
## Suwayomi-Server Changelog
- (r956) fix macOS-arm64 bundle launchers not working
- (r957) Workaround StdLib issue and add KtLint to all modules ([#206](https://github.com/Suwayomi/Suwayomi-Server/pull/206) by @Syer10)
- (r960-r963) Add recently updated chapters(Updates) endpoint
## Suwayomi-WebUI Changelog
- (r808) fix chapter list not calling onlineFetch=true
- (r809) add support for Updates
# Server: v0.5.2 + WebUI: r807
## TL;DR
- Fixed Local source not working on Windows
- Fixed Chapter numbers being shown incorrectly
## Suwayomi-Server
### Public API
#### Non-breaking changes
- N/A
#### Breaking changes
- N/A
#### Bug fixes
- (r948) Fix ManaToki (KO) and NewToki (KO) (issue [#202](https://github.com/Suwayomi/Suwayomi-Server/issue/202))
- (r949) Local source: fix windows paths
### Private API
- (r941) Update BytecodeEditor to use Java NIO Paths ([#200](https://github.com/Suwayomi/Suwayomi-Server/pull/200) by @Syer10)
- (r942) Gradle Updates ([#199](https://github.com/Suwayomi/Suwayomi-Server/pull/199) by @Syer10)
## Suwayomi-WebUI
#### Visible changes
- (r804) update text positioning on Reader and Player ([#35](https://github.com/Suwayomi/Suwayomi-WebUI/pull/35) by @voltrare)
- (r806) Source card for Local source is different
- (r807) add Local source guide
#### Bug fixes
- (r805) fix chapter name
#### Internal changes
- N/A
# Server: v0.5.1 + WebUI: r803
## TL;DR
- Loading sources' manga list is at least twice as fast
- Added support for Tachiyomi's Local source
- Added BasicAuth support, now you can protect your Suwayomi instance if you are running it on a public server
- Added ability to turn off cache for image requests
## Suwayomi-Server
### Public API
#### Non-breaking changes
- (r915) add BasicAuth support
- (r918) add ability to delete downloaded chapters
- (r923-r930) add Local Source
- (r938) add ability to turn off cache for image requests
#### Breaking changes
- N/A
#### Bug fixes
- (r917) detect if a downloaded chapter is missing
### Private API
- (r913) remove expand char limit on MangaTable columns
- (r914) migrate to Javalin 4
- (r921) depricate zero based chapters
- (r937) add ChapterRecognition from tachiyomi, closes #10
## Suwayomi-WebUI
#### Visible changes
- (r790) nice looking progress percentage
- (r791) show a Delete button for downloaded chapters
- (r792) Update hover effect using more of Material-UI color pallete ([#29](https://github.com/Suwayomi/Suwayomi-WebUI/pull/29) by @voltrare)
- (r793) Optimize images ([#32](https://github.com/Suwayomi/Suwayomi-WebUI/pull/32) by @phanirithvij)
- (r794) try fix #30 ([#31](https://github.com/Suwayomi/Suwayomi-WebUI/pull/31) by @phanirithvij)
- (r795) fix viewing page number when the string is long
- (r796) show proper display name for source
- (r797) fail gracefully when a thumbnail has errors
- (r798) fix when a source fails to load mangas
- (r800) add Local source ([#31](https://github.com/Suwayomi/Suwayomi-WebUI/pull/31))
- (r803) add support for useCache
#### Bug fixes
- N/A
#### Internal changes
- N/A
# Server: v0.5.0 + WebUI: r789
## TL;DR
- You can now install APK extensions from the extensions page
- WebUI now comes with an updated Material Design looks and is faster a little bit.
- WebUI now shows Nsfw content by default, disable it in settings if you prefer to not see Nsfw stuff
- Added support for configuration of sources, this enables MangaDex, Komga, Cubari and many other sources
- Chapters in the Manga page and Sources in the source page now look nicer and will glow with mouse hover
## Suwayomi-Server
### Public API
#### Non-breaking changes
- (r888) add installing APK from external sources endpoint
#### Breaking changes
- (r877 [#188](https://github.com/Suwayomi/Suwayomi-Server/pull/188) by @Syer10) `MangaDataClass.genre` changed type to `List<String>`
#### Bug fixes
- (r899-r901) fix when an external apk is installed and it doesn't have the default tachiyomi-extensions name
- (r905) fix a bug where if two sources return the same URL, a false duplicate might be detected
### Private API
- (r887) the `run` task won't call `downloadWebUI` now
- (r902) cleanup print/ln instances
- (r906) better handling of uninstalling Extensions
## Suwayomi-WebUI
#### Visible changes
- (r770) add support for the new genre type
- (r771) set the default value of `showNsfw` to `true` so we won't have visual artifacts with a clean install
- (r774 [#21](https://github.com/Suwayomi/Suwayomi-WebUI/pull/21) by @voltrare) `ReaderNavbar.jsx`: Swap close and retract Navbar buttons
- (r775 [#23](https://github.com/Suwayomi/Suwayomi-WebUI/pull/23) by @voltrare) `yarn.lock`: Fixes version inconsistency after commit 9b866811b
- (r776 [#23](https://github.com/Suwayomi/Suwayomi-WebUI/pull/23) by @voltrare) add margin between Source and Extension cards, make the Search button look nicer
- (r777) add support for installing external APK files
- (r778) fix the makeToaster?
- (r779) Action button for installing external extension
- (r780 Suwayomi/Suwayomi-WebUI#25) add on hover, active effect to Chapter/Episode card
- (r782-r785) updating material-ui to v5 changed the theme
- (r785-r788) better `SourceCard` looks on mobile, move `SourceDataClass.isConfigurable` gear button to `SourceMangas`
- (r789) implement source configuration
#### Bug fixes
- N/A
#### Internal changes
- (r782-r785) update dependencies, migrate material-ui from v4 to v5
# Server: v0.4.9 + WebUI: r769
## Suwayomi-Server
### Public API
#### Non-breaking changes
- N/A
#### Breaking changes
- (r857) renamed: `SourceDataClass.isNSFW` -> `SourceDataClass.isNsfw`
#### Bug fixes
- N/A
### Private API
- (r850) Bump WebUI version to r767
- (r861) Bump WebUI version to r769
#### Non-code changes
- (r851) Add this changelog file and `CHANGELOG-TEMPLATE.md`
- (r852-r853) `CONTRIBUTING.md`: Add a note about this maintaining this file changelog
- (r855) `CONTRIBUTING.md`: text cleanup
- (r859) `CONTRIBUTING.md`: remove dumb rule
- (r862) `windows-bundler.sh`: update jre
- (r864) add linux and macOS bundler script and launcher scripts
- (r865) fix macOS bundler script and launcher scripts
- (r866) bump electron version to v14.0.0
- (r868) add linux and macOS bundlers to the publish workflow
- (r871) `publish.yml`: remove node module cache, won't need it anymore
- (r873) `publish.yml` and `build_push.yml`: fix oopsies
## Suwayomi-WebUI
#### Visible changes
- (r767-r769) Support for hiding NSFW content in settings screen, extensions screen, sources screen
#### Bug fixes
- N/A
#### Internal changes
- (r767) Remove some duplicate dependency declaration from `package.json`
#### Non-code changes
- (r42-r45) Change `README.md`: some links and stuff
- (r45-r765) Add all of the commit history from when WebUI was separated from Server, jumping from r45 to r765 (r45 is exactly the same as r765)
- (r766) Steal `.gitattributes` from Suwayomi-Server
- (r767) Dependency cleanup in `package.json`
# Server: v0.4.8 + WebUI: r41
## Suwayomi-Server
### Public API
#### Non-breaking changes
- Added support for serializing Search Filters
- `SourceDataClass` now has a `isNsfw` key
#### Breaking changes
- N/A
#### Bug fixes
- Fixed a bug where backup restore reversed chapter order
- Open Site feature now works properly (https://github.com/Suwayomi/Suwayomi-WebUI/issues/19)
### Private API
- Added `CloudflareInterceptor` from TachiWeb-Server
- Restoring backup for mangas in library(merging manga data) is now supported
## Suwayomi-WebUI
#### Visible changes
- Better looking manga card titles
- Better reader title, next, prev buttons
#### Bug fixes
- Open Site feature now works properly (https://github.com/Suwayomi/Suwayomi-WebUI/issues/19)
- Re-ordering categories now works
#### Internal changes
- N/A

View File

@@ -1,37 +1,88 @@
# Contributing
## Where should I start?
Checkout [This Kanban Board](https://github.com/Suwayomi/Tachidesk/projects/1) to see the rough development roadmap.
Checkout [This Kanban Board](https://github.com/Suwayomi/Suwayomi-Server/projects/1) to see the rough development roadmap.
**Note to potential contributors:** Notify the developers on [Suwayomi discord](https://discord.gg/DDZdqZWaHA) (#programming channel) or open a WIP pull request before starting if you decide to take on working on anything from/not from the roadmap in order to avoid parallel efforts on the same issue/feature.
### Important notes
- Notify the developers on [Suwayomi discord](https://discord.gg/DDZdqZWaHA) (#tachidesk-server and #tachidesk-webui channels) or open a WIP pull request before starting if you decide to take on working on anything from/not from the roadmap in order to avoid parallel efforts on the same issue/feature.
- Your pull request will be squashed into a single commit.
- We hate big pull requests, make them as small as possible, change one meaningful thing. Spam pull requests, we don't mind.
## How does Tachidesk-Server work?
### Project goals and vision
- Porting Tachiyomi and covering its features
- Syncing with Tachiyomi, [main issue](https://github.com/Suwayomi/Suwayomi-Server/issues/159)
- Generally rejecting features that Tachiyomi(main app) doesn't have,
- Unless it's something that makes sense for desktop sizes or desktop form factor (keyboard + mouse)
- Additional/crazy features can go in forks and alternative clients
- [Suwayomi-WebUI](https://github.com/Suwayomi/Suwayomi-WebUI) should
- be responsive
- support both desktop and mobile form factors well
## How does Suwayomi-Server work?
This project has two components:
1. **Server:** contains the implementation of [tachiyomi's extensions library](https://github.com/tachiyomiorg/extensions-lib) and uses an Android compatibility library to run jar libraries converted from apk extensions. All this concludes to serving a REST API.
2. **WebUI:** A react SPA(`create-react-app`) project that works with the server to do the presentation located at https://github.com/Suwayomi/Tachidesk-WebUI
1. **Server:** contains the implementation of [tachiyomi's extensions library](https://github.com/tachiyomiorg/extensions-lib) and uses an Android compatibility library to run jar libraries converted from apk extensions. All this concludes to serving a GraphQL API.
2. **WebUI:** A React SPA(`create-react-app`) project that works with the server to do the presentation located at https://github.com/Suwayomi/Suwayomi-WebUI
## Why a web server app?
### API
#### GraphQL
*Only available in the preview at the moment*
The GraphQL API can be queried with a POST request to `/api/graphql`. There is also the GraphiQL IDE accessible by the browser at `/api/graphql` to perform ad-hoc queries and explore the API.
#### REST
> [!WARNING]
>
> Soon to be deprecated
The REST API can be queried at `/api/v1`. An interactive Swagger API explorer is available at `/api/swagger-ui`.
### Tracker client authorization
#### OAuth
Since the url of a Suwayomi-Server is not known, it is not possible to redirect directly to the client.<br/>
Thus, to provide tracker support via oauth, the tracker clients redirect to the [suwayomi website](https://suwayomi.org/)
and there the actual redirection to the client takes place.
When implementing the login process in your client you have to make sure to follow some preconditions:
To be able to redirect to the client you have to attach a `state` object to the query of the auth url
- this `state` object has to have a `redirectUrl` which points to the client route at which you want to handle the auth result
- besides the `redirectUrl` you can pass any information you require to handle the result (e.g. the server `id` of the tracker client)
- example URL for AniList: `https://anilist.co/api/v2/oauth/authorize?client_id=ID&response_type=token&state={ redirectUrl: "http://localhost:4567/handle/oauth/result", trackerId: 1, anyOtherInfo: "your client requires" }`
Once the permission has been granted, you will get redirected to the client at the provided route (`redirectUrl`).<br/>
- Example URL (decoded) for AniList: `http://localhost:4567/handle/oauth/result?access_token=TOKEN&token_type=Bearer&expires_in=31622400&state={ redirectUrl: "http://localhost:4567/handle/oauth/result", trackerId: 1, anyOtherInfo: "your client requires" }`).<br/>
Finally, to finish the login process, you just have to pass this URL to the server as the `callbackUrl`.
## Why a web app?
This structure is chosen to
- Achieve the maximum multi-platform-ness
- Gives the ability to acces Tachidesk-Server from a remote client e.g. your phone, tablet or smart TV
- Eaise development of user intefaces for Tachidesk
- Gives the ability to access Suwayomi-Server from a remote client e.g., your phone, tablet or smart TV
- Ease development of user interfaces for Suwayomi
## Building from source
### Prerequisites
You need these software packages installed in order to build the project
- Java Development Kit and Java Runtime Environment version 8 or newer(both Oracle JDK and OpenJDK works)
- Android stubs jar
- **Manual download:** Download [android.jar](https://raw.githubusercontent.com/Suwayomi/Tachidesk/android-jar/android.jar) and put it under `AndroidCompat/lib`.
- **Automated download:** Run `AndroidCompat/getAndroid.sh`(MacOS/Linux) or `AndroidCompat/getAndroid.ps1`(Windows) from project's root directory to download and rebuild the jar file from Google's repository.
### building the full-blown jar (Tachidesk-Server + Tachidesk-WebUI bundle)
Run `./gradlew server:downloadWebUI server:shadowJar`, the resulting built jar file will be `server/build/Tachidesk-Server-vX.Y.Z-rxxx.jar`.
### building the full-blown jar (Suwayomi-Server + Suwayomi-WebUI bundle)
Run `./gradlew server:downloadWebUI server:shadowJar`, the resulting built jar file will be `server/build/Suwayomi-Server-vX.Y.Z-rxxx.jar`.
### building without `webUI` bundled (server only)
Delete `server/src/main/resources/WebUI.zip` if exists from previous runs, then run `./gradlew server:shadowJar`, the resulting built jar file will be `server/build/Tachidesk-Server-vX.Y.Z-rxxx.jar`.
Delete `server/src/main/resources/WebUI.zip` if exists from previous runs, then run `./gradlew server:shadowJar`, the resulting built jar file will be `server/build/Suwayomi-Server-vX.Y.Z-rxxx.jar`.
### building the Windows package
First Build the jar, then cd into the `scripts` directory and run `./windows-bundler.sh win32` or `./windows-bundler.sh win64` depending on the target architecture, the resulting built zip package file will be `server/build/Tachidesk-Server-vX.Y.Z-rxxx-winXX.zip`.
First Build the jar, then cd into the `scripts` directory and run `./windows-bundler.sh win32` or `./windows-bundler.sh win64` depending on the target architecture, the resulting built zip package file will be `server/build/Suwayomi-Server-vX.Y.Z-rxxx-winXX.zip`.
## Running in development mode
run `./gradlew :server:run --stacktrace` to run the server
## Running tests
run `./gradlew :server:test` to execute all tests
to test a specific class run `./gradlew :server:test --tests <package.with.classname>`
## Building the android-jar maven repository
Run `AndroidCompat/getAndroid.sh`(macOS/Linux) or `AndroidCompat/getAndroid.ps1`(Windows)
from project's root directory to download and rebuild the jar file from Google's repository,
then use `AndroidCompat/lib/android.jar` to manually create a maven repository inside the `android-jar` git branch.
Update the dependency declaration afterwards.

171
README.md
View File

@@ -1,71 +1,115 @@
| Build | Stable | Preview | Support Server |
|-------|----------|---------|---------|
| ![CI](https://github.com/Suwayomi/Tachidesk/actions/workflows/build_push.yml/badge.svg) | [![stable release](https://img.shields.io/github/release/Suwayomi/Tachidesk.svg?maxAge=3600&label=download)](https://github.com/Suwayomi/Tachidesk/releases) | [![preview](https://img.shields.io/badge/dynamic/json?url=https://github.com/Suwayomi/Tachidesk-preview/raw/main/index.json&label=download&query=$.latest&color=blue)](https://github.com/Suwayomi/Tachidesk-preview/releases/latest) | [![Discord](https://img.shields.io/discord/801021177333940224.svg?label=discord&labelColor=7289da&color=2c2f33&style=flat)](https://discord.gg/DDZdqZWaHA) |
| Build | Stable | Preview | Support Server |
|-----------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------|
| ![CI](https://github.com/Suwayomi/Suwayomi-Server/actions/workflows/build_push.yml/badge.svg) | [![stable release](https://img.shields.io/github/release/Suwayomi/Suwayomi-Server.svg?maxAge=3600&label=download)](https://github.com/Suwayomi/Suwayomi-Server/releases) | [![preview](https://img.shields.io/badge/dynamic/json?url=https://github.com/Suwayomi/Suwayomi-Server-preview/raw/main/index.json&label=download&query=$.latest&color=blue)](https://github.com/Suwayomi/Suwayomi-Server-preview/releases/latest) | [![Discord](https://img.shields.io/discord/801021177333940224.svg?label=discord&labelColor=7289da&color=2c2f33&style=flat)](https://discord.gg/DDZdqZWaHA) |
# Tachidesk-Server is a server app! You may not want to Download Tachidesk-Server directly.
Yes, you need a client/user interface app as a front-end for Tachidesk-Server, if you Directly Download Tachidesk-Server you'll get a bundled version of [Tachodesk-WebUI](https://github.com/Suwayomi/Tachidesk-WebUI) with it.
## Table of Content
- [What is Suwayomi?](#what-is-suwayomi)
- [Suwayomi client projects](#Suwayomi-client-projects)
* [Is this application usable? Should I test it?](#is-this-application-usable-should-i-test-it)
- [Downloading and Running the app](#downloading-and-running-the-app)
* [Using Operating System Specific Bundles](#using-operating-system-specific-bundles)
- [Launcher Scripts](#launcher-scripts)
+ [Windows](#windows)
+ [macOS](#macos)
+ [GNU/Linux](#gnulinux)
* [Other methods of getting Suwayomi](#other-methods-of-getting-suwayomi)
+ [Arch Linux](#arch-linux)
+ [Ubuntu-based distributions](#ubuntu-based-distributions)
+ [Docker](#docker)
* [Advanced Methods](#advanced-methods)
+ [Running the jar release directly](#running-the-jar-release-directly)
+ [Using Suwayomi Remotely](#using-suwayomi-remotely)
- [Syncing With Tachiyomi](#syncing-with-tachiyomi)
- [Troubleshooting and Support](#troubleshooting-and-support)
- [Contributing and Technical info](#contributing-and-technical-info)
- [Credit](#credit)
- [License](#license)
<!-- Generated with https://ecotrust-canada.github.io/markdown-toc/ -->
Here's a list of known clients/user interfaces for Tachidesk-Server:
- [Tachidesk-JUI](https://github.com/Suwayomi/Tachidesk-JUI): The "official" front-end for Tachidesk-Server, A native desktop Application.
- [Tachidesk-WebUI](https://github.com/Suwayomi/Tachidesk-WebUI): The web/electrion front-end that Tachidesk is traditionally shipped with.
- [Tachidesk-qtui](https://github.com/Suwayomi/Tachidesk-qtui): A C++/Qt front-end for mobile devices(Android/linux), in super early stage of development.
- [Equinox](https://github.com/Suwayomi/Equinox): A web user interface made with Vue.js, in super early stage of development.
# What is Tachidesk then?
<img src="https://github.com/Suwayomi/Tachidesk/raw/master/server/src/main/resources/icon/faviconlogo.png" alt="drawing" width="200"/>
# What is Suwayomi?
<img src="https://github.com/Suwayomi/Suwayomi-Server/raw/master/server/src/main/resources/icon/faviconlogo.png" alt="drawing" width="200"/>
A free and open source manga reader server that runs extensions built for [Tachiyomi](https://tachiyomi.org/).
Tachidesk is an independent Tachiyomi compatible software and is **not a Fork of** Tachiyomi.
Suwayomi is an independent Tachiyomi compatible software and is **not a Fork of** Tachiyomi.
Tachidesk-Server is as multi-platform as you can get. Any platform that runs java and/or has a modern browser can run it. This includes Windows, Linux, macOS, chrome OS, etc. Follow [Downloading and Running the app](#downloading-and-running-the-app) for installation instructions.
Suwayomi-Server is as multi-platform as you can get. Any platform that runs java and/or has a modern browser can run it. This includes Windows, Linux, macOS, chrome OS, etc. Follow [Downloading and Running the app](#downloading-and-running-the-app) for installation instructions.
Ability to read and write Tachiyomi compatible backups and syncing is a planned feature.
Ability to sync with Tachiyomi is a planned feature, for more info look [here](#syncing-with-tachiyomi).
# Suwayomi client projects
**You need a client/user interface app as a front-end for Suwayomi-Server, if you [Directly Download Suwayomi-Server](https://github.com/Suwayomi/Suwayomi-Server/releases/latest) you'll get a bundled version of [Suwayomi-WebUI](https://github.com/Suwayomi/Suwayomi-WebUI) with it.**
Here's a list of known clients/user interfaces for Suwayomi-Server:
##### Actively Developed Clients
- [Suwayomi-WebUI](https://github.com/Suwayomi/Suwayomi-WebUI): The web/ElectronJS front-end that Suwayomi-Server ships with by default.
- [Tachidesk-JUI](https://github.com/Suwayomi/Tachidesk-JUI): The native desktop front-end for Suwayomi-Server. Currently, the most advanced.
- [Tachidesk-qtui](https://github.com/Suwayomi/Tachidesk-qtui): A C++/Qt front-end for mobile devices(Android/linux), feature support is basic.
- [Tachidesk-Sorayomi](https://github.com/Suwayomi/Tachidesk-Sorayomi): A Flutter front-end for Desktop(Linux, windows, etc.), Web and Android with a User Interface inspired by Tachiyomi.
- [Tachidesk-VaadinUI](https://github.com/Suwayomi/Tachidesk-VaadinUI): A Web front-end for Suwayomi-Server built with Vaadin.
- [Suwayomi-VUI](https://github.com/Suwayomi/Suwayomi-VUI): A preview focused web frontend built with svelte with some features the other UIs might not have (migration)
##### Inctive/Abandoned Clients
- [Equinox](https://github.com/Suwayomi/Equinox): A web user interface made with Vue.js.
- [Tachidesk-GTK](https://github.com/mahor1221/Tachidesk-GTK): A native Rust/GTK desktop client.
## Is this application usable? Should I test it?
Here is a list of current features:
- From Tachiyomi
- Installing and executing Tachiyomi's Extensions, So you'll get the same sources
- A library to save your mangas and categories to put them into
- Searching and browsing installed sources
- Ability to download Manga for offline read
- Backup and restore support powered by Tachiyomi Legacy Backups
- From Aniyomi
- Installing and executing Aniyomi's Extensions
- Searching and browsing installed sources.
- Viewing an anime and it's episodes
- Installing and executing Tachiyomi's Extensions, So you'll get the same sources
- A library to save your mangas and categories to put them into
- Searching and browsing installed sources
- Ability to download Manga for offline read
- Backup and restore support powered by Tachiyomi-compatible Backups
- Viewing latest updated chapters.
**Note:** These are capabilities of Tachidesk-Server, the actual working support is provided by each front-end app, checkout their respective readme for more info.
**Note:** These are capabilities of Suwayomi-Server, the actual working support is provided by each front-end app, checkout their respective readme for more info.
**Note:** Tachidesk-Server is alpha software and can break rarely and/or with each update. See [Troubleshooting](https://github.com/Suwayomi/Tachidesk-Server/wiki/Troubleshooting) if it happens.
# Downloading and Running the app
## Using Operating System Specific Bundles
To facilitate the use of Suwayomi we provide bundle releases that include The Java Runtime Environment, ElectronJS and the Suwayomi-Launcher.
## Downloading and Running the app
### All Operating Systems
You should have The Java Runtime Environment(JRE) 8 or newer and a modern browser installed(Google is your friend for seeking assitance). Also an internet connection is required as almost everything this app does is downloading stuff.
Download the latest "Stable" jar release from [the releases section](https://github.com/Suwayomi/Tachidesk/releases) or a preview jar build from [the preview repository](https://github.com/Suwayomi/Tachidesk-preview/releases).
Double click on the jar file or run `java -jar Tachidesk-vX.Y.Z-rxxx.jar` (or `java -jar Tachidesk-latest.jar` if you have the latest preview) from a Terminal/Command Prompt window to run the app which will open a new browser window automatically. Also the System Tray Icon is your friend if you need to open the browser window again or close Tachidesk.
If a bundle for your operating system or cpu architecture is not provided then refer to [Advanced Methods](#advanced-methods)
### Windows
Download the latest "Stable" win32 or win64 (depending on your system, usually you want win64) release from [the releases section](https://github.com/Suwayomi/Tachidesk/releases) or a preview one from [the preview repository](https://github.com/Suwayomi/Tachidesk-preview/releases).
Download the latest `win32`(Windows 32-bit) or `win64`(Windows 64-bit) release from [the releases section](https://github.com/Suwayomi/Suwayomi-Server/releases) or a preview one from [the preview repository](https://github.com/Suwayomi/Suwayomi-Server-preview/releases).
The Windows specific build has java bundled inside, so you don't have to install java to use it. Unzip `Tachidesk-vX.Y.Z-rxxx-win64.zip` and run one of the Launcher files depending on what you want(see bellow). The rest works like the previous section.
#### Windows Launchers
- `Tachidesk Electron Launcher.bat`: Launches Tachidesk inside Electron as a desktop applicaton
- `Tachidesk Browser Launcher.bat`: Launches Tachidesk in a browser window
- `Tachidesk Debug Launcher.bat`: Launches Tachidesk with debug logs attached. If Tachidesk doesn't work for you, running this can give you insight into why.
Unzip the downloaded file and double-click on one of the launcher scripts.
### macOS
Download the latest `macOS-x64`(older macOS systems) or `macOS-arm64`(Apple M1 and newer) release from [the releases section](https://github.com/Suwayomi/Suwayomi-Server/releases) or a preview one from [the preview repository](https://github.com/Suwayomi/Suwayomi-Server-preview/releases).
Unzip the downloaded file and double-click on one of the launcher scripts.
### GNU/Linux
Download the latest `linux-x64`(x86_64) release from [the releases section](https://github.com/Suwayomi/Suwayomi-Server/releases) or a preview one from [the preview repository](https://github.com/Suwayomi/Suwayomi-Server-preview/releases).
`tar xvf` the downloaded file and double-click on one of the launcher scripts or run them using the terminal.
## Other methods of getting Suwayomi
### Arch Linux
You can install Tachidesk from the AUR
You can install Suwayomi from the AUR:
```
yay -S tachidesk
```
### Debian/Ubuntu
Download the latest deb package from the release section or Install from the MPR
```
git clone https://mpr.makedeb.org/suwayomi-server.git
cd suwayomi-server
makedeb -si
```
### Ubuntu
```
sudo add-apt-repository ppa:suwayomi/suwayomi-server
sudo apt update
sudo apt install suwayomi-server
```
### Docker
Check our Offical Docker release [Tachidesk Container](https://github.com/orgs/Suwayomi/packages/container/package/tachidesk) or use [arbuilder's](https://github.com/arbuilder/Tachidesk-docker) tachidesk docker repo for installation. Source code for our container is available at [docker-tachidesk](https://github.com/Suwayomi/docker-tachidesk). By default the server will be running on http://localhost:4567 open this url in your browser.
Check our Official Docker release [Suwayomi Container](https://github.com/orgs/Suwayomi/packages/container/package/tachidesk) for running Suwayomi Server in a docker container. Source code for our container is available at [docker-tachidesk](https://github.com/Suwayomi/docker-tachidesk). By default, the server will be running on http://localhost:4567 open this url in your browser.
Install from the command line:
```
@@ -76,11 +120,38 @@ Run Container from the command line:
$ docker run -p 4567:4567 ghcr.io/suwayomi/tachidesk
```
### Using Tachidesk Remotely
You can run Tachidesk on your computer or a server and connect to it remotely through the web interface with a web browser on any device including a mobile or tablet or even your smart TV!, this method of using Tachidesk is only recommended if you are a power user and know what you are doing.
## Advanced Methods
### Running the jar release directly
In order to run the app you need the following:
- The jar release of Suwayomi-Server
- The Java Runtime Environment(JRE) 8 or newer
- A Browser like Google Chrome, Firefox, Edge, etc.
- ElectronJS (optional)
Download the latest `.jar` release from [the releases section](https://github.com/Suwayomi/Suwayomi-Server/releases) or a preview jar build from [the preview repository](https://github.com/Suwayomi/Suwayomi-Server-preview/releases).
Make sure you have The Java Runtime Environment installed on your system, Double-click on the jar file or run `java -jar Suwayomi-Server-vX.Y.Z-rxxxx.jar` from a Terminal/Command Prompt window to run the app which will open a new browser window automatically.
### Using Suwayomi Remotely
You can run Suwayomi on your computer or a server and connect to it remotely through one of our clients or the bundled web interface with a web browser. This method of using Suwayomi is requiring a bit of networking/firewall/port forwarding/server configuration/etc. knowledge on your side, if you can run a Minecraft server and configure it, then you are good to go.
Check out [this wiki page](https://github.com/Suwayomi/Suwayomi-Server/wiki/Configuring-Tachidesk-Server) for a guide on configuring Suwayomi-Server.
If you face issues with your setup then we are happy to provide help, just join our discord server(a discord badge is on the top of the page, you are just a click-clack away!).
## Syncing With Tachiyomi
### The Suwayomi extension and tracker
- You can install the `Suwayomi` extension inside tachiyomi.
- The extension will load your Suwayomi library.
- By manipulating extension search filters you can browse your categories.
- You can enable the Suwayomi tracker to track reading progress with your Suwayomi server.
- Note: Tachiyomi [only allows tracking one way](https://github.com/tachiyomiorg/tachiyomi/issues/1626), meaning that by reading chapters on other Suwayomi clients the last read chapter number will update on the tracker but tachiyomi won't automatically mark them as read for you.
### Other methods
Checkout [this issue](https://github.com/Suwayomi/Suwayomi-Server/issues/159) for tracking progress.
## Troubleshooting and Support
See [this troubleshooting wiki page](https://github.com/Suwayomi/Tachidesk/wiki/Troubleshooting).
See [this troubleshooting wiki page](https://github.com/Suwayomi/Suwayomi-Server/wiki/Troubleshooting).
## Contributing and Technical info
See [CONTRIBUTING.md](./CONTRIBUTING.md).
@@ -88,9 +159,9 @@ See [CONTRIBUTING.md](./CONTRIBUTING.md).
## Credit
This project is a spiritual successor of [TachiWeb-Server](https://github.com/Tachiweb/TachiWeb-server), Many of the ideas and the groundwork adopted in this project comes from TachiWeb.
The `AndroidCompat` module was originally developed by [@null-dev](https://github.com/null-dev) for [TachiWeb-Server](https://github.com/Tachiweb/TachiWeb-server) and is licensed under `Apache License Version 2.0`.
The `AndroidCompat` module was originally developed by [@null-dev](https://github.com/null-dev) for [TachiWeb-Server](https://github.com/Tachiweb/TachiWeb-server) and is licensed under `Apache License Version 2.0` and `Copyright 2019 Andy Bao and contributors`.
Parts of [tachiyomi](https://github.com/tachiyomiorg/tachiyomi) is adopted into this codebase, also licensed under `Apache License Version 2.0`.
Parts of [tachiyomi](https://github.com/tachiyomiorg/tachiyomi) is adopted into this codebase, also licensed under `Apache License Version 2.0` and `Copyright 2015 Javier Tomás`.
You can obtain a copy of `Apache License Version 2.0` from http://www.apache.org/licenses/LICENSE-2.0
@@ -103,3 +174,7 @@ Changes to both codebases is licensed under `MPL v. 2.0` as the rest of this pro
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
## Disclaimer
The developer of this application does not have any affiliation with the content providers available.

View File

@@ -1,8 +1,13 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile
import org.jlleitschuh.gradle.ktlint.KtlintExtension
import org.jlleitschuh.gradle.ktlint.KtlintPlugin
plugins {
kotlin("jvm") version kotlinVersion
kotlin("plugin.serialization") version kotlinVersion
alias(libs.plugins.kotlin.jvm)
alias(libs.plugins.kotlin.serialization)
alias(libs.plugins.ktlint)
alias(libs.plugins.buildconfig) apply false
alias(libs.plugins.download)
}
allprojects {
@@ -12,81 +17,39 @@ allprojects {
repositories {
mavenCentral()
maven("https://maven.google.com/")
google()
maven("https://github.com/Suwayomi/Suwayomi-Server/raw/android-jar/")
maven("https://jitpack.io")
maven("https://oss.sonatype.org/content/repositories/snapshots/")
maven("https://dl.google.com/dl/android/maven2/")
}
}
val projects = listOf(
project(":AndroidCompat"),
project(":AndroidCompat:Config"),
project(":server")
)
configure(projects) {
apply(plugin = "org.jetbrains.kotlin.jvm")
java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
tasks.withType<KotlinCompile> {
kotlinOptions {
jvmTarget = JavaVersion.VERSION_1_8.toString()
subprojects {
plugins.withType<JavaPlugin> {
extensions.configure<JavaPluginExtension> {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
}
dependencies {
// Kotlin
implementation(kotlin("stdlib-jdk8"))
implementation(kotlin("reflect"))
testImplementation(kotlin("test-junit5"))
// coroutines
val coroutinesVersion = "1.5.0"
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:$coroutinesVersion")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutinesVersion")
val kotlinSerializationVersion = "1.2.1"
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlinSerializationVersion")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-protobuf:$kotlinSerializationVersion")
// Dependency Injection
implementation("org.kodein.di:kodein-di-conf-jvm:7.5.0")
// Logging
implementation("org.slf4j:slf4j-api:1.7.30")
implementation("ch.qos.logback:logback-classic:1.2.3")
implementation("io.github.microutils:kotlin-logging:2.0.6")
// ReactiveX
implementation("io.reactivex:rxjava:1.3.8")
implementation("io.reactivex:rxkotlin:1.0.0")
implementation("com.jakewharton.rxrelay:rxrelay:1.2.0")
// JSoup
implementation("org.jsoup:jsoup:1.13.1")
// dependency of :AndroidCompat:Config
implementation("com.typesafe:config:1.4.1")
implementation("io.github.config4k:config4k:0.4.2")
// to get application content root
implementation("net.harawata:appdirs:1.2.1")
// dex2jar: https://github.com/DexPatcher/dex2jar/releases/tag/v2.1-20190905-lanchon
// note: watch https://github.com/ThexXTURBOXx/dex2jar for future developments
implementation("com.github.DexPatcher.dex2jar:dex-tools:v2.1-20190905-lanchon")
// APK parser
implementation("net.dongliu:apk-parser:2.6.10")
// Jackson
implementation("com.fasterxml.jackson.core:jackson-annotations:2.10.3")
plugins.withType<KtlintPlugin> {
extensions.configure<KtlintExtension>("ktlint") {
version.set(libs.versions.ktlint.get())
filter {
exclude("**/generated/**")
}
}
}
}
tasks {
withType<KotlinJvmCompile> {
dependsOn("ktlintFormat")
kotlinOptions {
jvmTarget = JavaVersion.VERSION_1_8.toString()
freeCompilerArgs += listOf(
"-Xcontext-receivers",
)
}
}
}
}

View File

@@ -7,5 +7,5 @@ repositories {
}
dependencies {
implementation("net.lingala.zip4j:zip4j:2.9.0")
}
implementation(libs.zip4j)
}

View File

@@ -0,0 +1,9 @@
rootProject.name = "buildSrc"
dependencyResolutionManagement {
versionCatalogs {
create("libs") {
from(files("../gradle/libs.versions.toml"))
}
}
}

View File

@@ -7,27 +7,27 @@ import java.io.BufferedReader
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
const val kotlinVersion = "1.5.21"
const val MainClass = "suwayomi.tachidesk.MainKt"
// should be bumped with each stable release
val tachideskVersion = System.getenv("ProductVersion") ?: "v0.4.7"
val tachideskVersion = System.getenv("ProductVersion") ?: "v0.7.0"
val webUIRevisionTag = System.getenv("WebUIRevision") ?: "r36"
val webUIRevisionTag = System.getenv("WebUIRevision") ?: "r1397"
// counts commits on the the master branch
val tachideskRevision = runCatching {
System.getenv("ProductRevision") ?: Runtime
.getRuntime()
.exec("git rev-list HEAD --count")
.let { process ->
process.waitFor()
val output = process.inputStream.use {
it.bufferedReader().use(BufferedReader::readText)
// counts commits on the current checked out branch
val getTachideskRevision = {
runCatching {
System.getenv("ProductRevision") ?: ProcessBuilder()
.command("git", "rev-list", "HEAD", "--count")
.start()
.let { process ->
process.waitFor()
val output = process.inputStream.use {
it.bufferedReader().use(BufferedReader::readText)
}
process.destroy()
"r" + output.trim()
}
process.destroy()
"r" + output.trim()
}
}.getOrDefault("r0")
}.getOrDefault("r0")
}

233
gradle/libs.versions.toml Normal file
View File

@@ -0,0 +1,233 @@
[versions]
kotlin = "1.9.10"
coroutines = "1.7.3"
serialization = "1.6.0"
okhttp = "5.0.0-alpha.11" # Major version is locked by Tachiyomi extensions
javalin = "4.6.8" # Javalin 5.0.0+ requires Java 11
jackson = "2.13.3" # jackson version locked by javalin, ref: `io.javalin.core.util.OptionalDependency`
exposed = "0.40.1"
dex2jar = "v64" # Stuck until https://github.com/ThexXTURBOXx/dex2jar/issues/27 is fixed
rhino = "1.7.14"
settings = "1.0.0-RC"
twelvemonkeys = "3.9.4"
graphqlkotlin = "6.5.6"
xmlserialization = "0.86.2"
ktlint = "1.0.0"
[libraries]
# Kotlin
kotlin-stdlib-jdk8 = { module = "org.jetbrains.kotlin:kotlin-stdlib-jdk8", version.ref = "kotlin" }
kotlin-reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlin" }
kotlin-test-junit5 = { module = "org.jetbrains.kotlin:kotlin-test-junit5", version.ref = "kotlin" }
# Coroutines
coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "coroutines" }
coroutines-jdk8 = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-jdk8", version.ref = "coroutines" }
coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "coroutines" }
# Serialization
serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "serialization" }
serialization-json-okio = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json-okio", version.ref = "serialization" }
serialization-protobuf = { module = "org.jetbrains.kotlinx:kotlinx-serialization-protobuf", version.ref = "serialization" }
serialization-xml-core = { module = "io.github.pdvrieze.xmlutil:core-jvm", version.ref = "xmlserialization" }
serialization-xml = { module = "io.github.pdvrieze.xmlutil:serialization-jvm", version.ref = "xmlserialization" }
# Logging
slf4japi = "org.slf4j:slf4j-api:2.0.9"
logback = "ch.qos.logback:logback-classic:1.3.11"
kotlinlogging = "io.github.microutils:kotlin-logging:3.0.5"
# OkHttp
okhttp-core = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" }
okhttp-logging = { module = "com.squareup.okhttp3:logging-interceptor", version.ref = "okhttp" }
okhttp-dnsoverhttps = { module = "com.squareup.okhttp3:okhttp-dnsoverhttps", version.ref = "okhttp" }
okhttp-brotli = { module = "com.squareup.okhttp3:okhttp-brotli", version.ref = "okhttp" }
okio = "com.squareup.okio:okio:3.3.0"
# Javalin api
javalin-core = { module = "io.javalin:javalin", version.ref = "javalin" }
javalin-openapi = { module = "io.javalin:javalin-openapi", version.ref = "javalin" }
jackson-databind = { module = "com.fasterxml.jackson.core:jackson-databind", version.ref = "jackson" }
jackson-kotlin = { module = "com.fasterxml.jackson.module:jackson-module-kotlin", version.ref = "jackson" }
jackson-annotations = { module = "com.fasterxml.jackson.core:jackson-annotations", version.ref = "jackson" }
# GraphQL
graphql-kotlin-server = { module = "com.expediagroup:graphql-kotlin-server", version.ref = "graphqlkotlin" }
graphql-kotlin-scheme = { module = "com.expediagroup:graphql-kotlin-schema-generator", version.ref = "graphqlkotlin" }
graphql-scalars = "com.graphql-java:graphql-java-extended-scalars:20.2"
# Exposed ORM
exposed-core = { module = "org.jetbrains.exposed:exposed-core", version.ref = "exposed" }
exposed-dao = { module = "org.jetbrains.exposed:exposed-dao", version.ref = "exposed" }
exposed-jdbc = { module = "org.jetbrains.exposed:exposed-jdbc", version.ref = "exposed" }
exposed-javatime = { module = "org.jetbrains.exposed:exposed-java-time", version.ref = "exposed" }
h2 = "com.h2database:h2:1.4.200" # current database driver, can't update to h2 v2 without sql migration
# Exposed Migrations
exposed-migrations = "com.github.Suwayomi:exposed-migrations:3.2.0"
# Dependency Injection
kodein = "org.kodein.di:kodein-di-conf-jvm:7.20.2"
# tray icon
systemtray-core = "com.dorkbox:SystemTray:4.2.1"
systemtray-utils = "com.dorkbox:Utilities:1.39" # version locked by SystemTray
systemtray-desktop = "com.dorkbox:Desktop:1.0"
# dependencies of Tachiyomi extensions
injekt = "com.github.inorichi.injekt:injekt-core:65b0440"
rxjava = "io.reactivex:rxjava:1.3.8"
jsoup = "org.jsoup:jsoup:1.16.1"
# Config
config = "com.typesafe:config:1.4.2"
config4k = "io.github.config4k:config4k:0.5.0"
# Sort
sort = "com.github.gpanther:java-nat-sort:natural-comparator-1.1"
# Android stub library
android-stubs = "com.github.Suwayomi:android-jar:1.0.0"
# Asm modificiation
asm = "org.ow2.asm:asm:9.5" # version locked by Dex2Jar
dex2jar-translator = { module = "com.github.ThexXTURBOXx.dex2jar:dex-translator", version.ref = "dex2jar" }
dex2jar-tools = { module = "com.github.ThexXTURBOXx.dex2jar:dex-tools", version.ref = "dex2jar" }
# APK
apk-parser = "net.dongliu:apk-parser:2.6.10"
apksig = "com.android.tools.build:apksig:7.2.1"
# Xml
xmlpull = "xmlpull:xmlpull:1.1.3.4a"
# Disk & File
appdirs = "net.harawata:appdirs:1.2.1"
zip4j = "net.lingala.zip4j:zip4j:2.11.5"
commonscompress = "org.apache.commons:commons-compress:1.24.0"
junrar = "com.github.junrar:junrar:7.5.5"
# AES/CBC/PKCS7Padding Cypher provider
bouncycastle = "org.bouncycastle:bcprov-jdk18on:1.76"
# AndroidX annotations
android-annotations = "androidx.annotation:annotation:1.7.0"
# Substitute for duktape-android
rhino-runtime = { module = "org.mozilla:rhino-runtime", version.ref = "rhino" } # slimmer version of 'org.mozilla:rhino'
rhino-engine = { module = "org.mozilla:rhino-engine", version.ref = "rhino" } # provides the same interface as 'javax.script' a.k.a Nashorn
# Settings
settings-core = { module = "com.russhwolf:multiplatform-settings-jvm", version.ref = "settings" }
settings-serialization = { module = "com.russhwolf:multiplatform-settings-serialization-jvm", version.ref = "settings" }
# ICU4J
icu4j = "com.ibm.icu:icu4j:73.2"
# Image Decoding implementation provider
twelvemonkeys-common-lang = { module = "com.twelvemonkeys.common:common-lang", version.ref = "twelvemonkeys" }
twelvemonkeys-common-io = { module = "com.twelvemonkeys.common:common-io", version.ref = "twelvemonkeys" }
twelvemonkeys-common-image = { module = "com.twelvemonkeys.common:common-image", version.ref = "twelvemonkeys" }
twelvemonkeys-imageio-core = { module = "com.twelvemonkeys.imageio:imageio-core", version.ref = "twelvemonkeys" }
twelvemonkeys-imageio-metadata = { module = "com.twelvemonkeys.imageio:imageio-metadata", version.ref = "twelvemonkeys" }
twelvemonkeys-imageio-jpeg = { module = "com.twelvemonkeys.imageio:imageio-jpeg", version.ref = "twelvemonkeys" }
twelvemonkeys-imageio-webp = { module = "com.twelvemonkeys.imageio:imageio-webp", version.ref = "twelvemonkeys" }
# Testing
mockk = "io.mockk:mockk:1.13.7"
# cron scheduler
cron4j = "it.sauronsoftware.cron4j:cron4j:2.2.5"
# cron-utils
cronUtils = "com.cronutils:cron-utils:9.2.1"
[plugins]
# Kotlin
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin"}
kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin"}
# Linter
ktlint = { id = "org.jlleitschuh.gradle.ktlint", version = "11.6.0"}
# Build config
buildconfig = { id = "com.github.gmazzo.buildconfig", version = "3.1.0"}
# Download
download = { id = "de.undercouch.download", version = "5.4.0"}
# ShadowJar
shadowjar = { id = "com.github.johnrengelman.shadow", version = "8.1.1"}
[bundles]
shared = [
"kotlin-stdlib-jdk8",
"kotlin-reflect",
"coroutines-core",
"coroutines-jdk8",
"serialization-json",
"serialization-json-okio",
"serialization-protobuf",
"kodein",
"slf4japi",
"logback",
"kotlinlogging",
"appdirs",
"rxjava",
"jsoup",
"config",
"config4k",
"dex2jar-translator",
"dex2jar-tools",
"apk-parser",
"jackson-annotations"
]
sharedTest = [
"kotlin-test-junit5",
"coroutines-test",
]
okhttp = [
"okhttp-core",
"okhttp-logging",
"okhttp-dnsoverhttps",
"okhttp-brotli",
]
javalin = [
"javalin-core",
"javalin-openapi",
]
jackson = [
"jackson-databind",
"jackson-kotlin",
"jackson-annotations",
]
exposed = [
"exposed-core",
"exposed-dao",
"exposed-jdbc",
"exposed-javatime",
]
systemtray = [
"systemtray-core",
"systemtray-utils",
"systemtray-desktop"
]
rhino = [
"rhino-runtime",
"rhino-engine",
]
settings = [
"settings-core",
"settings-serialization",
]
twelvemonkeys = [
"twelvemonkeys-common-lang",
"twelvemonkeys-common-io",
"twelvemonkeys-common-image",
"twelvemonkeys-imageio-core",
"twelvemonkeys-imageio-metadata",
"twelvemonkeys-imageio-jpeg",
"twelvemonkeys-imageio-webp",
]

Binary file not shown.

View File

@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

275
gradlew vendored
View File

@@ -1,7 +1,7 @@
#!/usr/bin/env sh
#!/bin/sh
#
# Copyright 2015 the original author or authors.
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -17,67 +17,101 @@
#
##############################################################################
##
## Gradle start up script for UN*X
##
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
APP_BASE_NAME=${0##*/}
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
MAX_FD=maximum
warn () {
echo "$*"
}
} >&2
die () {
echo
echo "$*"
echo
exit 1
}
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
@@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD="$JAVA_HOME/bin/java"
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
@@ -106,80 +140,101 @@ location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"

14
gradlew.bat vendored
View File

@@ -14,7 +14,7 @@
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@@ -25,7 +25,7 @@
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
if "%DIRNAME%"=="" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@@ -40,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -75,13 +75,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal

314
scripts/bundler.sh Executable file
View File

@@ -0,0 +1,314 @@
#!/bin/bash
# Copyright (C) Contributors to the Suwayomi project
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
main() {
POSITIONAL_ARGS=()
OUTPUT_DIR=.
while [ "$#" -gt 0 ]; do
case "$1" in
-o|--output-dir)
OUTPUT_DIR="$(readlink -e "$2" || exit 1)"
shift
shift
;;
*)
POSITIONAL_ARGS+=("$1")
shift
;;
esac
done
# restore positional parameters
set -- "${POSITIONAL_ARGS[@]}"
OS="$1"
JAR="$(ls server/build/*.jar | tail -n1)"
RELEASE_NAME="$(echo "${JAR%.*}" | xargs basename)-$OS"
RELEASE_VERSION="$(tmp="${JAR%-*}"; echo "${tmp##*-}" | tr -d v)"
#RELEASE_REVISION_NUMBER="$(tmp="${JAR%.*}" && echo "${tmp##*-}" | tr -d r)"
local electron_version="v28.1.3"
# clean temporary directory on function return
trap "rm -rf $RELEASE_NAME/" RETURN
mkdir "$RELEASE_NAME/"
download_launcher
case "$OS" in
debian-all)
RELEASE="$RELEASE_NAME.deb"
make_deb_package
move_release_to_output_dir
;;
linux-assets)
RELEASE="$RELEASE_NAME.tar.gz"
copy_linux_package_assets_to "$RELEASE_NAME/"
tar -I "gzip -9" -cvf "$RELEASE" "$RELEASE_NAME/"
move_release_to_output_dir
;;
linux-x64)
# https://github.com/adoptium/temurin8-binaries/releases/
JRE_RELEASE="jdk8u392-b08"
JRE="OpenJDK8U-jre_x64_linux_hotspot_$(echo "$JRE_RELEASE" | sed 's/jdk//;s/-//g').tar.gz"
JRE_DIR="$JRE_RELEASE-jre"
JRE_URL="https://github.com/adoptium/temurin8-binaries/releases/download/$JRE_RELEASE/$JRE"
ELECTRON="electron-$electron_version-linux-x64.zip"
ELECTRON_URL="https://github.com/electron/electron/releases/download/$electron_version/$ELECTRON"
download_jre_and_electron
RELEASE="$RELEASE_NAME.tar.gz"
make_linux_bundle
move_release_to_output_dir
;;
macOS-x64)
# https://github.com/adoptium/temurin8-binaries/releases/
JRE_RELEASE="jdk8u392-b08"
JRE="OpenJDK8U-jre_x64_mac_hotspot_$(echo "$JRE_RELEASE" | sed 's/jdk//;s/-//g').tar.gz"
JRE_DIR="$JRE_RELEASE-jre"
JRE_URL="https://github.com/adoptium/temurin8-binaries/releases/download/$JRE_RELEASE/$JRE"
ELECTRON="electron-$electron_version-darwin-x64.zip"
ELECTRON_URL="https://github.com/electron/electron/releases/download/$electron_version/$ELECTRON"
download_jre_and_electron
RELEASE="$RELEASE_NAME.zip"
make_macos_bundle
move_release_to_output_dir
;;
macOS-arm64)
# https://cdn.azul.com/zulu/bin/
JRE="zulu8.74.0.17-ca-jre8.0.392-macosx_aarch64.tar.gz"
JRE_RELEASE="zulu8.74.0.17-ca-jre8.0.392-macosx_aarch64"
JRE_DIR="$JRE_RELEASE/zulu-8.jre"
JRE_URL="https://cdn.azul.com/zulu/bin/$JRE"
ELECTRON="electron-$electron_version-darwin-arm64.zip"
ELECTRON_URL="https://github.com/electron/electron/releases/download/$electron_version/$ELECTRON"
download_jre_and_electron
RELEASE="$RELEASE_NAME.zip"
make_macos_bundle
move_release_to_output_dir
;;
windows-x86)
# https://github.com/adoptium/temurin8-binaries/releases/
JRE_RELEASE="jdk8u392-b08"
JRE="OpenJDK8U-jre_x86-32_windows_hotspot_$(echo "$JRE_RELEASE" | sed 's/jdk//;s/-//g').zip"
JRE_DIR="$JRE_RELEASE-jre"
JRE_URL="https://github.com/adoptium/temurin8-binaries/releases/download/$JRE_RELEASE/$JRE"
ELECTRON="electron-$electron_version-win32-ia32.zip"
ELECTRON_URL="https://github.com/electron/electron/releases/download/$electron_version/$ELECTRON"
download_jre_and_electron
RELEASE="$RELEASE_NAME.zip"
make_windows_bundle
move_release_to_output_dir
RELEASE="$RELEASE_NAME.msi"
make_windows_package
move_release_to_output_dir
;;
windows-x64)
# https://github.com/adoptium/temurin8-binaries/releases/
JRE_RELEASE="jdk8u392-b08"
JRE="OpenJDK8U-jre_x64_windows_hotspot_$(echo "$JRE_RELEASE" | sed 's/jdk//;s/-//g').zip"
JRE_DIR="$JRE_RELEASE-jre"
JRE_URL="https://github.com/adoptium/temurin8-binaries/releases/download/$JRE_RELEASE/$JRE"
ELECTRON="electron-$electron_version-win32-x64.zip"
ELECTRON_URL="https://github.com/electron/electron/releases/download/$electron_version/$ELECTRON"
download_jre_and_electron
RELEASE="$RELEASE_NAME.zip"
make_windows_bundle
move_release_to_output_dir
RELEASE="$RELEASE_NAME.msi"
make_windows_package
move_release_to_output_dir
;;
*)
error $LINENO "Unsupported operating system: $OS" 2
;;
esac
}
move_release_to_output_dir() {
# clean up from possible previous runs
if [ -f "$OUTPUT_DIR/$RELEASE" ]; then
rm "$OUTPUT_DIR/$RELEASE"
fi
mv "$RELEASE" "$OUTPUT_DIR/"
}
download_launcher() {
LAUNCHER_URL=$(curl -s "https://api.github.com/repos/Suwayomi/Suwayomi-Launcher/releases/latest" | grep "browser_download_url" | grep ".jar" | head -n 1 | cut -d '"' -f 4)
curl -L "$LAUNCHER_URL" -o "Suwayomi-Launcher.jar"
mv "Suwayomi-Launcher.jar" "$RELEASE_NAME/Suwayomi-Launcher.jar"
}
download_jre_and_electron() {
if [ ! -f "$JRE" ]; then
curl -L "$JRE_URL" -o "$JRE"
fi
if [ ! -f "$ELECTRON" ]; then
curl -L "$ELECTRON_URL" -o "$ELECTRON"
fi
local ext="${JRE##*.}"
if [ "$ext" = "zip" ]; then
unzip "$JRE"
else
tar xvf "$JRE"
fi
mv "$JRE_DIR" "$RELEASE_NAME/jre"
unzip "$ELECTRON" -d "$RELEASE_NAME/electron/"
mkdir "$RELEASE_NAME/bin"
tree
}
copy_linux_package_assets_to() {
local output_dir
output_dir="$(readlink -e "$1" || exit 1)"
cp "scripts/resources/pkg/suwayomi-server.sh" "$output_dir/"
cp "scripts/resources/pkg/suwayomi-server.desktop" "$output_dir/"
cp "scripts/resources/pkg/suwayomi-launcher.sh" "$output_dir/"
cp "scripts/resources/pkg/suwayomi-launcher.desktop" "$output_dir/"
cp "scripts/resources/pkg/systemd"/* "$output_dir/"
cp "server/src/main/resources/icon/faviconlogo-128.png" \
"$output_dir/suwayomi-server.png"
}
make_linux_bundle() {
cp "$JAR" "$RELEASE_NAME/bin/Suwayomi-Server.jar"
cp "scripts/resources/suwayomi-launcher.sh" "$RELEASE_NAME/"
cp "scripts/resources/suwayomi-server.sh" "$RELEASE_NAME/"
tar -I "gzip -9" -cvf "$RELEASE" "$RELEASE_NAME/"
}
make_macos_bundle() {
cp "$JAR" "$RELEASE_NAME/bin/Suwayomi-Server.jar"
cp "scripts/resources/Suwayomi Launcher.command" "$RELEASE_NAME/"
zip -9 -r "$RELEASE" "$RELEASE_NAME/"
}
# https://wiki.debian.org/SimplePackagingTutorial
# https://www.debian.org/doc/manuals/packaging-tutorial/packaging-tutorial.pdf
make_deb_package() {
#behind $RELEASE_VERSION is hyphen "-"
local source_dir="suwayomi-server-$RELEASE_VERSION"
#behind $RELEASE_VERSION is underscore "_"
local upstream_source="suwayomi-server_$RELEASE_VERSION.orig.tar.gz"
mkdir "$RELEASE_NAME/$source_dir/"
mv "$RELEASE_NAME/Suwayomi-Launcher.jar" "$RELEASE_NAME/$source_dir/Suwayomi-Launcher.jar"
cp "$JAR" "$RELEASE_NAME/$source_dir/Suwayomi-Server.jar"
copy_linux_package_assets_to "$RELEASE_NAME/$source_dir/"
tar -I "gzip" -C "$RELEASE_NAME/" -cvf "$upstream_source" "$source_dir"
cp -r "scripts/resources/deb/" "$RELEASE_NAME/$source_dir/debian/"
sed -i "s/\$pkgver/$RELEASE_VERSION/" "$RELEASE_NAME/$source_dir/debian/changelog"
sed -i "s/\$pkgrel/1/" "$RELEASE_NAME/$source_dir/debian/changelog"
sudo apt update
sudo apt install devscripts build-essential dh-exec
cd "$RELEASE_NAME/$source_dir/"
dpkg-buildpackage --no-sign --build=all
cd -
local deb="suwayomi-server_$RELEASE_VERSION-1_all.deb"
mv "$RELEASE_NAME/$deb" "$RELEASE"
}
make_windows_bundle() {
## I disabled this section until someone find a solution to this error:
##E: Unable to correct problems, you have held broken packages.
##./bundler.sh: line 250: wine: command not found
## check if running under github actions
#if [ "$CI" = true ]; then
## change electron executable's icon
#sudo dpkg --add-architecture i386
#wget -qO - https://dl.winehq.org/wine-builds/winehq.key \
#| sudo apt-key add -
#sudo add-apt-repository ppa:cybermax-dexter/sdl2-backport
#sudo apt-add-repository "deb https://dl.winehq.org/wine-builds/ubuntu \
#$(lsb_release -cs) main"
#sudo apt install --install-recommends winehq-stable
#fi
## this script assumes that wine is installed here on out
#local rcedit="rcedit-x85.exe"
#local rcedit_url="https://github.com/electron/rcedit/releases/download/v0.1.1/$rcedit"
## change electron's icon
#if [ ! -f "$rcedit" ]; then
#curl -L "$rcedit_url" -o "$rcedit"
#fi
#local icon="server/src/main/resources/icon/faviconlogo.ico"
#WINEARCH=win32 wine "$rcedit" "$RELEASE_NAME/electron/electron.exe" \
# --set-icon "$icon"
cp "$JAR" "$RELEASE_NAME/bin/Suwayomi-Server.jar"
cp "scripts/resources/Suwayomi Launcher.bat" "$RELEASE_NAME"
zip -9 -r "$RELEASE" "$RELEASE_NAME"
}
make_windows_package() {
if [ "$CI" = true ]; then
sudo apt update
sudo apt install -y wixl
fi
find "$RELEASE_NAME/jre" \
| wixl-heat --var var.SourceDir -p "$RELEASE_NAME/" \
--directory-ref jre --component-group jre >"$RELEASE_NAME/jre.wxs"
find "$RELEASE_NAME/electron" \
| wixl-heat --var var.SourceDir -p "$RELEASE_NAME/" \
--directory-ref electron --component-group electron >"$RELEASE_NAME/electron.wxs"
find "$RELEASE_NAME/bin" \
| wixl-heat --var var.SourceDir -p "$RELEASE_NAME/" \
--directory-ref bin --component-group bin >"$RELEASE_NAME/bin.wxs"
local icon="server/src/main/resources/icon/faviconlogo.ico"
local arch=${OS##*-}
wixl -D ProductVersion="$RELEASE_VERSION" -D SourceDir="$RELEASE_NAME" \
-D Icon="$icon" --arch "$arch" "scripts/resources/msi/suwayomi-server-$arch.wxs" \
"$RELEASE_NAME/jre.wxs" "$RELEASE_NAME/electron.wxs" "$RELEASE_NAME/bin.wxs" -o "$RELEASE"
}
# Error handler
# set -u: Treat unset variables as an error when substituting.
# set -o pipefail: Prevents errors in pipeline from being masked.
# set -e: Immediatly exit if any command has a non-zero exit status.
# set -E: Inherit the trap ERR function before exiting by set.
#
# set -e is not recommended and unpredictable.
# see https://stackoverflow.com/questions/64786/error-handling-in-bash
# and http://mywiki.wooledge.org/BashFAO/105
set -uo pipefail
error() {
local parent_lineno="$1"
local message="$2"
local code="${3:-1}"
if [ -z "$message" ]; then
echo "$0: line $parent_lineno: exiting with status $code"
else
echo "$0: line $parent_lineno: $message: exiting with status $code"
fi
exit "$code"
}
trap 'error $LINENO ""' ERR
main "$@"; exit

View File

@@ -0,0 +1 @@
start "" jre/bin/javaw -jar Suwayomi-Launcher.jar

View File

@@ -0,0 +1,3 @@
cd "`dirname "$0"`"
./jre/Contents/Home/bin/java -jar Suwayomi-Launcher.jar

View File

@@ -1 +0,0 @@
start "" jre/bin/javaw -jar Tachidesk.jar

View File

@@ -1,7 +0,0 @@
:: cleaner output
@echo off
jre\bin\java -Dsuwayomi.tachidesk.config.server.debugLogsEnabled=true -jar Tachidesk.jar
:: Prevent cmd from closing when Tachidesk crashes
pause

View File

@@ -1 +0,0 @@
jre\bin\javaw "-Dsuwayomi.tachidesk.config.server.webUIInterface=electron" "-Dsuwayomi.tachidesk.config.server.electronPath=electron/electron.exe" -jar Tachidesk.jar

View File

@@ -0,0 +1,5 @@
suwayomi-server ($pkgver-$pkgrel) unstable; urgency=medium
* See CHANGELOG.md on https://github.com/Suwayomi/Suwayomi-Server
-- Mahor1221 <mahor1221@pm.me> Fri, 14 Jan 2022 00:00:00 +0000

View File

@@ -0,0 +1,14 @@
Source: suwayomi-server
Section: web
Priority: optional
Maintainer: Mahor1221 <mahor1221@pm.me>
Build-Depends: debhelper-compat (= 13), dh-exec
Standards-Version: 4.5.1
Homepage: https://github.com/Suwayomi/Suwayomi-Server
Package: suwayomi-server
Architecture: all
Depends: ${misc:Depends}, java8-runtime, libc++-dev
Description: Manga Reader
A free and open source manga reader server that runs extensions built for Tachiyomi.
Suwayomi is an independent Tachiyomi compatible software and is not a Fork of Tachiyomi.

View File

@@ -0,0 +1,381 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: suwayomi-server
Upstream-Contact: https://discord.gg/DDZdqZWaHA
Source: https://github.com/Suwayomi/Suwayomi-Server
Files: *
Copyright: Contributors to the Suwayomi project
License: MPL-2.0
Mozilla Public License Version 2.0
==================================
.
1. Definitions
--------------
.
1.1. "Contributor"
means each individual or legal entity that creates, contributes to
the creation of, or owns Covered Software.
.
1.2. "Contributor Version"
means the combination of the Contributions of others (if any) used
by a Contributor and that particular Contributor's Contribution.
.
1.3. "Contribution"
means Covered Software of a particular Contributor.
.
1.4. "Covered Software"
means Source Code Form to which the initial Contributor has attached
the notice in Exhibit A, the Executable Form of such Source Code
Form, and Modifications of such Source Code Form, in each case
including portions thereof.
.
1.5. "Incompatible With Secondary Licenses"
means
.
(a) that the initial Contributor has attached the notice described
in Exhibit B to the Covered Software; or
.
(b) that the Covered Software was made available under the terms of
version 1.1 or earlier of the License, but not also under the
terms of a Secondary License.
.
1.6. "Executable Form"
means any form of the work other than Source Code Form.
.
1.7. "Larger Work"
means a work that combines Covered Software with other material, in
a separate file or files, that is not Covered Software.
.
1.8. "License"
means this document.
.
1.9. "Licensable"
means having the right to grant, to the maximum extent possible,
whether at the time of the initial grant or subsequently, any and
all of the rights conveyed by this License.
.
1.10. "Modifications"
means any of the following:
.
(a) any file in Source Code Form that results from an addition to,
deletion from, or modification of the contents of Covered
Software; or
.
(b) any new file in Source Code Form that contains any Covered
Software.
.
1.11. "Patent Claims" of a Contributor
means any patent claim(s), including without limitation, method,
process, and apparatus claims, in any patent Licensable by such
Contributor that would be infringed, but for the grant of the
License, by the making, using, selling, offering for sale, having
made, import, or transfer of either its Contributions or its
Contributor Version.
.
1.12. "Secondary License"
means either the GNU General Public License, Version 2.0, the GNU
Lesser General Public License, Version 2.1, the GNU Affero General
Public License, Version 3.0, or any later versions of those
licenses.
.
1.13. "Source Code Form"
means the form of the work preferred for making modifications.
.
1.14. "You" (or "Your")
means an individual or a legal entity exercising rights under this
License. For legal entities, "You" includes any entity that
controls, is controlled by, or is under common control with You. For
purposes of this definition, "control" means (a) the power, direct
or indirect, to cause the direction or management of such entity,
whether by contract or otherwise, or (b) ownership of more than
fifty percent (50%) of the outstanding shares or beneficial
ownership of such entity.
.
2. License Grants and Conditions
--------------------------------
.
2.1. Grants
.
Each Contributor hereby grants You a world-wide, royalty-free,
non-exclusive license:
.
(a) under intellectual property rights (other than patent or trademark)
Licensable by such Contributor to use, reproduce, make available,
modify, display, perform, distribute, and otherwise exploit its
Contributions, either on an unmodified basis, with Modifications, or
as part of a Larger Work; and
.
(b) under Patent Claims of such Contributor to make, use, sell, offer
for sale, have made, import, and otherwise transfer either its
Contributions or its Contributor Version.
.
2.2. Effective Date
.
The licenses granted in Section 2.1 with respect to any Contribution
become effective for each Contribution on the date the Contributor first
distributes such Contribution.
.
2.3. Limitations on Grant Scope
.
The licenses granted in this Section 2 are the only rights granted under
this License. No additional rights or licenses will be implied from the
distribution or licensing of Covered Software under this License.
Notwithstanding Section 2.1(b) above, no patent license is granted by a
Contributor:
.
(a) for any code that a Contributor has removed from Covered Software;
or
.
(b) for infringements caused by: (i) Your and any other third party's
modifications of Covered Software, or (ii) the combination of its
Contributions with other software (except as part of its Contributor
Version); or
.
(c) under Patent Claims infringed by Covered Software in the absence of
its Contributions.
.
This License does not grant any rights in the trademarks, service marks,
or logos of any Contributor (except as may be necessary to comply with
the notice requirements in Section 3.4).
.
2.4. Subsequent Licenses
.
No Contributor makes additional grants as a result of Your choice to
distribute the Covered Software under a subsequent version of this
License (see Section 10.2) or under the terms of a Secondary License (if
permitted under the terms of Section 3.3).
.
2.5. Representation
.
Each Contributor represents that the Contributor believes its
Contributions are its original creation(s) or it has sufficient rights
to grant the rights to its Contributions conveyed by this License.
.
2.6. Fair Use
.
This License is not intended to limit any rights You have under
applicable copyright doctrines of fair use, fair dealing, or other
equivalents.
.
2.7. Conditions
.
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
in Section 2.1.
.
3. Responsibilities
-------------------
.
3.1. Distribution of Source Form
.
All distribution of Covered Software in Source Code Form, including any
Modifications that You create or to which You contribute, must be under
the terms of this License. You must inform recipients that the Source
Code Form of the Covered Software is governed by the terms of this
License, and how they can obtain a copy of this License. You may not
attempt to alter or restrict the recipients' rights in the Source Code
Form.
.
3.2. Distribution of Executable Form
.
If You distribute Covered Software in Executable Form then:
.
(a) such Covered Software must also be made available in Source Code
Form, as described in Section 3.1, and You must inform recipients of
the Executable Form how they can obtain a copy of such Source Code
Form by reasonable means in a timely manner, at a charge no more
than the cost of distribution to the recipient; and
.
(b) You may distribute such Executable Form under the terms of this
License, or sublicense it under different terms, provided that the
license for the Executable Form does not attempt to limit or alter
the recipients' rights in the Source Code Form under this License.
.
3.3. Distribution of a Larger Work
.
You may create and distribute a Larger Work under terms of Your choice,
provided that You also comply with the requirements of this License for
the Covered Software. If the Larger Work is a combination of Covered
Software with a work governed by one or more Secondary Licenses, and the
Covered Software is not Incompatible With Secondary Licenses, this
License permits You to additionally distribute such Covered Software
under the terms of such Secondary License(s), so that the recipient of
the Larger Work may, at their option, further distribute the Covered
Software under the terms of either this License or such Secondary
License(s).
.
3.4. Notices
.
You may not remove or alter the substance of any license notices
(including copyright notices, patent notices, disclaimers of warranty,
or limitations of liability) contained within the Source Code Form of
the Covered Software, except that You may alter any license notices to
the extent required to remedy known factual inaccuracies.
.
3.5. Application of Additional Terms
.
You may choose to offer, and to charge a fee for, warranty, support,
indemnity or liability obligations to one or more recipients of Covered
Software. However, You may do so only on Your own behalf, and not on
behalf of any Contributor. You must make it absolutely clear that any
such warranty, support, indemnity, or liability obligation is offered by
You alone, and You hereby agree to indemnify every Contributor for any
liability incurred by such Contributor as a result of warranty, support,
indemnity or liability terms You offer. You may include additional
disclaimers of warranty and limitations of liability specific to any
jurisdiction.
.
4. Inability to Comply Due to Statute or Regulation
---------------------------------------------------
.
If it is impossible for You to comply with any of the terms of this
License with respect to some or all of the Covered Software due to
statute, judicial order, or regulation then You must: (a) comply with
the terms of this License to the maximum extent possible; and (b)
describe the limitations and the code they affect. Such description must
be placed in a text file included with all distributions of the Covered
Software under this License. Except to the extent prohibited by statute
or regulation, such description must be sufficiently detailed for a
recipient of ordinary skill to be able to understand it.
.
5. Termination
--------------
.
5.1. The rights granted under this License will terminate automatically
if You fail to comply with any of its terms. However, if You become
compliant, then the rights granted under this License from a particular
Contributor are reinstated (a) provisionally, unless and until such
Contributor explicitly and finally terminates Your grants, and (b) on an
ongoing basis, if such Contributor fails to notify You of the
non-compliance by some reasonable means prior to 60 days after You have
come back into compliance. Moreover, Your grants from a particular
Contributor are reinstated on an ongoing basis if such Contributor
notifies You of the non-compliance by some reasonable means, this is the
first time You have received notice of non-compliance with this License
from such Contributor, and You become compliant prior to 30 days after
Your receipt of the notice.
.
5.2. If You initiate litigation against any entity by asserting a patent
infringement claim (excluding declaratory judgment actions,
counter-claims, and cross-claims) alleging that a Contributor Version
directly or indirectly infringes any patent, then the rights granted to
You by any and all Contributors for the Covered Software under Section
2.1 of this License shall terminate.
.
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
end user license agreements (excluding distributors and resellers) which
have been validly granted by You or Your distributors under this License
prior to termination shall survive termination.
.
************************************************************************
* *
* 6. Disclaimer of Warranty *
* ------------------------- *
* *
* Covered Software is provided under this License on an "as is" *
* basis, without warranty of any kind, either expressed, implied, or *
* statutory, including, without limitation, warranties that the *
* Covered Software is free of defects, merchantable, fit for a *
* particular purpose or non-infringing. The entire risk as to the *
* quality and performance of the Covered Software is with You. *
* Should any Covered Software prove defective in any respect, You *
* (not any Contributor) assume the cost of any necessary servicing, *
* repair, or correction. This disclaimer of warranty constitutes an *
* essential part of this License. No use of any Covered Software is *
* authorized under this License except under this disclaimer. *
* *
************************************************************************
.
************************************************************************
* *
* 7. Limitation of Liability *
* -------------------------- *
* *
* Under no circumstances and under no legal theory, whether tort *
* (including negligence), contract, or otherwise, shall any *
* Contributor, or anyone who distributes Covered Software as *
* permitted above, be liable to You for any direct, indirect, *
* special, incidental, or consequential damages of any character *
* including, without limitation, damages for lost profits, loss of *
* goodwill, work stoppage, computer failure or malfunction, or any *
* and all other commercial damages or losses, even if such party *
* shall have been informed of the possibility of such damages. This *
* limitation of liability shall not apply to liability for death or *
* personal injury resulting from such party's negligence to the *
* extent applicable law prohibits such limitation. Some *
* jurisdictions do not allow the exclusion or limitation of *
* incidental or consequential damages, so this exclusion and *
* limitation may not apply to You. *
* *
************************************************************************
.
8. Litigation
-------------
.
Any litigation relating to this License may be brought only in the
courts of a jurisdiction where the defendant maintains its principal
place of business and such litigation shall be governed by laws of that
jurisdiction, without reference to its conflict-of-law provisions.
Nothing in this Section shall prevent a party's ability to bring
cross-claims or counter-claims.
.
9. Miscellaneous
----------------
.
This License represents the complete agreement concerning the subject
matter hereof. If any provision of this License is held to be
unenforceable, such provision shall be reformed only to the extent
necessary to make it enforceable. Any law or regulation which provides
that the language of a contract shall be construed against the drafter
shall not be used to construe this License against a Contributor.
.
10. Versions of the License
---------------------------
.
10.1. New Versions
.
Mozilla Foundation is the license steward. Except as provided in Section
10.3, no one other than the license steward has the right to modify or
publish new versions of this License. Each version will be given a
distinguishing version number.
.
10.2. Effect of New Versions
.
You may distribute the Covered Software under the terms of the version
of the License under which You originally received the Covered Software,
or under the terms of any subsequent version published by the license
steward.
.
10.3. Modified Versions
.
If you create software not governed by this License, and you want to
create a new license for such software, you may create and use a
modified version of this License if you rename the license and remove
any references to the name of the license steward (except to note that
such modified license differs from this License).
.
10.4. Distributing Source Code Form that is Incompatible With Secondary
Licenses
.
If You choose to distribute Source Code Form that is Incompatible With
Secondary Licenses under the terms of this version of the License, the
notice described in Exhibit B of this License must be attached.
.
Exhibit A - Source Code Form License Notice
-------------------------------------------
.
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at https://mozilla.org/MPL/2.0/.
.
If it is not possible or desirable to put the notice in a particular
file, then You may include the notice in a location (such as a LICENSE
file in a relevant directory) where a recipient would be likely to look
for such a notice.
.
You may add additional accurate notices of copyright ownership.
.
Exhibit B - "Incompatible With Secondary Licenses" Notice
---------------------------------------------------------
.
This Source Code Form is "Incompatible With Secondary Licenses", as
defined by the Mozilla Public License, v. 2.0.

13
scripts/resources/deb/install Executable file
View File

@@ -0,0 +1,13 @@
#!/usr/bin/dh-exec
Suwayomi-Server.jar usr/share/java/suwayomi-server/bin/
Suwayomi-Launcher.jar usr/share/java/suwayomi-server/
suwayomi-server.png usr/share/pixmaps/
suwayomi-server.desktop usr/share/applications/
suwayomi-launcher.desktop usr/share/applications/
suwayomi-server.service usr/lib/systemd/system/
suwayomi-server.sysusers => usr/lib/sysusers.d/suwayomi-server.conf
suwayomi-server.tmpfiles => usr/lib/tmpfiles.d/suwayomi-server.conf
suwayomi-server.conf => etc/suwayomi/server.conf
suwayomi-server.sh => usr/bin/suwayomi-server
suwayomi-launcher.sh => usr/bin/suwayomi-launcher

11
scripts/resources/deb/rules Executable file
View File

@@ -0,0 +1,11 @@
#!/usr/bin/make -f
# See debhelper(7) (uncomment to enable)
# output every command that modifies files on the build system.
#export DH_VERBOSE = 1
%:
dh $@
override_dh_strip_nondeterminism:
true

View File

@@ -0,0 +1 @@
3.0 (quilt)

View File

@@ -0,0 +1 @@
suwayomi-server.png

View File

@@ -0,0 +1,64 @@
<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" UpgradeCode="*"
Version="$(var.ProductVersion)" Language="1033" Name="Suwayomi Server" Manufacturer="Suwayomi">
<Package InstallerVersion="300" Compressed="yes" />
<Media Id="1" Cabinet="Suwayomi_Server.cab" EmbedCab="yes" />
<Condition Message="This version of Windows does not support deploying 64-bit packages.">
VersionNT64
</Condition>
<!-- Directory -->
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFiles64Folder">
<Directory Id="INSTALLDIR" Name="Suwayomi-Server" >
<Directory Id="jre"/>
<Directory Id="electron"/>
<Directory Id="bin"/>
</Directory>
</Directory>
<Directory Id="ProgramMenuFolder">
<Directory Id="ProgramMenuDir" Name="Suwayomi-Server">
<Component Id="ProgramMenuDir" Guid="*">
<RemoveFolder Id="ProgramMenuDir" On="uninstall"/>
<RegistryValue Root="HKCU" Key="Software\[Manufacturer]\[ProductName]" Type="string" Value="" KeyPath="yes"/>
</Component>
</Directory>
</Directory>
<Directory Id="DesktopFolder" />
</Directory>
<!-- Component -->
<DirectoryRef Id="INSTALLDIR">
<Component Id="SuwayomiJAR" Guid="*" Win64="yes">
<File Id="Suwayomi-Launcher.jar" Source="$(var.SourceDir)/Suwayomi-Launcher.jar" KeyPath="yes" />
</Component>
<Component Id="SuwayomiLauncherBAT" Guid="*" Win64="yes">
<File Id="SuwayomiLauncher.bat" Source="$(var.SourceDir)/Suwayomi Launcher.bat" KeyPath="yes" >
<Shortcut Id="SuwayomiLauncher.lnk" Name="Suwayomi Launcher" Directory="INSTALLDIR"
WorkingDirectory="INSTALLDIR" Icon="Suwayomi.ico" IconIndex="0" Advertise="yes" />
<Shortcut Id="DesktopSuwayomiLauncher.lnk" Name="Suwayomi Launcher" Directory="DesktopFolder"
WorkingDirectory="INSTALLDIR" Icon="Suwayomi.ico" IconIndex="0" Advertise="yes" />
<Shortcut Id="ProgramMenuSuwayomiLauncher.lnk" Name="Suwayomi Launcher" Directory="ProgramMenuDir"
WorkingDirectory="INSTALLDIR" Icon="Suwayomi.ico" IconIndex="0" Advertise="yes"
Description="A free and open source manga reader that runs extensions built for Tachiyomi." />
</File>
</Component>
</DirectoryRef>
<!-- Feature -->
<Feature Id="Suwayomi_Server" Title="Suwayomi-Server" Level="1">
<ComponentGroupRef Id="jre" />
<ComponentGroupRef Id="bin" />
<ComponentRef Id="SuwayomiJAR" />
<ComponentRef Id="SuwayomiLauncherBAT" />
<ComponentRef Id="ProgramMenuDir" />
<ComponentGroupRef Id="electron" />
</Feature>
<Icon Id="Suwayomi.ico" SourceFile="$(var.Icon)" />
<Property Id="ARPPRODUCTICON" Value="Suwayomi.ico" /> <!-- Icon in Add/Remove Programs -->
</Product>
</Wix>

View File

@@ -0,0 +1,60 @@
<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" UpgradeCode="*"
Version="$(var.ProductVersion)" Language="1033" Name="Suwayomi Server" Manufacturer="Suwayomi">
<Package InstallerVersion="300" Compressed="yes" />
<Media Id="1" Cabinet="Suwayomi_Server.cab" EmbedCab="yes" />
<!-- Directory -->
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLDIR" Name="Suwayomi-Server" >
<Directory Id="jre"/>
<Directory Id="electron"/>
<Directory Id="bin"/>
</Directory>
</Directory>
<Directory Id="ProgramMenuFolder">
<Directory Id="ProgramMenuDir" Name="Suwayomi-Server">
<Component Id="ProgramMenuDir" Guid="*">
<RemoveFolder Id="ProgramMenuDir" On="uninstall"/>
<RegistryValue Root="HKCU" Key="Software\[Manufacturer]\[ProductName]" Type="string" Value="" KeyPath="yes"/>
</Component>
</Directory>
</Directory>
<Directory Id="DesktopFolder" />
</Directory>
<!-- Component -->
<DirectoryRef Id="INSTALLDIR">
<Component Id="SuwayomiJAR" Guid="*">
<File Id="Suwayomi-Launcher.jar" Source="$(var.SourceDir)/Suwayomi-Launcher.jar" KeyPath="yes" />
</Component>
<Component Id="SuwayomiLauncherBAT" Guid="*" Win64="yes">
<File Id="SuwayomiLauncher.bat" Source="$(var.SourceDir)/Suwayomi Launcher.bat" KeyPath="yes" >
<Shortcut Id="SuwayomiLauncher.lnk" Name="Suwayomi Launcher" Directory="INSTALLDIR"
WorkingDirectory="INSTALLDIR" Icon="Suwayomi.ico" IconIndex="0" Advertise="yes" />
<Shortcut Id="DesktopSuwayomiLauncher.lnk" Name="Suwayomi Launcher" Directory="DesktopFolder"
WorkingDirectory="INSTALLDIR" Icon="Suwayomi.ico" IconIndex="0" Advertise="yes" />
<Shortcut Id="ProgramMenuSuwayomiLauncher.lnk" Name="Suwayomi Launcher" Directory="ProgramMenuDir"
WorkingDirectory="INSTALLDIR" Icon="Suwayomi.ico" IconIndex="0" Advertise="yes"
Description="A free and open source manga reader that runs extensions built for Tachiyomi." />
</File>
</Component>
</DirectoryRef>
<!-- Feature -->
<Feature Id="Suwayomi_Server" Title="Suwayomi-Server" Level="1">
<ComponentGroupRef Id="jre" />
<ComponentGroupRef Id="bin" />
<ComponentRef Id="SuwayomiJAR" />
<ComponentRef Id="SuwayomiLauncherBAT" />
<ComponentRef Id="ProgramMenuDir" />
<ComponentGroupRef Id="electron" />
</Feature>
<Icon Id="Suwayomi.ico" SourceFile="$(var.Icon)" />
<Property Id="ARPPRODUCTICON" Value="Suwayomi.ico" /> <!-- Icon in Add/Remove Programs -->
</Product>
</Wix>

View File

@@ -0,0 +1,8 @@
[Desktop Entry]
Type=Application
Name=Suwayomi-Launcher
Comment=Manga Reader
Exec=/usr/bin/java -jar /usr/share/java/suwayomi-server/Suwayomi-Launcher.jar "\\$@"
Icon=suwayomi-server
Terminal=false
Categories=Network;

View File

@@ -0,0 +1,3 @@
#!/bin/sh
exec /usr/bin/java -jar /usr/share/java/suwayomi-server/Suwayomi-Launcher.jar

View File

@@ -0,0 +1,8 @@
[Desktop Entry]
Type=Application
Name=Suwayomi-Server
Comment=Manga Reader
Exec=/usr/bin/java -jar /usr/share/java/suwayomi-server/bin/Suwayomi-Server.jar "\\$@"
Icon=suwayomi-server
Terminal=false
Categories=Network;

View File

@@ -0,0 +1,3 @@
#!/bin/sh
exec /usr/bin/java -jar /usr/share/java/suwayomi-server/bin/Suwayomi-Server.jar

View File

@@ -0,0 +1,5 @@
TACHIDESK_ROOT_DIR="/var/lib/suwayomi"
# Extra arguments passed to the java command
# The default value disables the system tray icon, and launching a browser on service start.
JAVA_ARGS=-Dsuwayomi.tachidesk.config.server.initialOpenInBrowserEnabled=false -Dsuwayomi.tachidesk.config.server.systemTrayEnabled=false

View File

@@ -0,0 +1,31 @@
[Unit]
Description=A free and open source manga reader server that runs extensions built for Tachiyomi.
Wants=network-online.target
After=network-online.target
[Service]
Type=simple
User=suwayomi-server
Group=suwayomi-server
SyslogIdentifier=suwayomi-server
EnvironmentFile=/etc/suwayomi/server.conf
ExecStart=/usr/bin/java $JAVA_ARGS -Dsuwayomi.tachidesk.config.server.rootDir="${TACHIDESK_ROOT_DIR}" -jar /usr/share/java/suwayomi-server/bin/Suwayomi-Server.jar
Restart=on-failure
ProtectSystem=full
ProtectHome=true
PrivateTmp=yes
PrivateDevices=yes
ProtectClock=yes
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectKernelLogs=yes
ProtectControlGroups=yes
RestrictSUIDSGID=yes
RestrictRealtime=yes
RestrictNamespaces=yes
NoNewPrivileges=yes
[Install]
WantedBy=multi-user.target

View File

@@ -0,0 +1,2 @@
#Type Name ID GECOS Home directory Shell
u suwayomi-server - "Suwayomi Manga Server" /var/lib/suwayomi

View File

@@ -0,0 +1,2 @@
#Type Path Mode User Group Age Argument
d /var/lib/suwayomi 0755 suwayomi-server suwayomi-server

View File

@@ -0,0 +1,3 @@
#!/bin/sh
exec ./jre/bin/java -jar ./Suwayomi-Launcher.jar

View File

@@ -0,0 +1,3 @@
#!/bin/sh
exec ./jre/bin/java -jar ./bin/Suwayomi-Server.jar

View File

@@ -1,82 +0,0 @@
#!/bin/bash
# Copyright (C) Contributors to the Suwayomi project
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
electron_version="v12.0.9"
if [ $1 = "win32" ]; then
jre="OpenJDK8U-jre_x86-32_windows_hotspot_8u292b10.zip"
arch="win32"
electron="electron-$electron_version-win32-ia32.zip"
else
jre="OpenJDK8U-jre_x64_windows_hotspot_8u292b10.zip"
arch="win64"
electron="electron-$electron_version-win32-x64.zip"
fi
jre_dir="jdk8u292-b10-jre"
echo "creating windows bundle"
jar=$(ls ../server/build/*.jar | tail -n1)
jar_name=$(echo $jar | cut -d'/' -f4)
release_name=$(echo $jar_name | sed 's/.jar//')-$arch
# make release dir
mkdir $release_name
echo "Dealing with jre..."
if [ ! -f $jre ]; then
curl -L "https://github.com/AdoptOpenJDK/openjdk8-binaries/releases/download/jdk8u292-b10/$jre" -o $jre
fi
unzip $jre
mv $jre_dir $release_name/jre
echo "Dealing with electron"
if [ ! -f $electron ]; then
curl -L "https://github.com/electron/electron/releases/download/$electron_version/$electron" -o $electron
fi
unzip $electron -d $release_name/electron
# change electron's icon
rcedit="rcedit-x86.exe"
if [ ! -f $rcedit ]; then
curl -L "https://github.com/electron/rcedit/releases/download/v1.1.1/$rcedit" -o $rcedit
fi
# check if running under github actions
if [ $CI = true ]; then
# change electron executable's icon
sudo dpkg --add-architecture i386
wget -qO - https://dl.winehq.org/wine-builds/winehq.key | sudo apt-key add -
sudo add-apt-repository ppa:cybermax-dexter/sdl2-backport
sudo apt-add-repository "deb https://dl.winehq.org/wine-builds/ubuntu $(lsb_release -cs) main"
sudo apt install --install-recommends winehq-stable
fi
# this script assumes that wine is installed here on out
WINEARCH=win32 wine $rcedit $release_name/electron/electron.exe --set-icon ../server/src/main/resources/icon/faviconlogo.ico
# copy artifacts
cp $jar $release_name/Tachidesk.jar
cp "resources/Tachidesk Browser Launcher.bat" $release_name
cp "resources/Tachidesk Debug Launcher.bat" $release_name
cp "resources/Tachidesk Electron Launcher.bat" $release_name
zip_name=$release_name.zip
zip -9 -r $zip_name $release_name
rm -rf $release_name
# clean up from possible previous runs
if [ -f ../server/build/$zip_name ]; then
rm ../server/build/$zip_name
fi
mv $zip_name ../server/build/

View File

@@ -1,94 +1,89 @@
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.jmailen.gradle.kotlinter.tasks.FormatTask
import org.jmailen.gradle.kotlinter.tasks.LintTask
import de.undercouch.gradle.tasks.download.Download
import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile
import java.time.Instant
plugins {
id(libs.plugins.kotlin.jvm.get().pluginId)
id(libs.plugins.kotlin.serialization.get().pluginId)
id(libs.plugins.ktlint.get().pluginId)
application
kotlin("plugin.serialization")
id("com.github.johnrengelman.shadow") version "7.0.0"
id("org.jmailen.kotlinter") version "3.4.3"
id("com.github.gmazzo.buildconfig") version "3.0.2"
}
repositories {
maven {
url = uri("https://repo1.maven.org/maven2/")
}
maven {
url = uri("https://jitpack.io")
}
alias(libs.plugins.shadowjar)
id(libs.plugins.buildconfig.get().pluginId)
}
dependencies {
// okhttp
val okhttpVersion = "4.9.1" // version is locked by Tachiyomi extensions
implementation("com.squareup.okhttp3:okhttp:$okhttpVersion")
implementation("com.squareup.okhttp3:logging-interceptor:$okhttpVersion")
implementation("com.squareup.okhttp3:okhttp-dnsoverhttps:$okhttpVersion")
implementation("com.squareup.okio:okio:2.10.0")
// Shared
implementation(libs.bundles.shared)
testImplementation(libs.bundles.sharedTest)
// OkHttp
implementation(libs.bundles.okhttp)
implementation(libs.okio)
// Javalin api
implementation("io.javalin:javalin:3.13.6")
// jackson version is tied to javalin, ref: `io.javalin.core.util.OptionalDependency`
implementation("com.fasterxml.jackson.core:jackson-databind:2.10.3")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.10.3")
implementation(libs.bundles.javalin)
implementation(libs.bundles.jackson)
// GraphQL
implementation(libs.graphql.kotlin.server)
implementation(libs.graphql.kotlin.scheme)
implementation(libs.graphql.scalars)
// Exposed ORM
val exposedVersion = "0.31.1"
implementation("org.jetbrains.exposed:exposed-core:$exposedVersion")
implementation("org.jetbrains.exposed:exposed-dao:$exposedVersion")
implementation("org.jetbrains.exposed:exposed-jdbc:$exposedVersion")
implementation("org.jetbrains.exposed:exposed-java-time:$exposedVersion")
// current database driver
implementation("com.h2database:h2:1.4.200")
implementation(libs.bundles.exposed)
implementation(libs.h2)
// Exposed Migrations
val exposedMigrationsVersion = "3.1.0"
implementation("com.github.Suwayomi:exposed-migrations:$exposedMigrationsVersion")
implementation(libs.exposed.migrations)
// tray icon
implementation("com.dorkbox:SystemTray:4.1")
implementation("com.dorkbox:Utilities:1.9")
implementation(libs.bundles.systemtray)
// dependencies of Tachiyomi extensions, some are duplicate, keeping it here for reference
implementation("com.github.inorichi.injekt:injekt-core:65b0440")
implementation("com.squareup.okhttp3:okhttp:4.9.1")
implementation("io.reactivex:rxjava:1.3.8")
implementation("org.jsoup:jsoup:1.13.1")
implementation("com.google.code.gson:gson:2.8.6")
implementation("com.github.salomonbrys.kotson:kotson:2.5.0")
implementation(libs.injekt)
implementation(libs.okhttp.core)
implementation(libs.rxjava)
implementation(libs.jsoup)
// ComicInfo
implementation(libs.serialization.xml.core)
implementation(libs.serialization.xml)
// asm for fixing SimpleDateFormat (must match Dex2Jar version)
implementation("org.ow2.asm:asm-debug-all:5.0.3")
// Sort
implementation(libs.sort)
// extracting zip files
implementation("net.lingala.zip4j:zip4j:2.9.0")
// asm for ByteCodeEditor(fixing SimpleDateFormat) (must match Dex2Jar version)
implementation(libs.asm)
// Source models and interfaces from Tachiyomi 1.x
// using source class from tachiyomi commit 9493577de27c40ce8b2b6122cc447d025e34c477 to not depend on tachiyomi.sourceapi
// implementation("tachiyomi.sourceapi:source-api:1.1")
// Disk & File
implementation(libs.zip4j)
implementation(libs.commonscompress)
implementation(libs.junrar)
// AES/CBC/PKCS7Padding Cypher provider for zh.copymanga
implementation(libs.bouncycastle)
// AndroidCompat
implementation(project(":AndroidCompat"))
implementation(project(":AndroidCompat:Config"))
implementation(projects.androidCompat)
implementation(projects.androidCompat.config)
// uncomment to test extensions directly
// implementation(fileTree("lib/"))
implementation(kotlin("script-runtime"))
testImplementation(libs.mockk)
implementation(libs.cron4j)
implementation(libs.cronUtils)
}
application {
applicationDefaultJvmArgs =
listOf(
"-Djunrar.extractor.thread-keep-alive-seconds=30",
)
mainClass.set(MainClass)
// uncomment for testing electron
// applicationDefaultJvmArgs = listOf(
// "-Dsuwayomi.tachidesk.config.server.webUIInterface=electron",
// "-Dsuwayomi.tachidesk.config.server.electronPath=/usr/bin/electron"
// )
}
sourceSets {
@@ -101,7 +96,7 @@ sourceSets {
buildConfig {
className("BuildConfig")
packageName("suwayomi.tachidesk.server")
packageName("suwayomi.tachidesk.server.generated")
useKotlinOutput()
@@ -109,57 +104,49 @@ buildConfig {
buildConfigField("String", "NAME", quoteWrap(rootProject.name))
buildConfigField("String", "VERSION", quoteWrap(tachideskVersion))
buildConfigField("String", "REVISION", quoteWrap(tachideskRevision))
buildConfigField("String", "REVISION", quoteWrap(getTachideskRevision()))
buildConfigField("String", "BUILD_TYPE", quoteWrap(if (System.getenv("ProductBuildType") == "Stable") "Stable" else "Preview"))
buildConfigField("long", "BUILD_TIME", Instant.now().epochSecond.toString())
buildConfigField("String", "WEBUI_REPO", quoteWrap("https://github.com/Suwayomi/Tachidesk-WebUI-preview"))
buildConfigField("String", "WEBUI_TAG", quoteWrap(webUIRevisionTag))
buildConfigField("String", "GITHUB", quoteWrap("https://github.com/Suwayomi/Tachidesk"))
buildConfigField("String", "GITHUB", quoteWrap("https://github.com/Suwayomi/Suwayomi-Server"))
buildConfigField("String", "DISCORD", quoteWrap("https://discord.gg/DDZdqZWaHA"))
}
tasks {
shadowJar {
isZip64 = true
manifest {
attributes(
mapOf(
"Main-Class" to MainClass,
"Implementation-Title" to rootProject.name,
"Implementation-Vendor" to "The Suwayomi Project",
"Specification-Version" to tachideskVersion,
"Implementation-Version" to tachideskRevision
)
"Main-Class" to MainClass,
"Implementation-Title" to rootProject.name,
"Implementation-Vendor" to "The Suwayomi Project",
"Specification-Version" to tachideskVersion,
"Implementation-Version" to getTachideskRevision(),
)
}
archiveBaseName.set(rootProject.name)
archiveVersion.set(tachideskVersion)
archiveClassifier.set(tachideskRevision)
}
withType<KotlinCompile> {
kotlinOptions {
freeCompilerArgs = listOf(
"-Xopt-in=kotlin.RequiresOptIn",
"-Xopt-in=kotlinx.coroutines.ExperimentalCoroutinesApi",
"-Xopt-in=kotlinx.coroutines.InternalCoroutinesApi",
"-Xopt-in=kotlinx.serialization.ExperimentalSerializationApi",
)
}
}
test {
useJUnit()
}
withType<ShadowJar> {
archiveClassifier.set(getTachideskRevision())
destinationDirectory.set(File("$rootDir/server/build"))
}
named("run") {
dependsOn("formatKotlin", "lintKotlin", "downloadWebUI")
test {
useJUnitPlatform()
testLogging {
showStandardStreams = true
events("passed", "skipped", "failed")
}
}
withType<KotlinJvmCompile> {
kotlinOptions {
freeCompilerArgs +=
listOf(
"-opt-in=kotlinx.serialization.ExperimentalSerializationApi",
)
}
}
named<Copy>("processResources") {
@@ -167,23 +154,24 @@ tasks {
mustRunAfter("downloadWebUI")
}
register<de.undercouch.gradle.tasks.download.Download>("downloadWebUI") {
src("https://github.com/Suwayomi/Tachidesk-WebUI-preview/releases/download/$webUIRevisionTag/Tachidesk-WebUI-$webUIRevisionTag.zip")
register<Download>("downloadWebUI") {
src("https://github.com/Suwayomi/Suwayomi-WebUI-preview/releases/download/$webUIRevisionTag/Suwayomi-WebUI-$webUIRevisionTag.zip")
dest("src/main/resources/WebUI.zip")
fun shouldOverwrite(): Boolean {
val zipPath = project.projectDir.absolutePath + "/src/main/resources/WebUI.zip"
val zipFile = net.lingala.zip4j.ZipFile(zipPath)
val zipFile = net.lingala.zip4j.ZipFile(zipPath)
var shouldOverwrite = true
if (zipFile.isValidZipFile) {
val zipRevision = zipFile.getInputStream(zipFile.getFileHeader("revision")).bufferedReader().use {
it.readText().trim()
}
val zipRevision =
zipFile.getInputStream(zipFile.getFileHeader("revision")).bufferedReader().use {
it.readText().trim()
}
if (zipRevision == webUIRevisionTag)
if (zipRevision == webUIRevisionTag) {
shouldOverwrite = false
}
}
return shouldOverwrite
@@ -192,11 +180,16 @@ tasks {
overwrite(shouldOverwrite())
}
withType<LintTask> {
source(files("src/kotlin"))
}
withType<FormatTask> {
source(files("src/kotlin"))
register("runElectron") {
group = "application"
finalizedBy(run)
doFirst {
application.applicationDefaultJvmArgs =
listOf(
"-Dsuwayomi.tachidesk.config.server.webUIInterface=electron",
// Change this to the installed electron application
"-Dsuwayomi.tachidesk.config.server.electronPath=/usr/bin/electron",
)
}
}
}

View File

@@ -9,15 +9,11 @@ package eu.kanade.tachiyomi
import android.app.Application
import android.content.Context
// import android.content.res.Configuration
// import android.support.multidex.MultiDex
// import timber.log.Timber
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.InjektScope
import uy.kohesive.injekt.registry.default.DefaultRegistrar
open class App : Application() {
override fun onCreate() {
super.onCreate()
Injekt = InjektScope(DefaultRegistrar())

View File

@@ -0,0 +1,34 @@
package eu.kanade.tachiyomi
import suwayomi.tachidesk.manga.impl.util.storage.ImageUtil
import suwayomi.tachidesk.server.generated.BuildConfig
/**
* Used by extensions.
*
* @since extension-lib 1.3
*/
object AppInfo {
/**
*
* should be something like 74
*
* @since extension-lib 1.3
*/
fun getVersionCode() = BuildConfig.REVISION.substring(1).toInt()
/**
* should be something like "0.13.1"
*
* @since extension-lib 1.3
*/
fun getVersionName() = BuildConfig.VERSION.substring(1)
/**
* A list of supported image MIME types by the reader.
* e.g. ["image/jpeg", "image/png", ...]
*
* @since extension-lib 1.5
*/
fun getSupportedImageMimeTypes(): List<String> = ImageUtil.ImageType.entries.map { it.mime }
}

View File

@@ -7,8 +7,6 @@ package eu.kanade.tachiyomi
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
import android.app.Application
import com.google.gson.Gson
// import eu.kanade.tachiyomi.data.cache.ChapterCache
// import eu.kanade.tachiyomi.data.cache.CoverCache
// import eu.kanade.tachiyomi.data.database.DatabaseHelper
@@ -17,6 +15,8 @@ import com.google.gson.Gson
// import eu.kanade.tachiyomi.data.sync.LibrarySyncManager
// import eu.kanade.tachiyomi.data.track.TrackManager
// import eu.kanade.tachiyomi.extension.ExtensionManager
import android.app.Application
import eu.kanade.tachiyomi.network.JavaScriptEngine
import eu.kanade.tachiyomi.network.NetworkHelper
import kotlinx.serialization.json.Json
import rx.Observable
@@ -28,9 +28,7 @@ import uy.kohesive.injekt.api.addSingletonFactory
import uy.kohesive.injekt.api.get
class AppModule(val app: Application) : InjektModule {
override fun InjektRegistrar.registerInjectables() {
addSingleton(app)
// addSingletonFactory { PreferencesHelper(app) }
@@ -43,6 +41,8 @@ class AppModule(val app: Application) : InjektModule {
addSingletonFactory { NetworkHelper(app) }
addSingletonFactory { JavaScriptEngine(app) }
// addSingletonFactory { SourceManager(app).also { get<ExtensionManager>().init(it) } }
//
// addSingletonFactory { ExtensionManager(app) }
@@ -53,8 +53,6 @@ class AppModule(val app: Application) : InjektModule {
//
// addSingletonFactory { LibrarySyncManager(app) }
addSingletonFactory { Gson() }
addSingletonFactory { Json { ignoreUnknownKeys = true } }
// Asynchronously init expensive components for a faster cold start

View File

@@ -1,46 +0,0 @@
package eu.kanade.tachiyomi.animesource
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
import eu.kanade.tachiyomi.animesource.model.AnimesPage
import rx.Observable
interface AnimeCatalogueSource : AnimeSource {
/**
* An ISO 639-1 compliant language code (two letters in lower case).
*/
override val lang: String
/**
* Whether the source has support for latest updates.
*/
val supportsLatest: Boolean
/**
* Returns an observable containing a page with a list of anime.
*
* @param page the page number to retrieve.
*/
fun fetchPopularAnime(page: Int): Observable<AnimesPage>
/**
* Returns an observable containing a page with a list of anime.
*
* @param page the page number to retrieve.
* @param query the search query.
* @param filters the list of filters to apply.
*/
fun fetchSearchAnime(page: Int, query: String, filters: AnimeFilterList): Observable<AnimesPage>
/**
* Returns an observable containing a page with a list of latest anime updates.
*
* @param page the page number to retrieve.
*/
fun fetchLatestUpdates(page: Int): Observable<AnimesPage>
/**
* Returns the list of filters for the source.
*/
fun getFilterList(): AnimeFilterList
}

View File

@@ -1,81 +0,0 @@
package eu.kanade.tachiyomi.animesource
import eu.kanade.tachiyomi.animesource.model.SAnime
import eu.kanade.tachiyomi.animesource.model.SEpisode
import eu.kanade.tachiyomi.animesource.model.Video
import rx.Observable
/**
* A basic interface for creating a source. It could be an online source, a local source, etc...
*/
interface AnimeSource {
/**
* Id for the source. Must be unique.
*/
val id: Long
/**
* Name of the source.
*/
val name: String
val lang: String
get() = ""
/**
* Returns an observable with the updated details for a anime.
*
* @param anime the anime to update.
*/
// @Deprecated("Use getAnimeDetails instead")
fun fetchAnimeDetails(anime: SAnime): Observable<SAnime>
/**
* Returns an observable with all the available episodes for an anime.
*
* @param anime the anime to update.
*/
// @Deprecated("Use getEpisodeList instead")
fun fetchEpisodeList(anime: SAnime): Observable<List<SEpisode>>
/**
* Returns an observable with a list of video for the episode of an anime.
*
* @param episode the episode to get the link for.
*/
// @Deprecated("Use getEpisodeList instead")
fun fetchVideoList(episode: SEpisode): Observable<List<Video>>
// /**
// * [1.x API] Get the updated details for a anime.
// */
// @Suppress("DEPRECATION")
// override suspend fun getAnimeDetails(anime: AnimeInfo): AnimeInfo {
// val sAnime = anime.toSAnime()
// val networkAnime = fetchAnimeDetails(sAnime).awaitSingle()
// sAnime.copyFrom(networkAnime)
// return sAnime.toAnimeInfo()
// }
// /**
// * [1.x API] Get all the available episodes for a anime.
// */
// @Suppress("DEPRECATION")
// override suspend fun getEpisodeList(anime: AnimeInfo): List<EpisodeInfo> {
// return fetchEpisodeList(anime.toSAnime()).awaitSingle()
// .map { it.toEpisodeInfo() }
// }
// /**
// * [1.x API] Get a link for the episode of an anime.
// */
// @Suppress("DEPRECATION")
// override suspend fun getEpisodeLink(episode: EpisodeInfo): String {
// return fetchEpisodeLink(episode.toSEpisode()).awaitSingle()
// }
}
// fun AnimeSource.icon(): Drawable? = Injekt.get<AnimeExtensionManager>().getAppIconForSource(this)
fun AnimeSource.getPreferenceKey(): String = "source_$id"

View File

@@ -1,12 +0,0 @@
package eu.kanade.tachiyomi.animesource
/**
* A factory for creating sources at runtime.
*/
interface AnimeSourceFactory {
/**
* Create a new copy of the sources
* @return The created sources
*/
fun createSources(): List<AnimeSource>
}

View File

@@ -1,8 +0,0 @@
package eu.kanade.tachiyomi.animesource
import androidx.preference.PreferenceScreen
interface ConfigurableAnimeSource : AnimeSource {
fun setupPreferenceScreen(screen: PreferenceScreen)
}

Some files were not shown because too many files have changed in this diff Show More