Compare commits

...

1336 Commits

Author SHA1 Message Date
Syer10
54df9d634a Fix release 2024-02-23 13:35:08 -05:00
Syer10
4eb9a696ff Fix release 2024-02-23 13:29:57 -05:00
Syer10
7b4fb4682b Add ChangeLog 2024-02-23 12:56:46 -05:00
Syer10
da4275530d v1.0.0 2024-02-23 12:13:42 -05:00
Mitchell Syer
1c417e909a Support Comic Info creation on download (#887)
* Support Comic Info creation on download

* Update Json and add Protobuf
2024-02-22 14:29:30 -05:00
Aria Moradi
fc53d69f82 Add auth and version support to socks proxy (#883)
* Add auth support to socsk proxy

* better logging

* fix lint issue

* implement fixes and version

* add to test reference too
2024-02-19 11:06:39 -05:00
Mitchell Syer
dda86cdb93 Seperate out migrations to allow run-once migrations (#882)
* Seperate out migrations to allow run-once migrations

* Previous

* Move migrations to a new file
2024-02-19 11:06:31 -05:00
Mitchell Syer
525a974e3a Start Server after routes are defined (#881)
* Start Server after routes are defined

* Separate events
2024-02-19 11:06:20 -05:00
Mitchell Syer
b18c155e22 Fix Downloader Memory Leak (#880) 2024-02-19 11:06:13 -05:00
Mitchell Syer
07e011092a Support Token Expiry properly (#878)
* Support token expiry properly

* Small fix

* Lint

* Use newer fixes for expiry

* Lint
2024-02-19 11:06:00 -05:00
Aria Moradi
6803ac0611 move qtui to inactive list as it hasen't had commits in 2 years 2024-02-19 15:21:51 +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
Aria Moradi
da44d3b2b4 bump to v0.4.7 2021-08-21 06:30:45 +04:30
Aria Moradi
99ec2aca6a update WebUI 2021-08-21 06:27:14 +04:30
Aria Moradi
6c278604ec got rid of legacy backups 2021-08-21 06:23:58 +04:30
Aria Moradi
1e094a467a not TODO 2021-08-21 06:13:55 +04:30
Aria Moradi
978ccfeeba the true commit 2021-08-21 06:12:22 +04:30
Aria Moradi
e93d66d8a1 add backup validation endpoints 2021-08-21 06:08:17 +04:30
Aria Moradi
c29a749833 proto export support 2021-08-21 05:48:05 +04:30
Aria Moradi
b08d5d1261 all forms of Default are illegal 2021-08-21 05:10:09 +04:30
Aria Moradi
9b129789e9 all forms of Default are illegal 2021-08-21 05:05:01 +04:30
Aria Moradi
a76a6d2798 creating a categort named Default is illegal 2021-08-21 03:58:46 +04:30
Aria Moradi
086a760378 update WebUI 2021-08-21 03:55:22 +04:30
Aria Moradi
f78c8d4fd8 Default is now a category, no more library 2021-08-21 03:54:16 +04:30
Aria Moradi
7b91489997 better print 2021-08-21 01:20:18 +04:30
Aria Moradi
36a8980c95 TODO block no longer relevant 2021-08-21 01:11:47 +04:30
Aria Moradi
7c65640cb7 include extra chapter data in restore 2021-08-21 00:37:50 +04:30
Aria Moradi
d70e68495a restoring with clean db and not installed extensions work 2021-08-21 00:18:03 +04:30
Aria Moradi
2586202772 better comments 2021-08-19 21:11:53 +04:30
Aria Moradi
b5f771368a put back dex2jar where it should be 2021-08-19 03:15:35 +04:30
Aria Moradi
0c28320ce3 better debug launcher 2021-08-19 02:54:36 +04:30
Aria Moradi
c8b4fbc36b new observation 2021-08-19 02:06:48 +04:30
Aria Moradi
e9b07849fe move dex2jar to server, lint 2021-08-19 01:47:26 +04:30
Aria Moradi
409260af6f Merge pull request #176 from Suwayomi/protobuf
protobuf backup support
2021-08-19 00:47:32 +04:30
Aria Moradi
d3d53d1a4e initial support for portobuf backup 2021-08-19 00:46:45 +04:30
Aria Moradi
e2db191f70 consolidate the external backup api 2021-08-18 23:34:39 +04:30
Aria Moradi
d61816734d add all proto backup classes we need 2021-08-18 22:58:56 +04:30
Aria Moradi
f4dad8058f Merge branch 'master' into protobuf 2021-08-18 21:51:12 +04:30
Aria Moradi
70bdb375c3 Update README.md 2021-08-18 19:10:46 +04:30
Aria Moradi
e724ab0a29 Update README.md 2021-08-18 19:10:16 +04:30
Aria Moradi
7d0ee2ac11 Update README.md 2021-08-18 06:17:04 +04:30
Aria Moradi
59b7e852e2 Update README.md 2021-08-18 06:15:44 +04:30
Aria Moradi
b2eb1a391d Update README.md 2021-08-18 05:31:34 +04:30
Aria Moradi
9b3aee98d3 Update CONTRIBUTING.md 2021-08-18 05:30:19 +04:30
Aria Moradi
0476f4144c Update CONTRIBUTING.md 2021-08-18 05:29:24 +04:30
Aria Moradi
ed77f45fae Update CONTRIBUTING.md 2021-08-18 05:28:26 +04:30
Aria Moradi
0cd529e746 Update CONTRIBUTING.md 2021-08-18 05:26:55 +04:30
Aria Moradi
5969048318 Update README.md 2021-08-18 05:19:42 +04:30
Aria Moradi
d1a7f8baa0 Update README.md 2021-08-18 05:04:22 +04:30
Aria Moradi
18dc936002 Update README.md (#177)
* Update README.md

* Update README.md
2021-08-18 04:50:10 +04:30
Aria Moradi
b4b7b5d572 bump to v0.4.6 2021-08-18 04:29:14 +04:30
Aria Moradi
291c2e692d clean up build.gradle files, move constants to buildSrc 2021-08-18 04:24:58 +04:30
Aria Moradi
8a9a4f21b1 remove some stuff we don't use 2021-08-18 04:06:13 +04:30
Aria Moradi
cd31332b39 better download progress 2021-08-18 03:55:52 +04:30
Aria Moradi
cc8d2162a0 fix compile issue 2021-08-18 02:59:07 +04:30
Aria Moradi
e6313cdc67 yeet improvments from jui 2021-08-18 01:21:17 +04:30
Aria Moradi
5af64892e7 Merge branch 'master' into protobuf 2021-08-18 00:28:42 +04:30
Aria Moradi
a5578a7ac7 fix compile warnings 2021-08-17 23:54:02 +04:30
Aria Moradi
fcdda6406e update dependencies 2021-08-17 23:53:41 +04:30
Aria Moradi
9bdd9f8aa6 better endpoint urls based on suggestion from @mgn-norm 2021-08-17 21:45:19 +04:30
Aria Moradi
f3856f051b protobuf backup endpoints 2021-08-17 20:09:31 +04:30
Aria Moradi
d3a6662c60 make it compile 2021-08-15 03:16:13 +04:30
Aria Moradi
5474eddf84 fix some inconsitencies 2021-08-15 02:41:23 +04:30
Aria Moradi
b666cd47d4 fix shouldOverwrite 2021-08-15 00:25:08 +04:30
Aria Moradi
8a986383fe fixes #175, better webUI download task 2021-08-14 17:10:41 +04:30
Aria Moradi
9fa17f617e add anime seach functionality 2021-08-11 08:47:07 +04:30
Aria Moradi
e46e165704 bump to v0.4.5 2021-08-11 00:39:08 +04:30
Aria Moradi
a6af423fb4 Merge branch 'master' of github.com:Suwayomi/Tachidesk-Server 2021-08-10 09:42:41 +04:30
Aria Moradi
3397e694c0 sync anime lib implementation with 12 (#133)
* sync anime lib implementation with 11

* fix wrong api

* delete unused classes

* adapt to lib 12

* add LICENSE for eu.kanade.tachiyomi

* changes for lib 12

* update to lib 12

* update webUI
2021-08-10 09:42:14 +04:30
Aria Moradi
77ff82505e fix wrong api 2021-08-10 04:01:08 +04:30
Aria Moradi
c3f2838270 fix name tag generator 2021-08-10 03:40:49 +04:30
Aria Moradi
aed7f205b6 update webUI 2021-08-10 03:39:36 +04:30
Aria Moradi
95b3587f7a update webUI 2021-08-10 02:04:35 +04:30
Aria Moradi
a4baeb995a refactor endpoints to the new styles 2021-08-09 23:18:41 +04:30
Aria Moradi
032ab54206 fix tag generator 2021-08-09 23:18:06 +04:30
Aria Moradi
1f9c1eb1c0 only open browser when appropriate 2021-08-09 07:15:41 +04:30
Aria Moradi
a213e568ba update property strings 2021-08-09 06:59:16 +04:30
Aria Moradi
7aeaeb4b86 move copyright notice to it's place 2021-08-09 06:49:12 +04:30
Aria Moradi
81aef4b8fa remove un-used files 2021-08-09 06:48:02 +04:30
Aria Moradi
31f0b6a16c ability to override server.conf with java -D arguments 2021-08-09 06:45:49 +04:30
Aria Moradi
44e3a682fd update Project name 2021-08-09 01:27:09 +04:30
Aria Moradi
70402a6d3a update webUI to r20 2021-08-08 14:18:46 +04:30
Aria Moradi
5c4143224a Bump to v0.4.4 2021-08-08 07:11:03 +04:30
Aria Moradi
f943e924f7 Update build_push.yml 2021-08-08 07:00:12 +04:30
Aria Moradi
7d2f542f8a bundle WebUI for stable builds 2021-08-08 06:18:00 +04:30
Aria Moradi
fb1f88e971 lint 2021-08-08 05:36:54 +04:30
Aria Moradi
f566f13423 launch parameter for Syer 2021-08-08 05:32:14 +04:30
Aria Moradi
0f88baf1c1 download webUI on demand 2021-08-08 05:31:58 +04:30
Aria Moradi
a04cbcd814 add webUIEnabled config 2021-08-08 01:11:21 +04:30
Aria Moradi
a17d6a2ea4 clean up the after effects of bringing back webUI 2021-08-07 22:52:44 +04:30
Aria Moradi
08f49e0ac4 Revert "changes for the headless Tachidesk"
This reverts commit e575aaf4fb.
2021-08-07 22:37:27 +04:30
Aria Moradi
7787dd1ecc better comments 2021-08-07 22:18:05 +04:30
Aria Moradi
3d0765d4ab posibly fixes #119 2021-08-07 22:01:38 +04:30
Aria Moradi
b51651ace4 refactor to fancy migration classes 2021-08-07 21:58:36 +04:30
Aria Moradi
568fa56d59 add suppress unused class warning 2021-08-07 17:15:01 +04:30
Aria Moradi
50dee9251c rename preview repo 2021-08-06 07:22:11 +04:30
Aria Moradi
e575aaf4fb changes for the headless Tachidesk 2021-08-06 07:15:38 +04:30
Aria Moradi
bdd5caae1a kick webUI out of Tachidesk 2021-08-06 04:55:03 +04:30
Aria Moradi
3af7de3460 partial implementation for Extenstion Preferences 2021-08-06 04:53:53 +04:30
Aria Moradi
caa219f8d6 remove not used types 2021-08-06 03:44:54 +04:30
Aria Moradi
afabaccf1d implement data store for extension prefs 2021-08-06 03:37:09 +04:30
Aria Moradi
53cc73701c update exposed version 2021-08-05 23:53:45 +04:30
Aria Moradi
c69b954ffd move migration lib outside of Tachidesk 2021-08-05 22:53:31 +04:30
Aria Moradi
d05c447fe4 refactor and comment 2021-08-05 20:43:08 +04:30
Aria Moradi
5810a24cb0 about api url is changed 2021-08-05 17:12:53 +04:30
Syer10
e04c6a9f4d Update Android jar to API 30 (#172) 2021-08-05 15:13:57 +04:30
Aria Moradi
e3a9f7af42 it's named Stable 2021-08-05 06:42:28 +04:30
Aria Moradi
5eb58a73ee check app update api closes #72 2021-08-05 06:39:09 +04:30
Aria Moradi
68ad1f72ce new about url, fix typo 2021-08-05 05:49:18 +04:30
Aria Moradi
704a52d943 separate Global API 2021-08-05 05:40:48 +04:30
Aria Moradi
67ec9ccc4e mark methods as @JsonIgnore to avoid Jackson serializing them 2021-08-05 03:31:32 +04:30
Aria Moradi
c7112ec67f mark methods as @JsonIgnore to avoid Jackson serializing them 2021-08-05 03:28:21 +04:30
Aria Moradi
1e1e2034eb Merge branch 'master' of github.com:Suwayomi/Tachidesk 2021-08-04 15:36:44 +04:30
Aria Moradi
5f316c6f44 rename to value 2021-08-04 15:36:29 +04:30
KraXen72
0c39718f82 the plural of Manga *is* Mangas don't let anyone tell you otherwise (#168) 2021-08-04 02:03:50 +04:30
Aria Moradi
8a5ac4a0af add better comments 2021-08-01 18:12:49 +04:30
Syer10
492d5f5e84 Fix list preference crashing on set (#166) 2021-08-01 17:13:50 +04:30
Syer10
5a3621fe39 Override getDefaultValueType with values based on the preference (#167) 2021-08-01 17:13:29 +04:30
Syer10
fb862e23e5 Fix main thread scheduler, fixes Komga and LANraragi(not the preferences though) (#165) 2021-07-31 19:43:50 +04:30
Aria Moradi
3d69348301 add comment about which types should be supported 2021-07-31 08:35:56 +04:30
Aria Moradi
30787846a2 sync androidx.preference method signatures with extensions-lib 2021-07-31 08:28:45 +04:30
Aria Moradi
345ca27f85 support ListPreference 2021-07-31 07:59:05 +04:30
Aria Moradi
b7a6d6cae8 fix HentaiHand preferences 2021-07-31 07:41:19 +04:30
Aria Moradi
dadb686514 refine extension preferences API 2021-07-31 07:24:45 +04:30
Aria Moradi
75f635a28b add configure button to source card 2021-07-31 05:06:46 +04:30
Aria Moradi
f2bd5b8149 add text to EditTextPreference 2021-07-31 05:04:30 +04:30
Aria Moradi
6ed4c79ca4 merge missing commit from #163 2021-07-31 04:50:43 +04:30
Aria Moradi
333f954919 hide anime menu stuff 2021-07-31 04:14:48 +04:30
Aria Moradi
2494d0821d ConfigurableExtension(PreferenceScreen) support (#163)
* initial PreferenceScreen support, works with 'NeoXXX Scans' (pt-br)

* convert EditTextPreference to json successfully

* commit what I've got

* bring back the old SharedPreferences for CustomContext, implement Toast

* put back syer's implementation
2021-07-31 03:53:28 +04:30
Aria Moradi
e349d0cef3 add pereference change 2021-07-31 03:50:41 +04:30
Aria Moradi
eddad2ba89 Merge branch 'preference-screen' of https://github.com/Syer10/Tachidesk into preference-screen 2021-07-31 02:50:20 +04:30
Aria Moradi
bfaf88afd6 put back syer's implementation 2021-07-31 02:49:15 +04:30
Syer10
cd59aed8c7 Fix Invalid Type exception 2021-07-30 17:56:12 -04:00
Aria Moradi
f18ca5811f bring back the old SharedPreferences for CustomContext, implement Toast 2021-07-31 02:10:48 +04:30
Aria Moradi
1ed9bcf7c8 commit what I've got 2021-07-31 00:41:09 +04:30
Aria Moradi
29a79ab079 dont print manifestXml 2021-07-30 19:00:58 +04:30
Aria Moradi
7c03c73419 convert EditTextPreference to json successfully 2021-07-30 18:48:07 +04:30
Aria Moradi
74f3b9b609 merge master into preference-screen 2021-07-30 16:55:14 +04:30
Aria Moradi
a3953d530e make it compile 2021-07-30 16:52:06 +04:30
Aria Moradi
2280e8c725 initial PreferenceScreen support, works with 'NeoXXX Scans' (pt-br) 2021-07-30 15:05:21 +04:30
Syer10
b327df732c Comments, comments, and comments!! And future proofing (#162) 2021-07-30 05:56:13 +04:30
Aria Moradi
21d7cf5d6a prepare for PreferenceScreen support, remove some old depricated android libs 2021-07-30 00:46:45 +04:30
Aria Moradi
5b64bdc5b7 add copyright notices to Syer10's previous PR 2021-07-29 23:26:23 +04:30
Aria Moradi
a3a25b6263 move replace classes 2021-07-29 22:59:03 +04:30
Aria Moradi
c7611c8024 log data root dir 2021-07-29 22:36:39 +04:30
Aria Moradi
f08170504c Merge branch 'master' of github.com:Suwayomi/Tachidesk 2021-07-29 22:35:29 +04:30
Syer10
863dccb5ea Modify extension bytecode to fix SimpleDateFormat cannot parse errors (#149)
- Fixes sources like NHentai
- Fixes mass testing
- Cleans up a bit of the build.gradle.kts's
- Fix Tsuki by setting a http.agent system property
2021-07-29 22:21:25 +04:30
Syer10
fc8bb10ca3 Modify extension bytecode to fix SimpleDateFormat cannot parse errors 2021-06-26 12:51:54 -04:00
Syer10
d06c3586fd Fix sources that require the singleton Json object (#147) 2021-06-24 11:37:26 +04:30
Syer10
395989b528 Improve process time for getAndroid.ps1 (#146) 2021-06-23 00:15:39 +04:30
Aria Moradi
a325440f24 bump to v0.4.3 2021-06-17 00:28:19 +04:30
Aria Moradi
14072bb5a0 fix manga extensions not loading 2021-06-17 00:26:34 +04:30
Aria Moradi
7fc33ba8db fix cache 2021-06-06 03:19:03 +04:30
Aria Moradi
47e51b6615 fix naming 2021-06-06 03:13:09 +04:30
Aria Moradi
857562eaff add build flexiblity for Equinox 2021-06-06 02:48:26 +04:30
Aria Moradi
bace854b50 rm dummy 2021-06-06 02:05:47 +04:30
Aria Moradi
e4a404472d Merge branch 'master' of github.com:Suwayomi/Tachidesk 2021-06-06 02:05:26 +04:30
Aria Moradi
7bfa215b4c change old paths 2021-06-06 01:52:05 +04:30
Aria Moradi
ab7af4b80b fix typo 2021-06-06 01:35:39 +04:30
Aria Moradi
2c7ebd8ece prepare for integration with Equinox 2021-06-06 01:34:49 +04:30
Syer10
c96da79058 Fix MacOS crashing on launch (#132) 2021-06-05 22:36:36 +04:30
Aria Moradi
8f09ebacf5 dummy file to trigger gh actions 2021-06-04 23:10:40 +04:30
Aria Moradi
e21f3b9c75 closes #130 2021-06-04 21:51:48 +04:30
Aria Moradi
37eeef06e2 correct spelling 2021-06-04 16:34:19 +04:30
Aria Moradi
b7fe56687c Bump styfle/cancel-workflow-action from 0.5.0 to 0.9.0 2021-06-04 13:35:20 +04:30
Aria Moradi
60565729ca lint by linter 2021-06-04 13:35:07 +04:30
Aria Moradi
36f4e1c340 move all packages to 'suwayomi.tachidesk' 2021-06-04 13:08:20 +04:30
Aria Moradi
abc2a5214b Merge branch 'master' of github.com:Suwayomi/Tachidesk 2021-06-04 10:43:39 +04:30
Aria Moradi
a29010e0d7 fix chached image returning file type with extra . 2021-06-04 10:43:03 +04:30
arbuilder
db99ab66ae Update build_push.yml (#124)
* Update build_push.yml

docker workflow for preview build

* Update build_push.yml

remove cd master

* Update build_push.yml

Change access token
2021-06-01 13:27:57 +04:30
arbuilder
84cc73c149 Update publish.yml (#123)
* Update publish.yml

add docker build workflow

* Update publish.yml

Remove cd master

* Update publish.yml

Change access token
2021-06-01 13:25:38 +04:30
Aria Moradi
10a29cab33 Merge branch 'master' of github.com:Suwayomi/Tachidesk 2021-05-30 04:56:59 +04:30
Aria Moradi
849e2f103a [SKIP CI] download chapters for real now 2021-05-30 04:24:21 +04:30
Syer10
6c22fe193a Add meta info for clients to store custom data in (#113)
* Add meta info for clients to store custom data in

* PR comments

* Really update migration
2021-05-30 04:18:08 +04:30
Syer10
e69dbbf418 Working shared preferences (#112)
* Working shared preferences

* Remove unneeded prefs dir

* Todo
2021-05-30 04:05:56 +04:30
Aria Moradi
dfa59a1691 bump version to v0.4.2 2021-05-30 04:04:11 +04:30
Aria Moradi
5023e96301 Implemented Dowloads front-end 2021-05-30 04:01:49 +04:30
Aria Moradi
224c24ee9f a little reminder 2021-05-30 02:21:43 +04:30
Aria Moradi
e3b154cf9e Merge branch 'master' of github.com:Suwayomi/Tachidesk 2021-05-29 23:59:29 +04:30
Aria Moradi
d249867c4c finishing touches of download backend, done @jipfr's requests 2021-05-29 23:57:22 +04:30
Aria Moradi
b56045e984 downloader backend done 2021-05-29 23:05:51 +04:30
Manchewable
3777cc646e Improve continuous horizontal reader (#110)
* differentiate ContinuesHorizontalLTR and ContinuesHorizontalRTL

* fix displaying pages in horizontal viewer

* add scroll handler for horizontal mode

* update curPage when images pass through center of the screen

* add click events to navigate pages

* remove console.log

* fix click mapping for ContinuesHorizontalRTL

* remove disable eslint inline comment

* fix ContinuesHorizontalRTL not updating curPage on scroll

* add ability to click to drag

* add margin in between images
2021-05-29 19:41:59 +04:30
Manchewable
aa5a1083d0 fit images to height (#108) 2021-05-28 23:27:31 +04:30
Manchewable
2ae5e0742e reference to img elements directly (#106) 2021-05-28 23:25:04 +04:30
Aria Moradi
e5e875c54a closes #100 2021-05-28 20:21:05 +04:30
Aria Moradi
1a99ec76e4 spinner image, closes #77 2021-05-28 19:37:26 +04:30
Manchewable
1b122d1157 Add a Double Page Viewer (#105)
* add double page reader

* implement singleRTL

* add on image load handler

* add retry display time interval

* remove comments

* add double page wrapper

* fix image getting out of bounds

* remove comments

* remove unused styles

* return imageStyle as type CSSProperties

* rename DoublePagedReader to DoublePagedPager
2021-05-28 17:06:55 +04:30
Aria Moradi
77f2f8cc18 add copyright notice to files that miss it 2021-05-28 16:23:26 +04:30
Aria Moradi
f0a99980b6 fixed issue with clearing up orphan chapters 2021-05-28 03:46:32 +04:30
Aria Moradi
b0d43ffe69 anime filter everywhere 2021-05-28 03:02:14 +04:30
Aria Moradi
16cb0184a4 fix catalog source imports 2021-05-28 02:53:36 +04:30
Aria Moradi
f211a33ea3 bump to v0.4.1 2021-05-28 02:49:01 +04:30
Aria Moradi
440c815189 missed from previous commit 2021-05-28 02:46:19 +04:30
Aria Moradi
25829aacfd new anime library 2021-05-28 02:43:30 +04:30
Aria Moradi
700a739f95 probably fixes http leaks (by @Syer10) 2021-05-27 22:45:44 +04:30
Aria Moradi
d9620bec05 fix getManga returning false for inLibrary 2021-05-27 22:30:29 +04:30
Aria Moradi
4b6c51b1f8 bump to v0.4.0 2021-05-27 19:32:16 +04:30
Aria Moradi
bd02edf0b1 barebones anime player 2021-05-27 18:37:45 +04:30
Aria Moradi
5c7123a997 Manga page Finished 2021-05-27 17:13:22 +04:30
Aria Moradi
c17e3bd04f can work with anime extensions successfully 2021-05-27 05:13:01 +04:30
Aria Moradi
994ae97256 no dependenct on tachidesk 2021-05-27 03:33:56 +04:30
Aria Moradi
781428a690 add initial anime stuff 2021-05-27 03:25:55 +04:30
Aria Moradi
c23ac5faa8 fix compile issue 2021-05-27 02:23:17 +04:30
Aria Moradi
e8d41f83c2 move databse to server package, move tables to a better place 2021-05-27 02:21:53 +04:30
Aria Moradi
921a0a3361 Merge branch 'master' into anime 2021-05-27 02:16:07 +04:30
Aria Moradi
dda5a2df93 reconsider package strings 2021-05-27 02:13:17 +04:30
Aria Moradi
155f9f107d more of package moving 2021-05-27 02:07:32 +04:30
Aria Moradi
24f68b8f1a move packages 2021-05-27 01:57:40 +04:30
Aria Moradi
0ffbe194fa move packages 2021-05-27 01:57:15 +04:30
Aria Moradi
0b41e2b72b Adapted Tachiyomi-mi extensions-lib implementation 2021-05-27 00:04:33 +04:30
arbuilder
ef07b9b4ce [SKIP CI] Update Docker info (#99)
* Update README.md

update docker info

* [SKIP CI] update docker info

* [SKIP CI] Update Readme

change to small case
2021-05-26 11:00:13 +04:30
Aria Moradi
f3999cf2d9 [SKIP CI] update docker info 2021-05-26 02:48:13 +04:30
Syer10
1729847937 Allow building without git access (#98)
Just something SY needs...
2021-05-26 02:39:25 +04:30
Aria Moradi
37bff6c76c About Screen 2021-05-25 21:06:27 +04:30
Aria Moradi
4ef32d8037 build type 2021-05-25 19:23:47 +04:30
Aria Moradi
d2f6a33f0a fix listener not being removed 2021-05-25 16:19:08 +04:30
Aria Moradi
31d9903251 got rid of all instances of diabling no-unused-vars 2021-05-25 13:24:56 +04:30
Aria Moradi
e97642d92a prevPage handle
* go back to previous chapter on page 0 when prevPage is triggered
2021-05-25 13:14:07 +04:30
Aria Moradi
c49fc0ff5f only show supported pagers 2021-05-25 13:12:42 +04:30
Aria Moradi
deb2ab1ff4 closes #96 2021-05-25 13:12:17 +04:30
Manchewable
23466cf853 Added some key mappings to navigate pages (#95)
* Added some key mappings to navigate pages

* use keyboard event codes

* unused files removed

* use a reference to current page

* fix some bugs with Virtuoso

* add keymapping for space to navigate to next page

* commit my changes

* fix functions not regenerating

* fix partial scroll back to start of page issue

Co-authored-by: Aria Moradi <aria.moradi007@gmail.com>
2021-05-24 23:46:05 +04:30
Aria Moradi
16b34f874d fix some bugs with Virtuoso 2021-05-24 21:26:55 +04:30
Aria Moradi
0e0d08ae5a bump to v0.3.9 2021-05-24 18:32:01 +04:30
Aria Moradi
986b4c2c27 unused files removed 2021-05-24 18:31:39 +04:30
Aria Moradi
0bf9ccfcbd [SKIP CI] fix more typo 2021-05-24 18:22:48 +04:30
Aria Moradi
5e8c47928d [SKIP CI] fix typo 2021-05-24 18:22:16 +04:30
Aria Moradi
ffae7f911f [SKIP CI] update windows instructions 2021-05-24 18:21:23 +04:30
Aria Moradi
e37fdf6d79 [SKIP CI] update preview link 2021-05-24 17:31:07 +04:30
Aria Moradi
b359116745 clean up tests 2021-05-24 17:09:05 +04:30
Aria Moradi
60073aace3 test new publish 2021-05-24 17:04:47 +04:30
Aria Moradi
874b13fa14 test new publish 2021-05-24 17:02:30 +04:30
Aria Moradi
b146d1024b test new publish 2021-05-24 16:56:03 +04:30
Aria Moradi
332e95c021 test new publish 2021-05-24 16:52:30 +04:30
Aria Moradi
1f68141df5 test new publish 2021-05-24 16:39:17 +04:30
Aria Moradi
dd731cd306 test new publish 2021-05-24 16:34:12 +04:30
Aria Moradi
38d8d03cae test new publish 2021-05-24 16:30:32 +04:30
Aria Moradi
ec7d840f37 test new publish 2021-05-24 16:29:03 +04:30
Aria Moradi
2813dbb897 test new publish 2021-05-24 16:27:46 +04:30
Aria Moradi
77d1402b8a test new publish 2021-05-24 16:25:42 +04:30
Aria Moradi
08e8a9d105 Electron launcher 2021-05-24 15:37:25 +04:30
Aria Moradi
71661f70b6 flexible z names 2021-05-24 01:49:42 +04:30
Aria Moradi
ac1e79ba83 electron! 2021-05-24 01:39:12 +04:30
Aria Moradi
d082809776 prepare for electron 2021-05-24 00:42:25 +04:30
Aria Moradi
a458a696db webview starts! 2021-05-23 23:04:02 +04:30
Aria Moradi
75786a91b0 add webview 2021-05-23 22:10:04 +04:30
Aria Moradi
6ddb5db57b use HEAD for counting commits 2021-05-23 18:22:35 +04:30
Aria Moradi
4f70cc9283 bump to v0.3.8 2021-05-23 17:27:33 +04:30
Aria Moradi
23b643d637 set default category when adding new manga 2021-05-23 15:28:46 +04:30
Aria Moradi
fdfc256c4d Meaningful icons! 2021-05-23 13:48:02 +04:30
Aria Moradi
fba56c1b75 replace win64 exe with @Syer10's MSVC build 2021-05-23 12:48:47 +04:30
Aria Moradi
4743bfacf7 [SKIP CI] removing Swing force fixed it for @nar1n 2021-05-21 16:47:46 +04:30
Aria Moradi
2356537f7c try swing 2021-05-21 15:55:37 +04:30
Aria Moradi
fa071aee84 refactor github api 2021-05-20 20:41:00 +04:30
Aria Moradi
c00ca23a8b put the comment where it should be 2021-05-20 20:27:22 +04:30
Aria Moradi
733b017936 fix webUI not being copied 2021-05-20 19:51:52 +04:30
Aria Moradi
4147f2e368 better comment 2021-05-20 19:21:30 +04:30
Aria Moradi
154b9992eb rewrite without retrofit and kotlin-serialization 2021-05-20 19:20:07 +04:30
Aria Moradi
88b881b043 get rid of guava 2021-05-20 17:56:33 +04:30
Aria Moradi
5d1491fb8c fix package directive 2021-05-20 16:23:13 +04:30
Aria Moradi
3a33196cf1 cleanup dependencies 2021-05-20 16:22:54 +04:30
Aria Moradi
fa8e0478da lint file 2021-05-20 13:50:10 +04:30
Aria Moradi
7e7e069244 - Set log level eairlier
- Set AndroidCompat's data root properly
2021-05-20 13:48:33 +04:30
Aria Moradi
18e0d34af0 [SKIP CI] "improvments" 2021-05-20 10:52:57 +04:30
Aria Moradi
3fe3f35483 better commit messages 2021-05-20 10:33:33 +04:30
Aria Moradi
cf8e274883 better use of kotlin DSL 2021-05-20 10:24:33 +04:30
Aria Moradi
10dee8b345 improve downloader 2021-05-20 02:36:20 +04:30
Aria Moradi
ae8d30593f lint 2021-05-19 23:05:25 +04:30
Aria Moradi
9cde46b5da Fix chpater names, closes #81 2021-05-19 23:03:40 +04:30
Aria Moradi
8e61632155 open the right ip 2021-05-19 17:40:26 +04:30
Aria Moradi
e2c4b4cb57 handle when the user runs the app instead of clicking on systemtray 2021-05-19 17:38:33 +04:30
Aria Moradi
326da504ea fix gradle complaning about lint tasks depending on webUI:copyBuild 2021-05-19 17:03:12 +04:30
Aria Moradi
c5874a3f10 better chapter looks 2021-05-19 16:50:48 +04:30
Aria Moradi
02802fab97 Application mutex 2021-05-19 16:36:17 +04:30
Aria Moradi
29dea10be2 Merge branch 'master' of github.com:Suwayomi/Tachidesk 2021-05-19 13:42:59 +04:30
Aria Moradi
6bc36193dc open server's location please! 2021-05-19 13:42:18 +04:30
Syer10
81e123388e Fix restore crashing (#90) 2021-05-19 05:29:44 +04:30
Aria Moradi
8ebd7869a5 [SKIP CI] name em 2021-05-19 04:30:21 +04:30
Aria Moradi
7a2f5f13f1 [SKIP CI] name em 2021-05-19 04:28:57 +04:30
Aria Moradi
25d7dad39f build the ref that you have been given! 2021-05-19 04:26:20 +04:30
Aria Moradi
c8f8795920 Merge branch 'master' of github.com:Suwayomi/Tachidesk 2021-05-19 03:57:27 +04:30
Aria Moradi
84206a7074 bump to v0.3.7 2021-05-19 03:52:55 +04:30
Aria Moradi
6fd8b36dca [SKIP CI] links to the new preview repo 2021-05-19 03:45:24 +04:30
Aria Moradi
d1500baae1 try with access token 2021-05-19 03:21:47 +04:30
Aria Moradi
045801dd1a push to Suwayomi/Tachidesk-preview 2021-05-19 02:56:46 +04:30
Aria Moradi
14a2cbc793 [SKIP CI] fix typo 2021-05-19 02:52:28 +04:30
Aria Moradi
fd385017df [SKIP CI] fix typo 2021-05-19 02:50:22 +04:30
Aria Moradi
9b05954cf2 [SKIP CI] fix typo 2021-05-19 02:49:10 +04:30
Aria Moradi
6aaf636069 [SKIP CI] update for new scripts 2021-05-19 02:47:48 +04:30
Aria Moradi
d30e89e5ec update workflows to include both 32-bit and 64-bit windows bundles 2021-05-19 02:42:14 +04:30
Aria Moradi
7acc745478 Merge the two windows bundlers 2021-05-19 02:31:56 +04:30
Aria Moradi
5a9a2d816e 32-bit variant of bundler 2021-05-19 02:26:29 +04:30
Aria Moradi
105f11ed02 Merge branch 'master' of github.com:Suwayomi/Tachidesk 2021-05-19 00:28:56 +04:30
Aria Moradi
3021437a05 new preview system! 2021-05-19 00:28:14 +04:30
Aria Moradi
439602fc03 [SKIP CI] no more preview 2021-05-18 23:42:43 +04:30
Aria Moradi
34e13b9589 [SKIP CI] improve wording... 2021-05-18 23:28:59 +04:30
Aria Moradi
2aab4ae918 [SKIP CI] asking for help! 2021-05-18 23:27:14 +04:30
Aria Moradi
7ef67671a4 print tachidesk info on startup 2021-05-18 22:36:41 +04:30
Syer10
e8df84416c Smarter Chapters and cleanup (#87)
* Smarter Chapters and cleanup

* Fix check
2021-05-18 22:22:15 +04:30
Aria Moradi
be930bb68b update to the new scheme 2021-05-18 22:03:18 +04:30
Aria Moradi
db52948865 update windows instructions 2021-05-18 21:42:30 +04:30
Aria Moradi
d2a72526f6 bump to v0.3.6 2021-05-18 21:40:42 +04:30
Aria Moradi
0a9f57b32b cleanup 2021-05-18 21:38:41 +04:30
Aria Moradi
180f210536 update windows instructions 2021-05-18 21:35:57 +04:30
Aria Moradi
c1baa31eed the new and simple way of packaging windows 2021-05-18 21:31:25 +04:30
Aria Moradi
cacc97cec7 bump to v0.3.5 2021-05-18 02:39:00 +04:30
Aria Moradi
d5691fd81c show last read page on initial load 2021-05-18 02:26:45 +04:30
Aria Moradi
49dc9fe5f6 fix wrong chapter count, abstract next page 2021-05-18 01:10:28 +04:30
Aria Moradi
c0b49c7428 Merge branch 'master' of github.com:Suwayomi/Tachidesk 2021-05-18 00:45:42 +04:30
Aria Moradi
fa345af42d use Dispatchers.IO 2021-05-18 00:43:32 +04:30
Aria Moradi
db3cc786a1 rename the job 2021-05-18 00:43:21 +04:30
Aria Moradi
fe879ae51d [SKIP CI] update windows instructions 2021-05-18 00:01:04 +04:30
Aria Moradi
2f55460ffb unzip the jre 2021-05-17 23:33:54 +04:30
Aria Moradi
fbc5bd4642 bump to v0.3.4 2021-05-17 23:29:36 +04:30
Aria Moradi
5e0c7d3c9d ditch packr because it can't load extension jars 2021-05-17 23:28:23 +04:30
Aria Moradi
083996a48d wating on: https://github.com/Kotlin/kotlinx.coroutines/issues/261 2021-05-17 14:30:59 +04:30
Aria Moradi
9d38f478e3 fix slow manga thumbnails issue, next manga reset page issue 2021-05-17 14:22:24 +04:30
Aria Moradi
57274a0a01 remove unused electron script 2021-05-17 12:32:15 +04:30
Aria Moradi
b3b56b7fc8 also build windows package for publish 2021-05-17 12:30:15 +04:30
Forgenn
0b690577da Load next chapter when getting to the last page (#84)
* Load next chapter when scrolling to the bottom (Webtoon, Continues Vertical)

* Load next chapter when scrolling to the bottom (Paged reader)

* Added missing types to IReaderProps

* Move load next chapter when at last page to VerticalReader

* Dependency fix

* Use react history for loading next page
2021-05-17 12:27:14 +04:30
Aria Moradi
e9683a3a37 bump to v0.3.3 2021-05-17 12:02:01 +04:30
Aria Moradi
f8f67b3eba finish up 2021-05-17 11:59:59 +04:30
Aria Moradi
7b16b082d8 needs kt 2021-05-17 11:55:49 +04:30
Aria Moradi
2a783f0d8e btter folder name 2021-05-17 11:54:33 +04:30
Aria Moradi
42ae32de33 give the correct path 2021-05-17 11:40:38 +04:30
Aria Moradi
cec7ddc486 update file permissions 2021-05-17 11:28:26 +04:30
Aria Moradi
9c55fc3868 make windows package with packr 2021-05-17 11:20:24 +04:30
Syer10
104c5a8d83 Code cleanup (#85)
* GC Unused or only used once objects

* Move things around a bit

* Revert some changes

* Fix imports

* Revert about change

* Put back logger

* Private logger

* Revert systemtray

* Move import
2021-05-17 02:48:01 +04:30
Aria Moradi
7450b16742 - Reader -> Pager
- add cloneObject
- add missing copyright notices
2021-05-17 01:38:59 +04:30
Aria Moradi
3ecd0931a1 missing from the previous commit 2021-05-17 01:37:25 +04:30
Aria Moradi
2f2a52ae2f Move navbars 2021-05-17 01:36:31 +04:30
Aria Moradi
f464087c30 also handle Errors from java 2021-05-16 23:58:32 +04:30
Aria Moradi
2364960388 Merge branch 'master' of github.com:Suwayomi/Tachidesk 2021-05-16 22:15:35 +04:30
Aria Moradi
76be4d64cd update launch4j's jre and make it 64bit 2021-05-16 12:39:05 +04:30
Aria Moradi
7d98e8ce47 [SKIP CI] correct link 2021-05-16 01:53:35 +04:30
Aria Moradi
40831fc681 [SKIP CI] new links 2021-05-16 01:52:01 +04:30
Aria Moradi
e38e7ccf26 [SKIP CI] troubleshooting from the wiki 2021-05-16 01:48:49 +04:30
Aria Moradi
98b9e2f2cf [SKIP CI] no need to delete data anymore... 2021-05-16 01:47:33 +04:30
Aria Moradi
4bf3c12f76 fixed when spinner stops just after first offline chapter fetch 2021-05-16 01:07:48 +04:30
Aria Moradi
bab25f9ad9 bump version 2021-05-15 23:24:25 +04:30
Aria Moradi
a62ee8f8c3 handle reader types 2021-05-15 23:22:37 +04:30
Aria Moradi
5f23691e20 add toast lib 2021-05-15 20:37:07 +04:30
Aria Moradi
3de9ccc62f stop spinning if chapter list is empty 2021-05-15 18:51:38 +04:30
Aria Moradi
1896f7f37b remove lazy load 2021-05-15 18:26:40 +04:30
Aria Moradi
490643dc02 proof of concept readers 2021-05-15 18:17:12 +04:30
Aria Moradi
9808976088 restructure the reader 2021-05-15 17:18:57 +04:30
Aria Moradi
5a73068a10 bump to v0.3.1 2021-05-15 14:53:44 +04:30
Aria Moradi
01d5c2540d chapter updates when pressing UI buttons 2021-05-15 13:43:26 +04:30
Aria Moradi
866b01f865 support bookmarked and isRead in webUI 2021-05-14 19:22:10 +04:30
Aria Moradi
da6a953099 exposed error 2021-05-14 17:31:07 +04:30
Aria Moradi
bce8d58845 make it look nicer? 2021-05-14 02:01:28 +04:30
Aria Moradi
3cfce2db04 fix chapters not shown on movbile 2021-05-13 21:40:42 +04:30
Aria Moradi
327aae5dd9 Merge pull request #79 from Suwayomi/read-category
Support more chapter parameters
2021-05-13 18:34:27 +04:30
Aria Moradi
1bdfde7032 no longer TODO 2021-05-13 18:33:24 +04:30
Aria Moradi
295a0817b0 fix wrong chapters being removed, fix da css 2021-05-13 18:29:20 +04:30
Aria Moradi
a02dc02d52 remove console prints 2021-05-13 17:49:33 +04:30
Aria Moradi
dc012edf7d staisfying results? with chapters scrolling 2021-05-13 17:46:40 +04:30
Aria Moradi
1e2eb11c13 update dependencies 2021-05-13 15:01:37 +04:30
Aria Moradi
3a825f4f25 fix manga thumbnail loading bug 2021-05-12 10:39:21 +04:30
Aria Moradi
b9ea8c5f74 code cleanup 2021-05-12 10:20:01 +04:30
Aria Moradi
320d7e2536 reformat 2021-05-11 18:55:09 +04:30
Aria Moradi
c200785479 handle front, handle orphans 2021-05-11 18:45:53 +04:30
Aria Moradi
8abb132ad6 chapter new parameters get endpoint 2021-05-11 15:50:18 +04:30
Aria Moradi
8bb2269f36 [SKIP CI] fix typo 2021-05-08 20:33:53 +04:30
Aria Moradi
9d17b26283 [SKIP CI] up for debate 2021-05-07 19:41:34 +04:30
Aria Moradi
5909f15db7 [SKIP CI] code of conduct 2021-05-07 19:39:24 +04:30
Aria Moradi
11672ca576 [SKIP CI] 2021-05-07 19:35:11 +04:30
Aria Moradi
e09773def3 [SKIP CI] potential contributors 2021-05-07 19:32:32 +04:30
Aria Moradi
f6d4432e6f [SKIP CI] typo 2021-05-07 19:13:48 +04:30
Aria Moradi
45a6abc5c2 [SKIP CI] improve structure 2021-05-07 19:13:04 +04:30
Aria Moradi
dc5e677a38 [SKIP CI] simplify 2021-05-07 19:05:11 +04:30
Aria Moradi
a82549dc17 [SKIP CI] why a web app? 2021-05-07 19:02:56 +04:30
Aria Moradi
a002e19d9d [SKIP CI] move info to CONTRIBUTING.md 2021-05-07 18:58:09 +04:30
Aria Moradi
cdf1f98d28 [SKIP CI] move troubleshooting to wiki 2021-05-07 18:51:47 +04:30
Aria Moradi
0ff1ebdeb7 [SKIP CI] not alternative 2021-05-07 18:36:32 +04:30
Aria Moradi
17f4a396f8 [SKIP CI] one must know friend from foe! 2021-05-07 18:29:01 +04:30
Aria Moradi
8aa3cf4368 [SKIP CI] move stuff around 2021-05-07 18:27:10 +04:30
Aria Moradi
0136c5e493 [SKIP CI] alternative ui projects 2021-05-07 18:21:32 +04:30
Aria Moradi
8b94b9ee80 [SKIP CI] add contributing.md 2021-05-07 18:17:55 +04:30
Aria Moradi
bed63f19f2 [SKIP CI] move technical info to contributing.md 2021-05-07 18:04:51 +04:30
Aria Moradi
e2a6545a84 [SKIP CI] 2021-05-07 15:28:30 +04:30
Aria Moradi
e3d3ec6895 fix sed output 2021-05-07 14:41:19 +04:30
Aria Moradi
7ba476bd79 include v 2021-05-07 14:39:15 +04:30
Aria Moradi
2dd41ebd27 Merge branch 'master' of github.com:Suwayomi/Tachidesk 2021-05-07 14:25:11 +04:30
Aria Moradi
038df78171 new preview version format 2021-05-07 14:24:28 +04:30
Aria Moradi
6e5ff2b508 [SKIP CI] it be "chrome OS" 2021-05-07 13:45:31 +04:30
Aria Moradi
ec8d1e8680 [SKIP CI] more housekeeping! 2021-05-07 13:42:02 +04:30
Aria Moradi
1f0f0c33b7 [SKIP CI] housekeeping 2021-05-07 13:32:42 +04:30
Aria Moradi
825940fcac [SKIP CI] add running instructions 2021-05-07 13:17:15 +04:30
Aria Moradi
4618834af2 [SKIP CI] Make it simpler 2021-05-07 11:24:40 +04:30
Aria Moradi
55d968df5e [SKIP CI] add some doc comments 2021-05-06 23:06:35 +04:30
Aria Moradi
63a078cf7d Add migrations (#76) 2021-05-06 18:46:12 +04:30
Aria Moradi
5304917e53 fix multiple version warning 2021-05-06 14:14:04 +04:30
Aria Moradi
831b74d2ec bintray is dead 2021-05-06 13:07:40 +04:30
Aria Moradi
1bad9dcd69 [SKIP CI] 2021-05-05 15:54:05 +04:30
Aria Moradi
dd43716851 [SKIP CI] more info 2021-05-05 15:26:52 +04:30
Aria Moradi
f2e55e95a2 reaffirmation of what Tachidesk is for some Twitter users... 2021-05-05 15:22:46 +04:30
Aria Moradi
14658a0c4d be fancy about the manifest info 😎 2021-05-04 00:15:31 +04:30
Aria Moradi
4195e7056b fix windowsPackge not building the jar 2021-05-03 23:51:48 +04:30
Aria Moradi
1d29e8b248 fix webUI not working with gradle 7.0 2021-05-03 23:21:37 +04:30
Syer10
b718c718df Download directly to file instead of a dir (#70) 2021-05-03 23:00:18 +04:30
Aria Moradi
a3601cf1b5 fix pull request build 2021-05-03 22:57:54 +04:30
Aria Moradi
0236a9639b rename vals, comments 2021-05-03 22:30:43 +04:30
Syer10
5f4c7454ee Update everything (#68)
* Update everything, cleanup build.gradle.kts's

* Make requested changes
2021-05-03 22:19:09 +04:30
Aria Moradi
773120c96a make the app build 2021-05-03 20:50:09 +04:30
Aria Moradi
4b273c6bf9 add a bit of docs 2021-05-03 20:48:29 +04:30
Aria Moradi
b626aa66ba Merge branch 'master' of github.com:Suwayomi/Tachidesk 2021-05-03 20:41:46 +04:30
Syer10
1dd029559e Stop Javalin properly on shutdown (#69) 2021-05-03 20:40:02 +04:30
Aria Moradi
59cbe5d5bc [SKIP CI] Yes, we do use git 2021-04-30 06:15:56 +04:30
Aria Moradi
40d1173653 put DBManager where it should be 2021-04-30 06:10:41 +04:30
Aria Moradi
bf6a0aba5d Rework the version endpoint 2021-04-30 06:07:29 +04:30
Kolby Moroz Liebl
34d8feacdd Add version api endpoint (#66) 2021-04-30 05:47:23 +04:30
Kolby Moroz Liebl
1ea821584c [SKIP CI] Remove IE Requirement in ps1 script (#65) 2021-04-29 01:52:24 +04:30
Aria Moradi
3d2fee19bb refactor 2021-04-28 10:25:01 +04:30
Forgenn
449d12779a Truncate manga description if it's too long (#63)
* Manga description changed from 4096 to 8192

* Check that the description of a manga is not longer than 4096, trim otherwise

* Revert description length changes
2021-04-28 09:50:56 +04:30
Aria Moradi
6fb6a251e7 [SKIP CI] latest pointer link 2021-04-18 20:52:59 +04:30
Aria Moradi
4d6220f894 dir pointer 2021-04-18 20:45:15 +04:30
Aria Moradi
fe747bfc52 [SKIP CI] fix link 2021-04-18 20:14:17 +04:30
Aria Moradi
0c2d038870 [SKIP CI] add logo back 2021-04-18 20:05:58 +04:30
Aria Moradi
4e3f73af75 fix string 2021-04-18 19:58:07 +04:30
Aria Moradi
63e5e1b45f add indexer 2021-04-18 19:50:26 +04:30
Aria Moradi
2e1558bd96 [SKIP CI] fix discord links, again 2021-04-18 19:40:25 +04:30
Aria Moradi
0671dee8b2 [SKIP CI] fix discord link 2021-04-18 19:38:43 +04:30
Aria Moradi
8f91b8089a [SKIP CI] fix preview 2021-04-18 19:38:05 +04:30
Aria Moradi
009b45f676 [SKIP CI] discord? 2021-04-18 19:26:28 +04:30
Aria Moradi
8f7d5eb311 [SKIP CI] badges 2021-04-18 19:22:25 +04:30
Aria Moradi
f3de835ef3 Update build_push.yml 2021-04-18 18:51:58 +04:30
Aria Moradi
fd6662f428 bring back the old licenses 2021-04-18 17:48:42 +04:30
Aria Moradi
fde137b3ed restore categories 2021-04-18 12:40:09 +04:30
Aria Moradi
a1349aa0e3 Merge branch 'master' of github.com:Suwayomi/Tachidesk 2021-04-18 11:54:44 +04:30
Aria Moradi
c9ef5f9b9d lint meh 2021-04-18 11:50:02 +04:30
Aria Moradi
8fbf564177 also backup chapter and category data 2021-04-18 11:48:14 +04:30
Aria Moradi
ae0b1a818c [SKIP CI] update troubleshooting guide 2021-04-15 15:57:42 +04:30
Aria Moradi
c04cc780b7 update discord invite 2021-04-15 14:15:49 +04:30
Aria Moradi
71ad1bb6e3 Merge branch 'master' of github.com:Suwayomi/Tachidesk 2021-04-13 10:54:50 +04:30
Aria Moradi
c1be77ee9b Merge pull request #60 from Arias800/patch-1
Fix white screen if the manga doesn't have genre.
2021-04-13 10:54:08 +04:30
Aria Moradi
d1fa857ffb avoid creating the jar befre the front-end is copied 2021-04-13 10:53:23 +04:30
Aria Moradi
93fd81b38b [SKIP CI] fix the glob 2021-04-13 10:36:34 +04:30
Aria Moradi
2f116b40b2 fix chapter reading not working 2021-04-13 01:23:09 +04:30
Arias800
b884d34bdf Fix white screen if the manga doesn't have genre. 2021-04-10 19:42:05 +02:00
Aria Moradi
309803368b [SKIP CI] rename workflow 2021-04-10 10:39:47 +04:30
Aria Moradi
19fc5be8f3 [SKIP CI] rename workflow 2021-04-10 10:35:28 +04:30
Aria Moradi
c28fac14c0 Merge branch 'master' of github.com:Suwayomi/Tachidesk 2021-04-10 10:30:47 +04:30
Aria Moradi
66e38de29f check for deps 2021-04-10 10:28:54 +04:30
Aria Moradi
282cb1d3be [CI SKIP] account for windows 2021-04-10 10:16:24 +04:30
Aria Moradi
b741ded595 [SKIP CI] improve wording 2021-04-10 10:13:56 +04:30
Aria Moradi
6b290695fc [SKIP CI] update for preview builds 2021-04-10 10:09:25 +04:30
Aria Moradi
4e43c554c0 fix triggers 2021-04-10 10:01:39 +04:30
Aria Moradi
090a72b35f rename repo to preview 2021-04-10 09:57:02 +04:30
Aria Moradi
3fcc269df3 now we can deploy repo too 2021-04-10 09:54:03 +04:30
Aria Moradi
9958e0eb34 bump version 2021-04-10 09:21:42 +04:30
Aria Moradi
c5269002a2 Update README.md 2021-04-10 01:18:15 +04:30
Aria Moradi
455a35f8ae front-end UI done 2021-04-10 00:44:13 +04:30
Aria Moradi
0c79f207c3 fist version of a working backup system 2021-04-09 22:59:13 +04:30
Aria Moradi
cd16d32a35 first instance of legacy import 2021-04-09 19:21:04 +04:30
Aria Moradi
1989c1eb48 add copyright notice 2021-04-09 18:18:40 +04:30
Aria Moradi
f56856529f Merge pull request #55 from txtsd/master
Fix blatant typo
2021-04-06 22:27:53 +04:30
txtsd
52e27a3e39 Fix typo 2021-04-06 14:52:26 +05:30
Aria Moradi
177c971b52 This is better. 2021-04-04 03:37:00 +04:30
Aria Moradi
7a52e19235 Better way of setting it maybe? 2021-04-04 03:23:50 +04:30
Aria Moradi
5171e509a5 remove TOOD 2021-04-04 03:16:02 +04:30
Aria Moradi
975a3b1828 Merge pull request #53 from Syer10/testing_suit
Add initial testing suit
2021-04-04 03:14:27 +04:30
Syer10
c11887fada Allow rootdir to be used as a argument 2021-04-03 18:35:30 -04:00
Syer10
e043cb5690 Use properties to set rootDir so that ConfigManager can use it 2021-04-03 18:12:01 -04:00
Syer10
b2d5354798 dirs -> applicationDirs 2021-04-03 17:25:53 -04:00
Syer10
a211a4143b Revert source id to long 2021-04-03 16:57:03 -04:00
Syer10
c0df7d314b Add initial testing suit 2021-04-03 16:42:13 -04:00
Aria Moradi
c8a8ce07e2 fix windows path 2021-04-04 00:52:58 +04:30
Aria Moradi
e0e474dfce fixes from inspector 2021-04-03 22:40:14 +04:30
Aria Moradi
7591748811 fixes from inspector 2021-04-03 20:30:28 +04:30
Aria Moradi
884308690f fixes from inspector 2021-04-03 20:08:50 +04:30
Aria Moradi
15bd5b4b7a the new and improved apk installer 2021-04-03 19:47:31 +04:30
Aria Moradi
abc3a16ee3 fix typo 2021-04-03 15:40:23 +04:30
Aria Moradi
bb09ccf3c0 lint 2021-04-03 15:26:23 +04:30
Aria Moradi
ad2ea8095b fixes from the inspector project 2021-04-03 15:09:48 +04:30
Aria Moradi
760d1116a1 prepare to install apk from any source 2021-04-03 13:20:14 +04:30
Aria Moradi
47fcf7eb97 export extensions 2021-04-02 18:10:02 +04:30
Aria Moradi
b0e90c2f63 use the correct endpoint 2021-04-02 18:05:42 +04:30
Aria Moradi
f502884fdd a partially working legacy import... 2021-04-02 17:57:29 +04:30
Aria Moradi
5ed79523d2 Move getHttpSource to util as it is a util 2021-04-02 14:17:37 +04:30
Aria Moradi
da5dd70969 use future properly 2021-04-02 14:06:41 +04:30
Aria Moradi
68e69085df flatten the code 2021-04-02 13:56:38 +04:30
Aria Moradi
640ce8f5d7 add future shorthand 2021-04-02 04:09:48 +04:30
Aria Moradi
c960cc1ee5 update comment 2021-04-02 03:24:12 +04:30
Aria Moradi
2b2601aa4a move coroutines to root 2021-04-02 03:14:40 +04:30
Aria Moradi
99a10ec7db improve logging 2021-04-02 03:14:19 +04:30
Aria Moradi
035105adf0 refactor and more 2021-04-02 02:56:16 +04:30
Aria Moradi
f983f0e359 Merge pull request #46 from Syer10/future
Implement coroutines
2021-04-02 02:53:59 +04:30
Syer10
769472b24c Implement coroutines 2021-04-01 16:07:35 -04:00
Aria Moradi
8c80ad7575 fix time between extensions list checks 2021-04-01 23:39:00 +04:30
Aria Moradi
63db2e6695 fix HNI-Scantard not installing correctly 2021-04-01 23:34:52 +04:30
Aria Moradi
d6d5e97fbd Merge pull request #45 from Syer10/getRepo
Fix getRepo function
2021-04-01 23:15:45 +04:30
Syer10
1ae0a8326e Fix getRepo function 2021-04-01 14:42:13 -04:00
Aria Moradi
57693fef7b clean up 2021-03-30 21:48:05 +04:30
Aria Moradi
5656016700 let's not polute the namespace together 2021-03-30 21:10:41 +04:30
Aria Moradi
90ae180b3e let's not polute the namespace 2021-03-30 21:04:06 +04:30
Aria Moradi
2a3c78d43e refactor 2021-03-30 20:49:54 +04:30
Aria Moradi
11000af718 get gz insead of big big json 2021-03-30 20:41:20 +04:30
Aria Moradi
b808121f1d Merge branch 'master' of github.com:Suwayomi/Tachidesk 2021-03-30 20:39:56 +04:30
Aria Moradi
addadefeb1 some refactor and comments 2021-03-30 20:39:40 +04:30
Aria Moradi
838cd20e57 new build scripts 2021-03-30 20:21:58 +04:30
Aria Moradi
5b9219522d separate jar task from webUI copy task 2021-03-30 20:14:25 +04:30
Aria Moradi
caeb4d273d refactor 2021-03-30 17:34:15 +04:30
Aria Moradi
77cf87c989 refactor 2021-03-30 17:21:41 +04:30
Aria Moradi
50c2dbed5d refactor 2021-03-30 16:52:10 +04:30
Aria Moradi
71a9396952 starts of legacy backup support 2021-03-30 01:18:57 +04:30
Aria Moradi
bc3ad75328 finished Update support: webUI side 2021-03-29 02:47:51 +04:30
Aria Moradi
077bbc3c38 refactor & support for extension update: Backend 2021-03-29 00:35:58 +04:30
Aria Moradi
b1b1abad1d refactor proxy 2021-03-28 20:41:39 +04:30
Aria Moradi
e6ba2a0066 bump version 2021-03-28 13:53:03 +04:30
Aria Moradi
9b56ef7d82 Merge branch 'master' of github.com:Suwayomi/Tachidesk 2021-03-28 13:50:33 +04:30
Aria Moradi
dd442c6653 fix extensions not being installed correctly 2021-03-28 13:40:18 +04:30
Aria Moradi
3044317b09 Update README.md 2021-03-28 06:00:34 +04:30
Aria Moradi
3a1e1e01dc continues gap switch 2021-03-28 04:03:46 +04:30
Aria Moradi
a567701639 chapter image fix for bato.to 2021-03-28 03:43:52 +04:30
Aria Moradi
1802271358 fix chapters not being loaded correctly 2021-03-28 03:19:01 +04:30
Aria Moradi
9e649eef79 fix a bug where add to library didn't work 2021-03-28 02:43:09 +04:30
Aria Moradi
1eb4a9c216 use logger to print exception 2021-03-28 02:11:40 +04:30
Aria Moradi
e3f65d2192 fix URI exception 2021-03-28 01:35:46 +04:30
Aria Moradi
bb09cfddb3 Migrate from Oracle Nashorn to Mozilla's Rhino 2021-03-28 01:15:50 +04:30
Aria Moradi
d383939c9f improve loading spinner's place 2021-03-28 01:12:32 +04:30
Aria Moradi
32dd543562 Loading placeholder & css fixes 2021-03-27 22:21:39 +04:30
Aria Moradi
5a75f26791 even better logging messages 2021-03-27 19:40:47 +04:30
Aria Moradi
95c437efd5 better logging 2021-03-27 18:53:29 +04:30
Aria Moradi
ec877f632f refactor & config improvments 2021-03-27 18:30:36 +04:30
Aria Moradi
8666cbf8bc lint some files 2021-03-26 12:15:14 +04:30
Aria Moradi
84b0c26450 change the copyright owner to Contributors to the Suwayomi project 2021-03-26 04:17:02 +04:30
Aria Moradi
64e5bbabb3 Update enters 2021-03-26 02:40:20 +04:30
Aria Moradi
cc1a15e5ba Update enters 2021-03-26 02:39:54 +04:30
Aria Moradi
d29e942a72 Update getAndroid.sh 2021-03-26 02:33:24 +04:30
Aria Moradi
8d86c88c38 Update getAndroid.ps1 2021-03-26 02:33:03 +04:30
Aria Moradi
c7dc7421aa Update getAndroid.sh 2021-03-26 02:32:51 +04:30
Aria Moradi
34ed3e5c68 Update getAndroid.ps1 2021-03-26 02:29:31 +04:30
Aria Moradi
1a4a8af384 Merge pull request #42 from Syer10/getandroid
getAndroid.ps1: Silently continue if it cant remove the tmp folder
2021-03-26 02:21:43 +04:30
Aria Moradi
62b1e99bbf get the right dex2jar package please 2021-03-26 02:07:00 +04:30
Syer10
1aa3b76934 getAndroid.ps1: Silently continue if it cant remove the tmp folder 2021-03-25 16:47:30 -04:00
Aria Moradi
3e53c50f64 better spelling 2021-03-25 18:32:31 +04:30
Aria Moradi
430386bc84 Merge branch 'master' of github.com:Suwayomi/Tachidesk 2021-03-25 18:21:57 +04:30
Aria Moradi
30049e8152 Update README.md 2021-03-25 18:21:14 +04:30
Aria Moradi
34d9a7a233 better use of dex2jar, get dex2jar from jitpack 2021-03-25 18:03:32 +04:30
Aria Moradi
183972475b better loging 2021-03-25 16:53:36 +04:30
Aria Moradi
fd46727f8e Merge pull request #40 from Syer10/Powerhsell
Create getAndroid.ps1
2021-03-25 05:07:03 +04:30
Syer10
f6ce010aa2 Update readme 2021-03-24 20:34:32 -04:00
Syer10
d0ff30df9f Create getAndroid.ps1 2021-03-24 20:28:34 -04:00
Aria Moradi
8e449abd67 Merge pull request #39 from Syer10/LF
Standardize Line endings
2021-03-25 04:53:22 +04:30
Syer10
2986130268 Standardize Line endings 2021-03-24 19:51:18 -04:00
Aria Moradi
1c0c09f2f2 add server Desktop Environment 2021-03-25 04:03:48 +04:30
Aria Moradi
44100cb5b6 closes #37 2021-03-25 01:03:51 +04:30
Aria Moradi
cfc6e5cd2a Fix for jip's Arch Linux 2021-03-24 19:28:27 +04:30
Aria Moradi
c067d14c2c Update README.md 2021-03-24 19:26:37 +04:30
Aria Moradi
aded854a2b Update README.md 2021-03-24 19:24:50 +04:30
Aria Moradi
e79d0b9dd2 search loading message 2021-03-24 03:31:38 +04:30
Aria Moradi
a0115d88b0 fix search bugs 2021-03-24 03:28:02 +04:30
Aria Moradi
85ec2ed367 drawer hide on click outside of it 2021-03-23 04:28:23 +04:30
Aria Moradi
bf908c4d17 chapter prev/next UI+Backend 2021-03-23 03:50:55 +04:30
Aria Moradi
f41c5c9428 bump version 2021-03-19 14:55:48 +03:30
Aria Moradi
04837983fa reader ui changes 2021-03-19 14:52:20 +03:30
Aria Moradi
5d484b012c new layout for manga page for >md 2021-03-18 22:55:17 +03:30
Aria Moradi
436a8d0585 improvments on the reader 2021-03-18 21:46:24 +03:30
Aria Moradi
28cc0a6f84 Merge branch 'master' of github.com:AriaMoradi/Tachidesk 2021-03-17 19:22:44 +03:30
Aria Moradi
26cc2f2c96 MangaDetails component improved drastically 2021-03-17 19:17:03 +03:30
Aria Moradi
149107e749 fix material error 2021-03-16 23:42:51 +03:30
Aria Moradi
a74936c5f5 Update README.md 2021-03-16 23:24:14 +03:30
Aria Moradi
ff8c8913d4 Update README.md 2021-03-16 23:14:36 +03:30
Aria Moradi
83426e1302 Update README.md 2021-03-16 23:13:44 +03:30
Aria Moradi
9cd93d467c bump version 2021-03-16 16:15:20 +03:30
Aria Moradi
257f8a5a27 fix extensions not showing the all pesudo-language 2021-03-16 16:10:06 +03:30
Aria Moradi
79bab08cae improvements 2021-03-16 16:04:29 +03:30
Aria Moradi
4e699e4f5a update dex2jar 2021-03-16 15:44:50 +03:30
Aria Moradi
1128f40bac closes #32 2021-03-14 23:57:33 +03:30
Aria Moradi
53ef836326 fix windows path 2021-03-14 20:28:23 +03:30
Aria Moradi
b8df0e89e5 Don't show installed if nothing is installed 2021-03-14 14:09:31 +03:30
Aria Moradi
472bfec6bf improve docs 2021-03-14 01:26:52 +03:30
Aria Moradi
c1b86cedd2 move getAndroid.sh 2021-03-14 01:02:43 +03:30
Aria Moradi
428c65f075 Enforce more limits on the issue format. 2021-03-13 22:59:37 +03:30
Aria Moradi
92ed48f7f6 bump version to v0.2.4 2021-03-13 11:08:39 +03:30
Aria Moradi
13e84bc492 Maskable icons 2021-03-13 11:06:22 +03:30
Aria Moradi
0ef86c34b7 server configuration fam 2021-03-11 14:43:29 +03:30
Aria Moradi
7e1a4259d7 fix langs not showing correctly 2021-03-09 18:05:34 +03:30
Aria Moradi
c842c51fb6 section sources by lang 2021-03-09 16:44:09 +03:30
Aria Moradi
6f2f228e08 section extension languages 2021-03-08 21:04:42 +03:30
Aria Moradi
c78eaa8b96 add issue closer 2021-03-08 13:47:58 +03:30
Aria Moradi
f9606526d2 add issue closer 2021-03-08 13:39:25 +03:30
Aria Moradi
fe4cc9ea2c add issue closer 2021-03-08 13:32:17 +03:30
Aria Moradi
54d0c05fcc add issue closer 2021-03-08 13:31:03 +03:30
Aria Moradi
2f7df73a37 add issue closer 2021-03-08 13:22:44 +03:30
Aria Moradi
cf19f3626b improve text 2021-03-08 13:01:23 +03:30
Aria Moradi
ff2da5e59b issue template 2021-03-08 12:57:12 +03:30
Aria Moradi
e03922e518 fix PWA icons 2021-03-07 23:08:30 +03:30
Aria Moradi
893fba5b8c fix image urls 2021-03-07 22:35:27 +03:30
Aria Moradi
c1786f8e24 migrate to axios, front-end part of configurable ServerAddress 2021-03-07 22:25:29 +03:30
Aria Moradi
a59f974537 fix #25 2021-03-07 22:12:38 +03:30
Aria Moradi
7157e07328 better messages, axios client 2021-03-07 16:27:13 +03:30
Aria Moradi
954084bd82 Merge branch 'master' of github.com:AriaMoradi/Tachidesk 2021-03-07 10:51:24 +03:30
Aria Moradi
0915ba40f6 🤌 Tachidesk's logo! 2021-02-25 21:54:49 +03:30
Aria Moradi
de30d55bcf darkTheme in localStorage 2021-02-25 14:38:16 +03:30
Aria Moradi
af1c34fba5 v0.2.3 2021-02-24 12:27:28 +03:30
Aria Moradi
7b7d93786f Merge branch 'master' of github.com:AriaMoradi/Tachidesk 2021-02-24 12:09:39 +03:30
Aria Moradi
7c1c504482 new icon, fix headless systems crashing 2021-02-24 11:55:43 +03:30
Aria Moradi
33b22fcab6 Update README.md 2021-02-22 14:54:04 +03:30
Aria Moradi
ab0566dcba Update README.md 2021-02-22 14:51:39 +03:30
Aria Moradi
c4f2cc7189 Update README.md 2021-02-22 14:49:17 +03:30
Aria Moradi
4626d99590 Update README.md 2021-02-22 14:48:17 +03:30
Aria Moradi
6465ca8a19 Update README.md 2021-02-22 01:29:55 +03:30
Aria Moradi
15b9d151df Update README.md 2021-02-22 01:28:13 +03:30
Aria Moradi
dd1b6c86cd Update README.md 2021-02-22 01:23:44 +03:30
Aria Moradi
9613cda79a new icons by @as280093 2021-02-21 23:37:11 +03:30
Aria Moradi
648b8e5960 bump version: v0.2.2 2021-02-21 04:42:33 +03:30
Aria Moradi
ce545b1fd5 fix some bugs 2021-02-21 04:41:56 +03:30
Aria Moradi
9151034fbc category done! 2021-02-21 04:27:41 +03:30
Aria Moradi
312a8baa13 hide menu button for now 2021-02-20 02:59:32 +03:30
Aria Moradi
18b6168cd1 theme select in settings 2021-02-20 02:57:52 +03:30
Aria Moradi
9a282c3bf4 redirect / to library 2021-02-20 02:41:30 +03:30
Aria Moradi
2bbebe4c30 fix removing manga from library not working 2021-02-20 02:34:26 +03:30
Aria Moradi
162961b560 fix tabs 2021-02-20 02:28:55 +03:30
Aria Moradi
f1cc37d0db finished the category screen 2021-02-20 01:23:52 +03:30
Aria Moradi
5a9d216fb7 bump version 2021-02-14 23:18:14 +03:30
Aria Moradi
bf37d3be7c fix syntax 2021-02-14 22:51:22 +03:30
Aria Moradi
7fd57aaed8 try new release action 2021-02-14 22:49:40 +03:30
Aria Moradi
d996c44b24 try publish wiht draft 2021-02-14 22:20:50 +03:30
Aria Moradi
6f3052dd1b category backend 2021-02-14 01:10:43 +03:30
Aria Moradi
d2b1bfdcdd Merge branch 'master' of github.com:AriaMoradi/Tachidesk 2021-02-13 22:45:18 +03:30
Aria Moradi
945fb99594 Update README.md 2021-02-13 21:25:49 +03:30
Aria Moradi
09d624a4e2 add library 2021-02-13 21:12:18 +03:30
Aria Moradi
eb90db7ce6 Update README.md 2021-02-13 17:18:31 +03:30
Aria Moradi
b56f9391b8 Update README.md 2021-02-13 17:07:39 +03:30
Aria Moradi
c181478909 Update README.md 2021-02-13 17:06:37 +03:30
Aria Moradi
76b31e734c Update README.md 2021-02-13 17:06:16 +03:30
Aria Moradi
ed8bd76d95 dummy file to trigger actions 2021-02-13 15:34:17 +03:30
Aria Moradi
3051a72d7f add node_modules cache 2021-02-13 15:30:15 +03:30
Aria Moradi
3a33bf3a5d just download android.jar to improve build time 2021-02-13 15:18:57 +03:30
Aria Moradi
7959ba2664 [RELEASE CI] test new release 2021-02-13 14:50:46 +03:30
Aria Moradi
fe6568b82c [RELEASE CI] test new release 2021-02-13 14:39:16 +03:30
Aria Moradi
c228648bb6 [RELEASE CI] test new release 2021-02-13 14:15:38 +03:30
Aria Moradi
fdaeb6d1fa [RELEASE CI] test new release 2021-02-13 14:01:01 +03:30
Aria Moradi
ba45e18399 [RELEASE CI] test new release 2021-02-13 13:39:52 +03:30
Aria Moradi
3e2bf877d4 [RELEASE CI] test new release 2021-02-13 13:32:59 +03:30
Aria Moradi
c80d344046 [RELEASE CI] test new release 2021-02-13 13:21:13 +03:30
Aria Moradi
2364f10d8d [RELEASE CI] test new release 2021-02-13 13:13:15 +03:30
Aria Moradi
2602275c20 [RELEASE CI] test new release 2021-02-13 13:12:40 +03:30
Aria Moradi
d113311f4e [RELEASE CI] test new release 2021-02-13 12:57:01 +03:30
Aria Moradi
8d95701e8e [RELEASE CI] test new release 2021-02-13 12:55:57 +03:30
Aria Moradi
0d2c54a5ed [RELEASE CI] test new release 2021-02-13 12:54:36 +03:30
Aria Moradi
6506c84b85 publish? 2021-02-08 05:36:19 +03:30
Aria Moradi
69bb38b487 [CI RELEASE] do it 2021-02-08 05:12:13 +03:30
Aria Moradi
95e17f2b50 Merge branch 'master' of github.com:AriaMoradi/Tachidesk 2021-02-08 05:11:48 +03:30
Aria Moradi
9625da9221 [RLEASE CI] add upload release binaries action 2021-02-08 05:11:21 +03:30
Aria Moradi
c1659f1cf2 refactor, add todos for library and category 2021-02-06 18:48:59 +03:30
Aria Moradi
c46ee764ac Update README.md 2021-02-05 11:47:17 +03:30
Aria Moradi
7aada85f76 Update README.md 2021-02-05 11:46:29 +03:30
Aria Moradi
145cbe3e4f Update README.md 2021-02-05 11:45:56 +03:30
Aria Moradi
cb8dd8259d Update README.md 2021-02-05 11:44:24 +03:30
Aria Moradi
b8e721fd27 Update README.md 2021-02-05 01:48:59 +03:30
Aria Moradi
7917b5384c Update README.md 2021-02-05 01:17:03 +03:30
Aria Moradi
087b7554bf cleanup 2021-02-05 01:09:11 +03:30
Aria Moradi
fb5f851a2a Merge branch 'master' of github.com:AriaMoradi/Tachidesk 2021-02-05 00:57:16 +03:30
Aria Moradi
7ac51f8c2a Update README.md 2021-02-05 00:50:56 +03:30
Aria Moradi
e5e40a986c Update README.md 2021-02-05 00:46:46 +03:30
Aria Moradi
7a27436868 now done with lfs track 2021-02-05 00:20:25 +03:30
571 changed files with 38607 additions and 22521 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

35
.gitattributes vendored
View File

@@ -1,6 +1,31 @@
#
# https://help.github.com/articles/dealing-with-line-endings/
#
# These are explicitly windows files and should use crlf
*.bat text eol=crlf
* text=auto
* text eol=lf
# Windows forced line-endings
/.idea/* text eol=crlf
*.bat text eol=crlf
*.ps1 text eol=crlf
# Gradle wrapper
*.jar binary
# Binary files types
*.webp binary
*.png binary
*.jpg binary
*.jpeg binary
*.gif binary
*.ico binary
*.gz binary
*.zip binary
*.7z binary
*.ttf binary
*.eot binary
*.woff binary
*.pyc binary
*.swp binary
*.pdf binary
*.exe binary
*.avif binary
*.heif binary
*.jxl binary

44
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@@ -0,0 +1,44 @@
---
name: "🐞 Bug report"
title: "[Bug] <short description>"
about: "Report a bug"
labels: "bug"
---
**PLEASE READ THIS**
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 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
Note that the issue will be automatically closed if you do not fill out the title or requested information.
**DELETE THIS SECTION IF YOU HAVE READ AND ACKNOWLEDGED IT**
---
## Device information
- 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)
- Client Operating System: <usually the same as above Server Operating System>
- Client Web Browser: (Example: Google Chrome 89.0.4389.82)
## Steps to reproduce
1. First Step
2. Second Step
### Expected behavior
Describe what should have happened. Remove this line after you are done.
### Actual behavior
Describe what happens instead. Remove this line after you are done.
## Other details
Describe additional details If necessary. Remove this line after you are done.

1
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@@ -0,0 +1 @@
blank_issues_enabled: false

View File

@@ -0,0 +1,29 @@
---
name: "🌟 Feature request"
title: "[Feature Request] <short description>"
about: "Suggest a feature to improve the project"
labels: "enhancement"
---
**PLEASE READ THIS**
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 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
Note that the issue will be automatically closed if you do not fill out the title or requested information.
**DELETE THIS SECTION IF YOU HAVE READ AND ACKNOWLEDGED IT**
---
## What feature should be added to 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
Explain why this should be added. Remove this line after you are done.

View File

@@ -1,25 +0,0 @@
#!/bin/bash
git lfs install
git lfs track "*.zip"
cp ../master/repo/* .
new_jar_build=$(ls *.jar| tail -1)
echo "last jar build file name: $new_jar_build"
new_win32_build=$(ls *.zip| tail -1)
echo "last win32 build file name: $new_win32_build"
cp -f $new_jar_build Tachidesk-latest.jar
cp -f $new_win32_build Tachidesk-latest-win32.zip
git config --global user.email "github-actions[bot]@users.noreply.github.com"
git config --global user.name "github-actions[bot]"
git status
if [ -n "$(git status --porcelain)" ]; then
git add .
git commit -m "Update repo"
git push
else
echo "No changes to commit"
fi

View File

@@ -1,14 +0,0 @@
#!/bin/bash
# Get last commit message
last_commit_log=$(git log -1 --pretty=format:"%s")
echo "last commit log: $last_commit_log"
filter_count=$(echo "$last_commit_log" | grep -e '\[RELEASE CI\]' -e '\[CI RELEASE\]' | wc -c)
echo "count is: $filter_count"
if [ "$filter_count" -gt 0 ]; then
mkdir -p repo/
cp server/build/Tachidesk-*.jar repo/
cp server/build/Tachidesk-*.zip repo/
fi

View File

@@ -1,84 +0,0 @@
name: CI
on:
push:
branches:
- master
pull_request:
jobs:
check_wrapper:
name: Validate Gradle Wrapper
runs-on: ubuntu-latest
steps:
- name: Clone repo
uses: actions/checkout@v2
- name: Validate Gradle Wrapper
uses: gradle/wrapper-validation-action@v1
build:
name: Build FatJar
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.5.0
with:
access_token: ${{ github.token }}
- name: Checkout master branch
uses: actions/checkout@v2
with:
ref: master
path: master
fetch-depth: 0
- name: Set up JDK 1.8
uses: actions/setup-java@v1
with:
java-version: 1.8
- name: Copy CI gradle.properties
run: |
cd master
mkdir -p ~/.gradle
cp .github/runner-files/ci-gradle.properties ~/.gradle/gradle.properties
- name: Download and process android.jar
if: github.event_name == 'push' && github.repository == 'AriaMoradi/Tachidesk'
run: |
cd master
./scripts/getAndroid.sh
- name: Build Jar and launch4j
uses: eskatos/gradle-command-action@v1
with:
build-root-directory: master
wrapper-directory: master
arguments: :server:windowsPackage --stacktrace
wrapper-cache-enabled: true
dependencies-cache-enabled: true
configuration-cache-enabled: true
- name: Create repo artifacts
if: github.event_name == 'push' && github.repository == 'AriaMoradi/Tachidesk'
run: |
cd master
./.github/scripts/create-repo.sh
- name: Checkout repo branch
if: github.event_name == 'push' && github.repository == 'AriaMoradi/Tachidesk'
uses: actions/checkout@v2
with:
ref: repo
path: repo
- name: Deploy repo
if: github.event_name == 'push' && github.repository == 'AriaMoradi/Tachidesk'
run: |
cd repo
../master/.github/scripts/commit-repo.sh

View File

@@ -0,0 +1,52 @@
name: CI Pull Request
on:
pull_request:
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@v4
- name: Validate Gradle Wrapper
uses: gradle/wrapper-validation-action@v1
build:
name: Build pull request
needs: check_wrapper
runs-on: ubuntu-latest
steps:
- name: Checkout pull request
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@v4
with:
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: Build Jar
uses: gradle/gradle-build-action@v2
with:
build-root-directory: master
arguments: ktlintCheck :server:shadowJar --stacktrace

202
.github/workflows/build_push.yml vendored Normal file
View File

@@ -0,0 +1,202 @@
name: CI build
on:
push:
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@v3
- name: Validate Gradle Wrapper
uses: gradle/wrapper-validation-action@v1
build:
name: Build Jar
needs: check_wrapper
runs-on: ubuntu-latest
steps:
- name: Checkout master branch
uses: actions/checkout@v4
with:
ref: master
path: master
fetch-depth: 0
- name: Set up JDK 1.8
uses: actions/setup-java@v4
with:
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: Build Jar
uses: gradle/gradle-build-action@v2
env:
ProductBuildType: "Preview"
with:
build-root-directory: master
arguments: :server:shadowJar --stacktrace
- 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 release
genTag=$(ls *.jar | sed -e's/Suwayomi-Server-\|.jar//g')
echo "$genTag"
echo "value=$genTag" >> $GITHUB_OUTPUT
- name: Create Tag
run: |
TAG="${{ steps.GenTagName.outputs.value }}"
echo "tag: $TAG"
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.name "github-actions[bot]"
git commit -m "Updated to $TAG"
git push origin main
git tag $TAG
git push origin $TAG
- name: Upload Preview Release
uses: softprops/action-gh-release@v1
with:
token: ${{ secrets.DEPLOY_PREVIEW_TOKEN }}
repository: "Suwayomi/Suwayomi-Server-preview"
tag_name: ${{ steps.GenTagName.outputs.value }}
files: release/*

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

48
.github/workflows/issue_moderator.yml vendored Normal file
View File

@@ -0,0 +1,48 @@
name: Issue moderator
on:
issues:
types: [opened, edited, reopened]
issue_comment:
types: [created]
jobs:
autoclose:
runs-on: ubuntu-latest
steps:
- name: Moderate issues
uses: tachiyomiorg/issue-moderator-action@v1
with:
repo-token: ${{ github.token }}
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>.*",
"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.*",
"message": "The acknowledgment section was not removed"
},
{
"type": "body",
"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"
},
{
"type": "body",
"regex": ".*Remove this line after you are done.*",
"message": "The lines requesting to be removed were not removed."
}
]

174
.github/workflows/publish.yml vendored Normal file
View File

@@ -0,0 +1,174 @@
name: CI Publish
on:
workflow_dispatch:
push:
tags:
- "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@v4
- name: Validate Gradle Wrapper
uses: gradle/wrapper-validation-action@v1
build:
name: Build Jar
needs: check_wrapper
runs-on: ubuntu-latest
steps:
- name: Checkout ${{ github.ref }}
uses: actions/checkout@v4
with:
ref: ${{ github.ref }}
path: master
fetch-depth: 0
- name: Set up JDK 1.8
uses: actions/setup-java@v4
with:
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: Build and copy webUI, Build Jar
uses: gradle/gradle-build-action@v2
env:
ProductBuildType: "Stable"
with:
build-root-directory: master
arguments: :server:downloadWebUI :server:shadowJar --stacktrace
- name: Upload Jar
uses: actions/upload-artifact@v4
with:
name: jar
path: master/server/build/*.jar
if-no-files-found: error
- name: Upload icons
uses: actions/upload-artifact@v4
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@v4
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@v4
with:
name: jar
path: server/build
- name: Download icons
uses: actions/download-artifact@v4
with:
name: icon
path: server/src/main/resources/icon
- name: Download scripts.tar.gz
uses: actions/download-artifact@v4
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 }} files
uses: actions/upload-artifact@v4
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@v4
with:
name: jar
path: release
- uses: actions/download-artifact@v4
with:
name: debian-all
path: release
- uses: actions/download-artifact@v4
with:
name: linux-assets
path: release
- uses: actions/download-artifact@v4
with:
name: linux-x64
path: release
- uses: actions/download-artifact@v4
with:
name: macOS-x64
path: release
- uses: actions/download-artifact@v4
with:
name: macOS-arm64
path: release
- uses: actions/download-artifact@v4
with:
name: windows-x64
path: release
- uses: actions/download-artifact@v4
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.DEPLOY_RELEASE_TOKEN }}
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 }}

17
.gitignore vendored
View File

@@ -1,8 +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
server/src/main/resources/react
# WebUI is either to be downloaded on-demand or is a dynamic build asset
server/src/main/resources/WebUI.zip
# bundling stage downlaoded assets
scripts/OpenJDK*
scripts/zulu*
scripts/electron-*
scripts/rcedit-*

View File

@@ -1,4 +0,0 @@
dependencies {
// Config API
// implementation("com.typesafe:config:1.4.0")
}

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

@@ -0,0 +1,20 @@
package xyz.nulldev.ts.config
/*
* 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/. */
import net.harawata.appdirs.AppDirsFactory
const val CONFIG_PREFIX = "suwayomi.tachidesk.config"
val ApplicationRootDir: String
get(): String {
return System.getProperty(
"$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

@@ -1,8 +1,21 @@
package xyz.nulldev.ts.config
/*
* 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/. */
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
@@ -10,58 +23,72 @@ import java.io.File
* Manages app config.
*/
open class ConfigManager {
private val generatedModules
= mutableMapOf<Class<out ConfigModule>, ConfigModule>()
val config by lazy { loadConfigs() }
val logger = KotlinLogging.logger {}
private val generatedModules = mutableMapOf<Class<out ConfigModule>, ConfigModule>()
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
open val configFolder: String
get() = System.getProperty("compat-configdirs") ?: "tachiserver-data/config"
val logger = KotlinLogging.logger {}
private val mutex = Mutex()
/**
* Get a config module
*/
inline fun <reified T : ConfigModule> module(): T
= loadedModules[T::class.java] as T
inline fun <reified T : ConfigModule> module(): T = loadedModules[T::class.java] as T
/**
* Get a config module (Java API)
*/
fun <T : ConfigModule> module(type: Class<T>): T
= loadedModules[type] as T
@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 {
val configs = mutableListOf<Config>()
// Load reference configs
val compatConfig = ConfigFactory.parseResources("compat-reference.conf")
val serverConfig = ConfigFactory.parseResources("server-reference.conf")
val baseConfig =
ConfigFactory.parseMap(
mapOf(
// override AndroidCompat's rootDir
"androidcompat.rootDir" to "$ApplicationRootDir/android-compat",
),
)
//Load reference config
configs += ConfigFactory.parseResources("reference.conf")
// Load user config
val userConfig = getUserConfig()
//Load custom configs from dir
File(configFolder).listFiles()?.map {
ConfigFactory.parseFile(it)
}?.filterNotNull()?.forEach {
configs += it.withFallback(configs.last())
}
val config =
ConfigFactory.empty()
.withFallback(baseConfig)
.withFallback(userConfig)
.withFallback(compatConfig)
.withFallback(serverConfig)
.resolve()
val config = configs.last().resolve()
logger.debug {
"Loaded config:\n" + config.root().render(ConfigRenderOptions.concise().setFormatted(true))
// set log level early
if (debugLogsEnabled(config)) {
setLogLevelFor(BASE_LOGGER_NAME, Level.DEBUG)
}
return config
}
fun registerModule(module: ConfigModule) {
generatedModules.put(module.javaClass, module)
generatedModules[module.javaClass] = module
}
fun registerModules(vararg modules: ConfigModule) {
@@ -69,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

@@ -1,8 +1,57 @@
package xyz.nulldev.ts.config
/*
* 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/. */
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)
@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)
}
/** 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(
"$CONFIG_PREFIX.$moduleName.${property.name}",
if (T::class.simpleName == "List") {
ConfigValueFactory.fromAnyRef(configValue).render()
} else {
configValue.toString()
},
)
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 // covers String
} as T
}
}

View File

@@ -0,0 +1,96 @@
package xyz.nulldev.ts.config
/*
* 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/. */
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
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
}
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

@@ -1,35 +0,0 @@
package xyz.nulldev.ts.config
import com.typesafe.config.Config
import java.io.File
class ServerConfig(config: Config) : ConfigModule(config) {
val ip = config.getString("ip")
val port = config.getInt("port")
val allowConfigChanges = config.getBoolean("allowConfigChanges")
val enableWebUi = config.getBoolean("enableWebUi")
val useOldWebUi = config.getBoolean("useOldWebUi")
val prettyPrintApi = config.getBoolean("prettyPrintApi")
// TODO Apply to operation IDs
val disabledApiEndpoints = config.getStringList("disabledApiEndpoints").map(String::toLowerCase)
val enabledApiEndpoints = config.getStringList("enabledApiEndpoints").map(String::toLowerCase)
val httpInitializedPrintMessage = config.getString("httpInitializedPrintMessage")
val useExternalStaticFiles = config.getBoolean("useExternalStaticFiles")
val externalStaticFilesFolder = config.getString("externalStaticFilesFolder")
val rootDir = registerFile(config.getString("rootDir"))
val patchesDir = registerFile(config.getString("patchesDir"))
fun registerFile(file: String): File {
return File(file).apply {
mkdirs()
}
}
companion object {
fun register(config: Config)
= ServerConfig(config.getConfig("ts.server"))
}
}

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 +0,0 @@
xyz.nulldev.ts.api.v2.java.impl.ServerAPIImpl

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

File diff suppressed because one or more lines are too long

View File

@@ -1,22 +0,0 @@
[
{
"label": "Sync",
"icon": "import_export",
"type": "nested",
"prefs": []
},
{
"label": "Server",
"icon": "dns",
"type": "nested",
"prefs": [
{
"label": "Password authentication",
"type": "text-password",
"default": "",
"key": "pref_ts_server_password",
"hint": "Enter a password"
}
]
}
]

View File

@@ -1,87 +0,0 @@
# Server ip and port bindings
ts.server.ip = 0.0.0.0
ts.server.port = 4567
# 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
# Storage dir for the emulated Android app
android.files.rootDir = ${ts.server.rootDir}/android-compat/appdata
# External storage dir for the emulated Android app's
android.files.externalStorageDir = ${ts.server.rootDir}/android-compat/extappdata
# Internal Android directories
android.files.dataDir = ${android.files.rootDir}/data
android.files.filesDir = ${android.files.rootDir}/files
android.files.cacheDir = ${android.files.rootDir}/cache
android.files.codeCacheDir = ${android.files.rootDir}/code_cache
android.files.noBackupFilesDir = ${android.files.rootDir}/no_backup
android.files.databasesDir = ${android.files.rootDir}/databases
android.files.prefsDir = ${android.files.rootDir}/shared_prefs
# External Android directories
android.files.externalFilesDirs = [${android.files.externalStorageDir}/files]
android.files.obbDirs = [${android.files.externalStorageDir}/obb]
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
# Emulated Android app package name
android.app.packageName = eu.kanade.tachiyomi
# Debug mode for the emulated Android app
android.app.debug = true
# 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 = ""

View File

@@ -1,72 +1,38 @@
plugins {
application
}
repositories {
mavenCentral()
jcenter()
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 {
// Shared
implementation(libs.bundles.shared)
testImplementation(libs.bundles.sharedTest)
// Android stub library
// compileOnly( fileTree(File(rootProject.rootDir, "libs/android"), include: "*.jar")
implementation(fileTree("lib/"))
implementation(fileTree("${rootProject.rootDir}/server/lib/dex2jar/"))
// Android JAR libs
// compileOnly( fileTree(dir: new File(rootProject.rootDir, "libs/other"), include: "*.jar")
// JSON
compileOnly( "com.google.code.gson:gson:2.8.6")
// Javassist
compileOnly( "org.javassist:javassist:3.27.0-GA")
// Coroutines
val kotlinx_coroutines_version = "1.4.2"
compileOnly( "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinx_coroutines_version")
compileOnly( "org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:$kotlinx_coroutines_version")
implementation(libs.android.stubs)
// XML
compileOnly( group= "xmlpull", name= "xmlpull", version= "1.1.3.1")
compileOnly(libs.xmlpull)
// Config API
implementation( project(":AndroidCompat:Config"))
// dex2jar
// compileOnly( "dex2jar:dex-translator")
// APK parser
compileOnly("net.dongliu:apk-parser:2.6.10")
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)
// compileOnly("io.reactivex:rxjava:1.3.8")
// substitute for duktape-android
implementation(libs.bundles.rhino)
// Kotlin wrapper around Java Preferences, makes certain things easier
implementation(libs.bundles.settings)
// Android version of SimpleDateFormat
implementation(libs.icu4j)
// 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

@@ -0,0 +1,106 @@
# 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/.
# This is a windows only PowerShell script to create android.jar stubs
# foolproof against running from AndroidCompat dir instead of running from project root
if ($(Split-Path -Path (Get-Location) -Leaf) -eq "AndroidCompat" ) {
Set-Location ..
}
Write-Output "Getting required Android.jar..."
Remove-Item -Recurse -Force "tmp" -ErrorAction SilentlyContinue | Out-Null
New-Item -ItemType Directory -Force -Path "tmp" | Out-Null
$androidEncoded = (Invoke-WebRequest -Uri "https://android.googlesource.com/platform/prebuilts/sdk/+/6cd31be5e4e25901aadf838120d71a79b46d9add/30/public/android.jar?format=TEXT" -UseBasicParsing).content
$android_jar = (Get-Location).Path + "\tmp\android.jar"
[IO.File]::WriteAllBytes($android_jar, [Convert]::FromBase64String($androidEncoded))
# We need to remove any stub classes that we have implementations for
Write-Output "Patching JAR..."
function Remove-Files-Zip($zipfile, $paths)
{
[Reflection.Assembly]::LoadWithPartialName('System.IO.Compression') | Out-Null
$stream = New-Object IO.FileStream($zipfile, [IO.FileMode]::Open)
$mode = [IO.Compression.ZipArchiveMode]::Update
$zip = New-Object IO.Compression.ZipArchive($stream, $mode)
if ($paths.getType().Name -eq "Object[]")
{
$paths | ForEach-Object {
$path = $_
($zip.Entries | Where-Object { $_.FullName -like $path }) | ForEach-Object { Write-Output "Deleting: $($_.FullName)"; $_.Delete() }
}
}
else
{
($zip.Entries | Where-Object { $_.FullName -like $paths }) | ForEach-Object { Write-Output "Deleting: $($_.FullName)"; $_.Delete() }
}
$zip.Dispose()
$stream.Close()
$stream.Dispose()
}
Write-Output "Removing org.json..."
Remove-Files-Zip $android_jar 'org/json/*'
Write-Output "Removing org.apache..."
Remove-Files-Zip $android_jar 'org/apache/*'
Write-Output "Removing org.w3c..."
Remove-Files-Zip $android_jar 'org/w3c/*'
Write-Output "Removing org.xml..."
Remove-Files-Zip $android_jar 'org/xml/*'
Write-Output "Removing org.xmlpull..."
Remove-Files-Zip $android_jar 'org/xmlpull/*'
Write-Output "Removing junit..."
Remove-Files-Zip $android_jar 'junit/*'
Write-Output "Removing javax..."
Remove-Files-Zip $android_jar 'javax/*'
Write-Output "Removing java..."
Remove-Files-Zip $android_jar 'java/*'
Write-Output "Removing overriden classes..."
Remove-Files-Zip $android_jar 'android/app/Application.class'
Remove-Files-Zip $android_jar 'android/app/Service.class'
Remove-Files-Zip $android_jar 'android/net/Uri.class'
Remove-Files-Zip $android_jar 'android/net/Uri$Builder.class'
Remove-Files-Zip $android_jar 'android/os/Environment.class'
Remove-Files-Zip $android_jar 'android/text/format/Formatter.class'
Remove-Files-Zip $android_jar 'android/text/Html.class'
function Dedupe($path)
{
Push-Location $path
$classes = Get-ChildItem . *.* -Recurse | Where-Object { !$_.PSIsContainer }
$classes | ForEach-Object {
"Processing class: $($_.FullName)"
Remove-Files-Zip $android_jar ("$($_.Name).class","$($_.Name)$*.class","$($_.Name)Kt.class","$($_.Name)Kt$*.class") | Out-Null
}
Pop-Location
}
Dedupe "AndroidCompat/src/main/java"
Dedupe "server/src/main/kotlin"
Write-Output "Copying Android.jar to library folder..."
Move-Item -Force $android_jar "AndroidCompat/lib/android.jar"
Write-Output "Cleaning up..."
Remove-Item -Recurse -Force "tmp"
Write-Output "Done!"

View File

@@ -1,12 +1,38 @@
#!/usr/bin/env 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/.
# This is a bash script to create android.jar stubs
for dep in "curl" "base64" "zip"
do
which $dep >/dev/null 2>&1 || { echo >&2 "Error: This script needs $dep installed."; abort=yes; }
done
if [ "$abort" = yes ]; then
echo "Some of the dependencies didn't exist. Aborting."
exit 1
fi
# foolproof against running from AndroidCompat dir instead of running from project root
if [ "$(basename "$(pwd)")" = "AndroidCompat" ]; then
cd ..
fi
echo "Getting required Android.jar..."
rm -rf "tmp"
mkdir -p "tmp"
pushd "tmp"
curl "https://android.googlesource.com/platform/prebuilts/sdk/+/3b8a524d25fa6c3d795afb1eece3f24870c60988/27/public/android.jar?format=TEXT" | base64 --decode > android.jar
curl "https://android.googlesource.com/platform/prebuilts/sdk/+/6cd31be5e4e25901aadf838120d71a79b46d9add/30/public/android.jar?format=TEXT" | base64 --decode > android.jar
# We need to remove any stub classes that we might use
# We need to remove any stub classes that we have implementations for
echo "Patching JAR..."
echo "Removing org.json..."
@@ -33,7 +59,7 @@ zip --delete android.jar javax/*
echo "Removing java..."
zip --delete android.jar java/*
echo "Removing overriden classes..."
echo "Removing overridden classes..."
zip --delete android.jar android/app/Application.class
zip --delete android.jar android/app/Service.class
zip --delete android.jar android/net/Uri.class
@@ -42,12 +68,12 @@ zip --delete android.jar android/os/Environment.class
zip --delete android.jar android/text/format/Formatter.class
zip --delete android.jar android/text/Html.class
# Dedup overriden Android classes
# Dedup overridden Android classes
ABS_JAR="$(realpath android.jar)"
function dedup() {
pushd "$1"
CLASSES="$(find * -type f)"
echo "$CLASSES" | while read class
CLASSES="$(find ./* -type f)"
echo "$CLASSES" | while read -r class
do
NAME="${class%.*}"
echo "Processing class: $NAME"
@@ -56,13 +82,10 @@ function dedup() {
popd
}
pushd ..
popd
dedup AndroidCompat/src/main/java
dedup server/src/main/java
dedup server/src/main/kotlin
popd
popd
echo "Copying Android.jar to library folder..."
mv tmp/android.jar AndroidCompat/lib

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

@@ -1,291 +0,0 @@
/*
* Copyright (C) 2012 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.
*/
package android.support.v4.content;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.StatFs;
import android.support.v4.os.EnvironmentCompat;
import java.io.File;
/**
* Helper for accessing features in {@link android.content.Context}
* introduced after API level 4 in a backwards compatible fashion.
*/
public class ContextCompat {
/**
* Start a set of activities as a synthesized task stack, if able.
*
* <p>In API level 11 (Android 3.0/Honeycomb) the recommended conventions for
* app navigation using the back key changed. The back key's behavior is local
* to the current task and does not capture navigation across different tasks.
* Navigating across tasks and easily reaching the previous task is accomplished
* through the "recents" UI, accessible through the software-provided Recents key
* on the navigation or system bar. On devices with the older hardware button configuration
* the recents UI can be accessed with a long press on the Home key.</p>
*
* <p>When crossing from one task stack to another post-Android 3.0,
* the application should synthesize a back stack/history for the new task so that
* the user may navigate out of the new task and back to the Launcher by repeated
* presses of the back key. Back key presses should not navigate across task stacks.</p>
*
* <p>startActivities provides a mechanism for constructing a synthetic task stack of
* multiple activities. If the underlying API is not available on the system this method
* will return false.</p>
*
* @param context Start activities using this activity as the starting context
* @param intents Array of intents defining the activities that will be started. The element
* length-1 will correspond to the top activity on the resulting task stack.
* @return true if the underlying API was available and the call was successful, false otherwise
*/
public static boolean startActivities(Context context, Intent[] intents) {
return startActivities(context, intents, null);
}
/**
* Start a set of activities as a synthesized task stack, if able.
*
* <p>In API level 11 (Android 3.0/Honeycomb) the recommended conventions for
* app navigation using the back key changed. The back key's behavior is local
* to the current task and does not capture navigation across different tasks.
* Navigating across tasks and easily reaching the previous task is accomplished
* through the "recents" UI, accessible through the software-provided Recents key
* on the navigation or system bar. On devices with the older hardware button configuration
* the recents UI can be accessed with a long press on the Home key.</p>
*
* <p>When crossing from one task stack to another post-Android 3.0,
* the application should synthesize a back stack/history for the new task so that
* the user may navigate out of the new task and back to the Launcher by repeated
* presses of the back key. Back key presses should not navigate across task stacks.</p>
*
* <p>startActivities provides a mechanism for constructing a synthetic task stack of
* multiple activities. If the underlying API is not available on the system this method
* will return false.</p>
*
* @param context Start activities using this activity as the starting context
* @param intents Array of intents defining the activities that will be started. The element
* length-1 will correspond to the top activity on the resulting task stack.
* @param options Additional options for how the Activity should be started.
* See {@link android.content.Context#startActivity(Intent, Bundle)
* @return true if the underlying API was available and the call was successful, false otherwise
*/
public static boolean startActivities(Context context, Intent[] intents,
Bundle options) {
context.startActivities(intents, options);
return true;
}
/**
* Returns absolute paths to application-specific directories on all
* external storage devices where the application's OBB files (if there are
* any) can be found. Note if the application does not have any OBB files,
* these directories may not exist.
* <p>
* This is like {@link Context#getFilesDir()} in that these files will be
* deleted when the application is uninstalled, however there are some
* important differences:
* <ul>
* <li>External files are not always available: they will disappear if the
* user mounts the external storage on a computer or removes it.
* <li>There is no security enforced with these files.
* </ul>
* <p>
* External storage devices returned here are considered a permanent part of
* the device, including both emulated external storage and physical media
* slots, such as SD cards in a battery compartment. The returned paths do
* not include transient devices, such as USB flash drives.
* <p>
* An application may store data on any or all of the returned devices. For
* example, an app may choose to store large files on the device with the
* most available space, as measured by {@link StatFs}.
* <p>
* Starting in {@link android.os.Build.VERSION_CODES#KITKAT}, no permissions
* are required to write to the returned paths; they're always accessible to
* the calling app. Before then,
* {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} is required to
* write. Write access outside of these paths on secondary external storage
* devices is not available. To request external storage access in a
* backwards compatible way, consider using {@code android:maxSdkVersion}
* like this:
*
* <pre class="prettyprint">&lt;uses-permission
* android:name="android.permission.WRITE_EXTERNAL_STORAGE"
* android:maxSdkVersion="18" /&gt;</pre>
* <p>
* The first path returned is the same as {@link Context#getObbDir()}.
* Returned paths may be {@code null} if a storage device is unavailable.
*
* @see Context#getObbDir()
* @see EnvironmentCompat#getStorageState(File)
*/
public static File[] getObbDirs(Context context) {
return context.getObbDirs();
}
/**
* Returns absolute paths to application-specific directories on all
* external storage devices where the application can place persistent files
* it owns. These files are internal to the application, and not typically
* visible to the user as media.
* <p>
* This is like {@link Context#getFilesDir()} in that these files will be
* deleted when the application is uninstalled, however there are some
* important differences:
* <ul>
* <li>External files are not always available: they will disappear if the
* user mounts the external storage on a computer or removes it.
* <li>There is no security enforced with these files.
* </ul>
* <p>
* External storage devices returned here are considered a permanent part of
* the device, including both emulated external storage and physical media
* slots, such as SD cards in a battery compartment. The returned paths do
* not include transient devices, such as USB flash drives.
* <p>
* An application may store data on any or all of the returned devices. For
* example, an app may choose to store large files on the device with the
* most available space, as measured by {@link StatFs}.
* <p>
* Starting in {@link android.os.Build.VERSION_CODES#KITKAT}, no permissions
* are required to write to the returned paths; they're always accessible to
* the calling app. Before then,
* {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} is required to
* write. Write access outside of these paths on secondary external storage
* devices is not available. To request external storage access in a
* backwards compatible way, consider using {@code android:maxSdkVersion}
* like this:
*
* <pre class="prettyprint">&lt;uses-permission
* android:name="android.permission.WRITE_EXTERNAL_STORAGE"
* android:maxSdkVersion="18" /&gt;</pre>
* <p>
* The first path returned is the same as
* {@link Context#getExternalFilesDir(String)}. Returned paths may be
* {@code null} if a storage device is unavailable.
*
* @see Context#getExternalFilesDir(String)
* @see EnvironmentCompat#getStorageState(File)
*/
public static File[] getExternalFilesDirs(Context context, String type) {
return context.getExternalFilesDirs(type);
}
/**
* Returns absolute paths to application-specific directories on all
* external storage devices where the application can place cache files it
* owns. These files are internal to the application, and not typically
* visible to the user as media.
* <p>
* This is like {@link Context#getCacheDir()} in that these files will be
* deleted when the application is uninstalled, however there are some
* important differences:
* <ul>
* <li>External files are not always available: they will disappear if the
* user mounts the external storage on a computer or removes it.
* <li>There is no security enforced with these files.
* </ul>
* <p>
* External storage devices returned here are considered a permanent part of
* the device, including both emulated external storage and physical media
* slots, such as SD cards in a battery compartment. The returned paths do
* not include transient devices, such as USB flash drives.
* <p>
* An application may store data on any or all of the returned devices. For
* example, an app may choose to store large files on the device with the
* most available space, as measured by {@link StatFs}.
* <p>
* Starting in {@link android.os.Build.VERSION_CODES#KITKAT}, no permissions
* are required to write to the returned paths; they're always accessible to
* the calling app. Before then,
* {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} is required to
* write. Write access outside of these paths on secondary external storage
* devices is not available. To request external storage access in a
* backwards compatible way, consider using {@code android:maxSdkVersion}
* like this:
*
* <pre class="prettyprint">&lt;uses-permission
* android:name="android.permission.WRITE_EXTERNAL_STORAGE"
* android:maxSdkVersion="18" /&gt;</pre>
* <p>
* The first path returned is the same as
* {@link Context#getExternalCacheDir()}. Returned paths may be {@code null}
* if a storage device is unavailable.
*
* @see Context#getExternalCacheDir()
* @see EnvironmentCompat#getStorageState(File)
*/
public static File[] getExternalCacheDirs(Context context) {
return context.getExternalCacheDirs();
}
/**
* Return a drawable object associated with a particular resource ID.
* <p>
* Starting in {@link android.os.Build.VERSION_CODES#LOLLIPOP}, the returned
* drawable will be styled for the specified Context's theme.
*
* @param id The desired resource identifier, as generated by the aapt tool.
* This integer encodes the package, type, and resource entry.
* The value 0 is an invalid identifier.
* @return Drawable An object that can be used to draw this resource.
*/
public static final Drawable getDrawable(Context context, int id) {
return context.getDrawable(id);
}
/**
* Returns the absolute path to the directory on the filesystem similar to
* {@link Context#getFilesDir()}. The difference is that files placed under this
* directory will be excluded from automatic backup to remote storage on
* devices running {@link android.os.Build.VERSION_CODES#LOLLIPOP} or later. See
* {@link android.app.backup.BackupAgent BackupAgent} for a full discussion
* of the automatic backup mechanism in Android.
*
* <p>No permissions are required to read or write to the returned path, since this
* path is internal storage.
*
* @return The path of the directory holding application files that will not be
* automatically backed up to remote storage.
*
* @see android.content.Context.getFilesDir
*/
public final File getNoBackupFilesDir(Context context) {
return context.getNoBackupFilesDir();
}
/**
* Returns the absolute path to the application specific cache directory on
* the filesystem designed for storing cached code. On devices running
* {@link android.os.Build.VERSION_CODES#LOLLIPOP} or later, the system will delete
* any files stored in this location both when your specific application is
* upgraded, and when the entire platform is upgraded.
* <p>
* This location is optimal for storing compiled or optimized code generated
* by your application at runtime.
* <p>
* Apps require no extra permissions to read or write to the returned path,
* since this path lives in their private storage.
*
* @return The path of the directory holding application code cache files.
*/
public final File getCodeCacheDir(Context context) {
return context.getCodeCacheDir();
}
}

View File

@@ -1,53 +0,0 @@
/*
* Copyright (C) 2011 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.
*/
package android.support.v4.os;
import android.os.Environment;
import java.io.File;
/**
* Helper for accessing features in {@link Environment} introduced after API
* level 4 in a backwards compatible fashion.
*/
public class EnvironmentCompat {
/**
* Unknown storage state, such as when a path isn't backed by known storage
* media.
*
* @see #getStorageState(File)
*/
public static final String MEDIA_UNKNOWN = "unknown";
/**
* Returns the current state of the storage device that provides the given
* path.
*
* @return one of {@link #MEDIA_UNKNOWN}, {@link Environment#MEDIA_REMOVED},
* {@link Environment#MEDIA_UNMOUNTED},
* {@link Environment#MEDIA_CHECKING},
* {@link Environment#MEDIA_NOFS},
* {@link Environment#MEDIA_MOUNTED},
* {@link Environment#MEDIA_MOUNTED_READ_ONLY},
* {@link Environment#MEDIA_SHARED},
* {@link Environment#MEDIA_BAD_REMOVAL}, or
* {@link Environment#MEDIA_UNMOUNTABLE}.
*/
public static String getStorageState(File path) {
return Environment.getStorageState(path);
}
}

View File

@@ -1,193 +0,0 @@
/*
* 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.
*/
package android.support.v7.preference;
import android.support.annotation.Nullable;
import java.util.Set;
/**
* A data store interface to be implemented and provided to the Preferences framework. This can be
* used to replace the default {@link android.content.SharedPreferences}, if needed.
*
* <p>In most cases you want to use {@link android.content.SharedPreferences} as it is automatically
* backed up and migrated to new devices. However, providing custom data store to preferences can be
* useful if your app stores its preferences in a local db, cloud or they are device specific like
* "Developer settings". It might be also useful when you want to use the preferences UI but
* the data are not supposed to be stored at all because they are valid per session only.
*
* <p>Once a put method is called it is full responsibility of the data store implementation to
* safely store the given values. Time expensive operations need to be done in the background to
* prevent from blocking the UI. You also need to have a plan on how to serialize the data in case
* the activity holding this object gets destroyed.
*
* <p>By default, all "put" methods throw {@link UnsupportedOperationException}.
*/
public abstract class PreferenceDataStore {
/**
* Sets a {@link String} value to the data store.
*
* <p>Once the value is set the data store is responsible for holding it.
*
* @param key the name of the preference to modify
* @param value the new value for the preference
* @see #getString(String, String)
*/
public void putString(String key, @Nullable String value) {
throw new UnsupportedOperationException("Not implemented on this data store");
}
/**
* Sets a set of Strings to the data store.
*
* <p>Once the value is set the data store is responsible for holding it.
*
* @param key the name of the preference to modify
* @param values the set of new values for the preference
* @see #getStringSet(String, Set<String>)
*/
public void putStringSet(String key, @Nullable Set<String> values) {
throw new UnsupportedOperationException("Not implemented on this data store");
}
/**
* Sets an {@link Integer} value to the data store.
*
* <p>Once the value is set the data store is responsible for holding it.
*
* @param key the name of the preference to modify
* @param value the new value for the preference
* @see #getInt(String, int)
*/
public void putInt(String key, int value) {
throw new UnsupportedOperationException("Not implemented on this data store");
}
/**
* Sets a {@link Long} value to the data store.
*
* <p>Once the value is set the data store is responsible for holding it.
*
* @param key the name of the preference to modify
* @param value the new value for the preference
* @see #getLong(String, long)
*/
public void putLong(String key, long value) {
throw new UnsupportedOperationException("Not implemented on this data store");
}
/**
* Sets a {@link Float} value to the data store.
*
* <p>Once the value is set the data store is responsible for holding it.
*
* @param key the name of the preference to modify
* @param value the new value for the preference
* @see #getFloat(String, float)
*/
public void putFloat(String key, float value) {
throw new UnsupportedOperationException("Not implemented on this data store");
}
/**
* Sets a {@link Boolean} value to the data store.
*
* <p>Once the value is set the data store is responsible for holding it.
*
* @param key the name of the preference to modify
* @param value the new value for the preference
* @see #getBoolean(String, boolean)
*/
public void putBoolean(String key, boolean value) {
throw new UnsupportedOperationException("Not implemented on this data store");
}
/**
* Retrieves a {@link String} value from the data store.
*
* @param key the name of the preference to retrieve
* @param defValue value to return if this preference does not exist in the storage
* @return the value from the data store or the default return value
* @see #putString(String, String)
*/
@Nullable
public String getString(String key, @Nullable String defValue) {
return defValue;
}
/**
* Retrieves a set of Strings from the data store.
*
* @param key the name of the preference to retrieve
* @param defValues values to return if this preference does not exist in the storage
* @return the values from the data store or the default return values
* @see #putStringSet(String, Set<String>)
*/
@Nullable
public Set<String> getStringSet(String key, @Nullable Set<String> defValues) {
return defValues;
}
/**
* Retrieves an {@link Integer} value from the data store.
*
* @param key the name of the preference to retrieve
* @param defValue value to return if this preference does not exist in the storage
* @return the value from the data store or the default return value
* @see #putInt(String, int)
*/
public int getInt(String key, int defValue) {
return defValue;
}
/**
* Retrieves a {@link Long} value from the data store.
*
* @param key the name of the preference to retrieve
* @param defValue value to return if this preference does not exist in the storage
* @return the value from the data store or the default return value
* @see #putLong(String, long)
*/
public long getLong(String key, long defValue) {
return defValue;
}
/**
* Retrieves a {@link Float} value from the data store.
*
* @param key the name of the preference to retrieve
* @param defValue value to return if this preference does not exist in the storage
* @return the value from the data store or the default return value
* @see #putFloat(String, float)
*/
public float getFloat(String key, float defValue) {
return defValue;
}
/**
* Retrieves a {@link Boolean} value from the data store.
*
* @param key the name of the preference to retrieve
* @param defValue value to return if this preference does not exist in the storage
* @return the value from the data store or the default return value
* @see #getBoolean(String, boolean)
*/
public boolean getBoolean(String key, boolean defValue) {
return defValue;
}
}

View File

@@ -1,4 +0,0 @@
package android.support.v7.preference;
public class PreferenceScreen {
}

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,40 @@
package android.widget;
/*
* 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/. */
public class EditText {
public EditText(android.content.Context context) { throw new RuntimeException("Stub!"); }
public EditText(android.content.Context context, android.util.AttributeSet attrs) { throw new RuntimeException("Stub!"); }
public EditText(android.content.Context context, android.util.AttributeSet attrs, int defStyleAttr) { throw new RuntimeException("Stub!"); }
public EditText(android.content.Context context, android.util.AttributeSet attrs, int defStyleAttr, int defStyleRes) { throw new RuntimeException("Stub!"); }
public boolean getFreezesText() { throw new RuntimeException("Stub!"); }
protected boolean getDefaultEditable() { throw new RuntimeException("Stub!"); }
protected android.text.method.MovementMethod getDefaultMovementMethod() { throw new RuntimeException("Stub!"); }
public android.text.Editable getText() { throw new RuntimeException("Stub!"); }
public void setText(java.lang.CharSequence text, android.widget.TextView.BufferType type) { throw new RuntimeException("Stub!"); }
public void setSelection(int start, int stop) { throw new RuntimeException("Stub!"); }
public void setSelection(int index) { throw new RuntimeException("Stub!"); }
public void selectAll() { throw new RuntimeException("Stub!"); }
public void extendSelection(int index) { throw new RuntimeException("Stub!"); }
public void setEllipsize(android.text.TextUtils.TruncateAt ellipsis) { throw new RuntimeException("Stub!"); }
public java.lang.CharSequence getAccessibilityClassName() { throw new RuntimeException("Stub!"); }
}

View File

@@ -0,0 +1,91 @@
package android.widget;
/*
* 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/. */
public class Toast {
public static final int LENGTH_LONG = 1;
public static final int LENGTH_SHORT = 0;
private CharSequence text;
private Toast(CharSequence text) {
this.text = text;
}
public Toast(android.content.Context context) {
throw new RuntimeException("Stub!");
}
public void show() {
System.out.printf("made a Toast: \"%s\"\n", text.toString());
}
public void cancel() {
throw new RuntimeException("Stub!");
}
public void setView(android.view.View view) {
throw new RuntimeException("Stub!");
}
public android.view.View getView() {
throw new RuntimeException("Stub!");
}
public void setDuration(int duration) {
throw new RuntimeException("Stub!");
}
public int getDuration() {
throw new RuntimeException("Stub!");
}
public void setMargin(float horizontalMargin, float verticalMargin) {
throw new RuntimeException("Stub!");
}
public float getHorizontalMargin() {
throw new RuntimeException("Stub!");
}
public float getVerticalMargin() {
throw new RuntimeException("Stub!");
}
public void setGravity(int gravity, int xOffset, int yOffset) {
throw new RuntimeException("Stub!");
}
public int getGravity() {
throw new RuntimeException("Stub!");
}
public int getXOffset() {
throw new RuntimeException("Stub!");
}
public int getYOffset() {
throw new RuntimeException("Stub!");
}
public static Toast makeText(android.content.Context context, java.lang.CharSequence text, int duration) {
return new Toast(text);
}
public static android.widget.Toast makeText(android.content.Context context, int resId, int duration) throws android.content.res.Resources.NotFoundException {
throw new RuntimeException("Stub!");
}
public void setText(int resId) {
throw new RuntimeException("Stub!");
}
public void setText(java.lang.CharSequence s) {
throw new RuntimeException("Stub!");
}
}

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

@@ -0,0 +1,18 @@
package androidx.preference;
/*
* 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/. */
import android.content.Context;
public class CheckBoxPreference extends TwoStatePreference {
// reference: https://android.googlesource.com/platform/frameworks/support/+/996971f962fcd554339a7cb2859cef9ca89dbcb7/preference/preference/src/main/java/androidx/preference/CheckBoxPreference.java
public CheckBoxPreference(Context context) {
super(context);
}
}

View File

@@ -0,0 +1,33 @@
package androidx.preference;
/*
* 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/. */
import android.content.Context;
public abstract class DialogPreference extends Preference {
private CharSequence dialogTitle;
private CharSequence dialogMessage;
public DialogPreference(Context context) { super(context); }
public CharSequence getDialogTitle() {
return dialogTitle;
}
public void setDialogTitle(CharSequence dialogTitle) {
this.dialogTitle = dialogTitle;
}
public CharSequence getDialogMessage() {
return dialogMessage;
}
public void setDialogMessage(CharSequence dialogMessage) {
this.dialogMessage = dialogMessage;
}
}

View File

@@ -0,0 +1,53 @@
package androidx.preference;
/*
* 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/. */
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.widget.EditText;
import com.fasterxml.jackson.annotation.JsonIgnore;
public class EditTextPreference extends DialogPreference {
// reference: https://android.googlesource.com/platform/frameworks/support/+/996971f962fcd554339a7cb2859cef9ca89dbcb7/preference/preference/src/main/java/androidx/preference/EditTextPreference.java
private String text;
@JsonIgnore
private OnBindEditTextListener onBindEditTextListener;
public EditTextPreference(Context context) {
super(context);
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public OnBindEditTextListener getOnBindEditTextListener() {
return onBindEditTextListener;
}
public void setOnBindEditTextListener(@Nullable OnBindEditTextListener onBindEditTextListener) {
this.onBindEditTextListener = onBindEditTextListener;
}
public interface OnBindEditTextListener {
void onBindEditText(@NonNull EditText editText);
}
/** Tachidesk specific API */
@Override
public String getDefaultValueType() {
return "String";
}
}

View File

@@ -0,0 +1,66 @@
package androidx.preference;
/*
* 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/. */
import android.content.Context;
import android.text.TextUtils;
import com.fasterxml.jackson.annotation.JsonIgnore;
public class ListPreference extends Preference {
// reference: https://android.googlesource.com/platform/frameworks/support/+/996971f962fcd554339a7cb2859cef9ca89dbcb7/preference/preference/src/main/java/androidx/preference/ListPreference.java
// Note: remove @JsonIgnore and implement methods if any extension ever uses these methods or the variables behind them
private CharSequence[] entries;
private CharSequence[] entryValues;
public ListPreference(Context context) {
super(context);
}
public CharSequence[] getEntries() {
return entries;
}
public void setEntries(CharSequence[] entries) {
this.entries = entries;
}
public int findIndexOfValue(String value) {
if (value != null && entryValues != null) {
for (int i = entryValues.length - 1; i >= 0; i--) {
if (TextUtils.equals(entryValues[i].toString(), value)) {
return i;
}
}
}
return -1;
}
public CharSequence[] getEntryValues() {
return entryValues;
}
public void setEntryValues(CharSequence[] entryValues) {
this.entryValues = entryValues;
}
@JsonIgnore
public void setValueIndex(int index) { throw new RuntimeException("Stub!"); }
@JsonIgnore
public String getValue() { throw new RuntimeException("Stub!"); }
@JsonIgnore
public void setValue(String value) { throw new RuntimeException("Stub!"); }
/** Tachidesk specific API */
@Override
public String getDefaultValueType() {
return "String";
}
}

View File

@@ -0,0 +1,61 @@
package androidx.preference;
/*
* 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/. */
import android.content.Context;
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
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 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!");
}
/** Tachidesk specific API */
@Override
public String getDefaultValueType() {
return "Set<String>";
}
}

View File

@@ -0,0 +1,157 @@
package androidx.preference;
/*
* 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/. */
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
*/
public class Preference {
// reference: https://android.googlesource.com/platform/frameworks/support/+/996971f962fcd554339a7cb2859cef9ca89dbcb7/preference/preference/src/main/java/androidx/preference/Preference.java
// Note: `Preference` doesn't actually hold or persist the value, `OnPreferenceChangeListener` is called and it's up to the extension to persist it.
@JsonIgnore
protected Context context;
private boolean isVisible;
private String key;
private CharSequence title;
private CharSequence summary;
private Object defaultValue;
/** Tachidesk specific API */
@JsonIgnore
private SharedPreferences sharedPreferences;
@JsonIgnore
public OnPreferenceChangeListener onChangeListener;
public Preference(Context context) {
this.context = context;
}
public Context getContext() {
return context;
}
public void setOnPreferenceChangeListener(OnPreferenceChangeListener onPreferenceChangeListener) {
this.onChangeListener = onPreferenceChangeListener;
}
public void setOnPreferenceClickListener(OnPreferenceClickListener onPreferenceClickListener) {
throw new RuntimeException("Stub!");
}
public CharSequence getTitle() {
return title;
}
public void setTitle(CharSequence title) {
this.title = title;
}
public CharSequence getSummary() {
return summary;
}
public void setSummary(CharSequence summary) {
this.summary = summary;
}
public void setEnabled(boolean enabled) {
throw new RuntimeException("Stub!");
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public void setDefaultValue(Object defaultValue) {
this.defaultValue = defaultValue;
}
public boolean callChangeListener(Object newValue) {
return onChangeListener == null || onChangeListener.onPreferenceChange(this, newValue);
}
public Object getDefaultValue() {
return defaultValue;
}
/** Tachidesk specific API */
public String getDefaultValueType() {
return defaultValue.getClass().getSimpleName();
}
/** Tachidesk specific API */
public SharedPreferences getSharedPreferences() {
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;
}
public interface OnPreferenceChangeListener {
boolean onPreferenceChange(Preference preference, Object newValue);
}
public interface OnPreferenceClickListener {
boolean onPreferenceClick(Preference 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":
sharedPreferences.edit().putString(key, (String)value).apply();
break;
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

@@ -0,0 +1,36 @@
package androidx.preference;
/*
* 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/. */
import android.content.Context;
import java.util.LinkedList;
import java.util.List;
public class PreferenceScreen extends Preference {
/** Tachidesk specific API */
private List<Preference> preferences = new LinkedList<>();
public PreferenceScreen(Context context) {
super(context);
}
public boolean addPreference(Preference preference) {
// propagate own shared preferences
preference.setSharedPreferences(getSharedPreferences());
preferences.add(preference);
return true;
}
/** Tachidesk specific API */
public List<Preference> getPreferences(){
return preferences;
}
}

View File

@@ -0,0 +1,18 @@
package androidx.preference;
/*
* 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/. */
import android.content.Context;
public class SwitchPreferenceCompat extends TwoStatePreference {
// reference: https://android.googlesource.com/platform/frameworks/support/+/996971f962fcd554339a7cb2859cef9ca89dbcb7/preference/preference/src/main/java/androidx/preference/CheckBoxPreference.java
public SwitchPreferenceCompat(Context context) {
super(context);
}
}

View File

@@ -0,0 +1,50 @@
package androidx.preference;
/*
* 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/. */
import android.content.Context;
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);
setDefaultValue(false);
}
@JsonIgnore
public boolean isChecked() { throw new RuntimeException("Stub!"); }
@JsonIgnore
public void setChecked(boolean checked) { throw new RuntimeException("Stub!"); }
@JsonIgnore
public CharSequence getSummaryOn() { throw new RuntimeException("Stub!"); }
@JsonIgnore
public void setSummaryOn(CharSequence summary) { throw new RuntimeException("Stub!"); }
@JsonIgnore
public CharSequence getSummaryOff() { throw new RuntimeException("Stub!"); }
@JsonIgnore
public void setSummaryOff(CharSequence summary) { throw new RuntimeException("Stub!"); }
@JsonIgnore
public boolean getDisableDependentsState() { throw new RuntimeException("Stub!"); }
@JsonIgnore
public void setDisableDependentsState(boolean disableDependentsState) { throw new RuntimeException("Stub!"); }
/** Tachidesk specific API */
@Override
public String getDefaultValueType() {
return "Boolean";
}
}

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

@@ -1,2 +0,0 @@
package com.f2prateek;
//TODO Consider if we can change this package into an Android dependency

View File

@@ -1,34 +0,0 @@
/*
Copyright 2014 Prateek Srivastava
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.
This file may have been modified after being copied from it's original source.
*/
package com.f2prateek.rx.preferences;
import android.content.SharedPreferences;
import android.support.annotation.NonNull;
final class BooleanAdapter implements Preference.Adapter<Boolean> {
static final BooleanAdapter INSTANCE = new BooleanAdapter();
@Override public Boolean get(@NonNull String key, @NonNull SharedPreferences preferences) {
return preferences.getBoolean(key, false);
}
@Override public void set(@NonNull String key, @NonNull Boolean value,
@NonNull SharedPreferences.Editor editor) {
editor.putBoolean(key, value);
}
}

View File

@@ -1,40 +0,0 @@
/*
Copyright 2014 Prateek Srivastava
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.
This file may have been modified after being copied from it's original source.
*/
package com.f2prateek.rx.preferences;
import android.content.SharedPreferences;
import android.support.annotation.NonNull;
final class EnumAdapter<T extends Enum<T>> implements Preference.Adapter<T> {
private final Class<T> enumClass;
EnumAdapter(Class<T> enumClass) {
this.enumClass = enumClass;
}
@Override public T get(@NonNull String key, @NonNull SharedPreferences preferences) {
String value = preferences.getString(key, null);
assert value != null; // Not called unless key is present.
return Enum.valueOf(enumClass, value);
}
@Override
public void set(@NonNull String key, @NonNull T value, @NonNull SharedPreferences.Editor editor) {
editor.putString(key, value.name());
}
}

View File

@@ -1,34 +0,0 @@
/*
Copyright 2014 Prateek Srivastava
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.
This file may have been modified after being copied from it's original source.
*/
package com.f2prateek.rx.preferences;
import android.content.SharedPreferences;
import android.support.annotation.NonNull;
final class FloatAdapter implements Preference.Adapter<Float> {
static final FloatAdapter INSTANCE = new FloatAdapter();
@Override public Float get(@NonNull String key, @NonNull SharedPreferences preferences) {
return preferences.getFloat(key, 0f);
}
@Override public void set(@NonNull String key, @NonNull Float value,
@NonNull SharedPreferences.Editor editor) {
editor.putFloat(key, value);
}
}

View File

@@ -1,34 +0,0 @@
/*
Copyright 2014 Prateek Srivastava
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.
This file may have been modified after being copied from it's original source.
*/
package com.f2prateek.rx.preferences;
import android.content.SharedPreferences;
import android.support.annotation.NonNull;
final class IntegerAdapter implements Preference.Adapter<Integer> {
static final IntegerAdapter INSTANCE = new IntegerAdapter();
@Override public Integer get(@NonNull String key, @NonNull SharedPreferences preferences) {
return preferences.getInt(key, 0);
}
@Override public void set(@NonNull String key, @NonNull Integer value,
@NonNull SharedPreferences.Editor editor) {
editor.putInt(key, value);
}
}

View File

@@ -1,34 +0,0 @@
/*
Copyright 2014 Prateek Srivastava
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.
This file may have been modified after being copied from it's original source.
*/
package com.f2prateek.rx.preferences;
import android.content.SharedPreferences;
import android.support.annotation.NonNull;
final class LongAdapter implements Preference.Adapter<Long> {
static final LongAdapter INSTANCE = new LongAdapter();
@Override public Long get(@NonNull String key, @NonNull SharedPreferences preferences) {
return preferences.getLong(key, 0L);
}
@Override public void set(@NonNull String key, @NonNull Long value,
@NonNull SharedPreferences.Editor editor) {
editor.putLong(key, value);
}
}

View File

@@ -1,127 +0,0 @@
/*
Copyright 2014 Prateek Srivastava
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.
This file has been modified after being copied from it's original source.
*/
package com.f2prateek.rx.preferences;
import android.content.SharedPreferences;
import android.support.annotation.CheckResult;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import rx.Observable;
import rx.functions.Action1;
/** A preference of type {@link T}. Instances can be created from {@link RxSharedPreferences}. */
public final class Preference<T> {
/** Stores and retrieves instances of {@code T} in {@link SharedPreferences}. */
public interface Adapter<T> {
/** Retrieve the value for {@code key} from {@code preferences}. */
T get(@NonNull String key, @NonNull SharedPreferences preferences);
/**
* Store non-null {@code value} for {@code key} in {@code editor}.
* <p>
* Note: Implementations <b>must not</b> call {@code commit()} or {@code apply()} on
* {@code editor}.
*/
void set(@NonNull String key, @NonNull T value, @NonNull SharedPreferences.Editor editor);
}
private final SharedPreferences preferences;
private final String key;
private final T defaultValue;
private final Adapter<T> adapter;
private final Observable<T> values;
Preference(SharedPreferences preferences, final String key, T defaultValue, Adapter<T> adapter,
Observable<String> keyChanges) {
this.preferences = preferences;
this.key = key;
this.defaultValue = defaultValue;
this.adapter = adapter;
this.values = keyChanges
.filter(key::equals)
.startWith("<init>") // Dummy value to trigger initial load.
.onBackpressureLatest()
.map(ignored -> get());
}
/** The key for which this preference will store and retrieve values. */
@NonNull
public String key() {
return key;
}
/** The value used if none is stored. May be {@code null}. */
@Nullable
public T defaultValue() {
return defaultValue;
}
/**
* Retrieve the current value for this preference. Returns {@link #defaultValue()} if no value is
* set.
*/
@Nullable
public T get() {
if (!preferences.contains(key)) {
return defaultValue;
}
return adapter.get(key, preferences);
}
/**
* Change this preference's stored value to {@code value}. A value of {@code null} will delete the
* preference.
*/
public void set(@Nullable T value) {
SharedPreferences.Editor editor = preferences.edit();
if (value == null) {
editor.remove(key);
} else {
adapter.set(key, value, editor);
}
editor.apply();
}
/** Returns true if this preference has a stored value. */
public boolean isSet() {
return preferences.contains(key);
}
/** Delete the stored value for this preference, if any. */
public void delete() {
set(null);
}
/**
* Observe changes to this preference. The current value or {@link #defaultValue()} will be
* emitted on first subscribe.
*/
@CheckResult @NonNull
public Observable<T> asObservable() {
return values;
}
/**
* An action which stores a new value for this preference. Passing {@code null} will delete the
* preference.
*/
@CheckResult @NonNull
public Action1<? super T> asAction() {
return (Action1<T>) this::set;
}
}

View File

@@ -1,178 +0,0 @@
/*
Copyright 2014 Prateek Srivastava
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.
This file has been modified after being copied from it's original source.
*/
package com.f2prateek.rx.preferences;
import android.annotation.TargetApi;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.support.annotation.CheckResult;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import java.util.Collections;
import java.util.Set;
import rx.Observable;
import rx.subscriptions.Subscriptions;
import static android.os.Build.VERSION_CODES.HONEYCOMB;
import static com.f2prateek.rx.preferences.Preconditions.checkNotNull;
/** A factory for reactive {@link Preference} objects. */
public final class RxSharedPreferences {
private static final Float DEFAULT_FLOAT = 0f;
private static final Integer DEFAULT_INTEGER = 0;
private static final Boolean DEFAULT_BOOLEAN = Boolean.FALSE;
private static final Long DEFAULT_LONG = 0L;
/** Create an instance of {@link RxSharedPreferences} for {@code preferences}. */
@CheckResult @NonNull
public static RxSharedPreferences create(@NonNull SharedPreferences preferences) {
checkNotNull(preferences, "preferences == null");
return new RxSharedPreferences(preferences);
}
private final SharedPreferences preferences;
private final Observable<String> keyChanges;
private RxSharedPreferences(final SharedPreferences preferences) {
this.preferences = preferences;
this.keyChanges = Observable.create((Observable.OnSubscribe<String>) subscriber -> {
final OnSharedPreferenceChangeListener listener = (preferences1, key) -> subscriber.onNext(key);
preferences.registerOnSharedPreferenceChangeListener(listener);
subscriber.add(Subscriptions.create(() -> preferences.unregisterOnSharedPreferenceChangeListener(listener)));
}).share();
}
/** Create a boolean preference for {@code key}. Default is {@code false}. */
@CheckResult @NonNull
public Preference<Boolean> getBoolean(@NonNull String key) {
return getBoolean(key, DEFAULT_BOOLEAN);
}
/** Create a boolean preference for {@code key} with a default of {@code defaultValue}. */
@CheckResult @NonNull
public Preference<Boolean> getBoolean(@NonNull String key, @Nullable Boolean defaultValue) {
checkNotNull(key, "key == null");
return new Preference<>(preferences, key, defaultValue, BooleanAdapter.INSTANCE, keyChanges);
}
/** Create an enum preference for {@code key}. Default is {@code null}. */
@CheckResult @NonNull
public <T extends Enum<T>> Preference<T> getEnum(@NonNull String key,
@NonNull Class<T> enumClass) {
return getEnum(key, null, enumClass);
}
/** Create an enum preference for {@code key} with a default of {@code defaultValue}. */
@CheckResult @NonNull
public <T extends Enum<T>> Preference<T> getEnum(@NonNull String key, @Nullable T defaultValue,
@NonNull Class<T> enumClass) {
checkNotNull(key, "key == null");
checkNotNull(enumClass, "enumClass == null");
Preference.Adapter<T> adapter = new EnumAdapter<>(enumClass);
return new Preference<>(preferences, key, defaultValue, adapter, keyChanges);
}
/** Create a float preference for {@code key}. Default is {@code 0}. */
@CheckResult @NonNull
public Preference<Float> getFloat(@NonNull String key) {
return getFloat(key, DEFAULT_FLOAT);
}
/** Create a float preference for {@code key} with a default of {@code defaultValue}. */
@CheckResult @NonNull
public Preference<Float> getFloat(@NonNull String key, @Nullable Float defaultValue) {
checkNotNull(key, "key == null");
return new Preference<>(preferences, key, defaultValue, FloatAdapter.INSTANCE, keyChanges);
}
/** Create an integer preference for {@code key}. Default is {@code 0}. */
@CheckResult @NonNull
public Preference<Integer> getInteger(@NonNull String key) {
//noinspection UnnecessaryBoxing
return getInteger(key, DEFAULT_INTEGER);
}
/** Create an integer preference for {@code key} with a default of {@code defaultValue}. */
@CheckResult @NonNull
public Preference<Integer> getInteger(@NonNull String key, @Nullable Integer defaultValue) {
checkNotNull(key, "key == null");
return new Preference<>(preferences, key, defaultValue, IntegerAdapter.INSTANCE, keyChanges);
}
/** Create a long preference for {@code key}. Default is {@code 0}. */
@CheckResult @NonNull
public Preference<Long> getLong(@NonNull String key) {
//noinspection UnnecessaryBoxing
return getLong(key, DEFAULT_LONG);
}
/** Create a long preference for {@code key} with a default of {@code defaultValue}. */
@CheckResult @NonNull
public Preference<Long> getLong(@NonNull String key, @Nullable Long defaultValue) {
checkNotNull(key, "key == null");
return new Preference<>(preferences, key, defaultValue, LongAdapter.INSTANCE, keyChanges);
}
/** Create a preference of type {@code T} for {@code key}. Default is {@code null}. */
@CheckResult @NonNull
public <T> Preference<T> getObject(@NonNull String key, @NonNull Preference.Adapter<T> adapter) {
return getObject(key, null, adapter);
}
/**
* Create a preference for type {@code T} for {@code key} with a default of {@code defaultValue}.
*/
@CheckResult @NonNull
public <T> Preference<T> getObject(@NonNull String key, @Nullable T defaultValue,
@NonNull Preference.Adapter<T> adapter) {
checkNotNull(key, "key == null");
checkNotNull(adapter, "adapter == null");
return new Preference<>(preferences, key, defaultValue, adapter, keyChanges);
}
/** Create a string preference for {@code key}. Default is {@code null}. */
@CheckResult @NonNull
public Preference<String> getString(@NonNull String key) {
return getString(key, null);
}
/** Create a string preference for {@code key} with a default of {@code defaultValue}. */
@CheckResult @NonNull
public Preference<String> getString(@NonNull String key, @Nullable String defaultValue) {
checkNotNull(key, "key == null");
return new Preference<>(preferences, key, defaultValue, StringAdapter.INSTANCE, keyChanges);
}
/** Create a string set preference for {@code key}. Default is an empty set. */
@TargetApi(HONEYCOMB)
@CheckResult @NonNull
public Preference<Set<String>> getStringSet(@NonNull String key) {
return getStringSet(key, Collections.emptySet());
}
/** Create a string set preference for {@code key} with a default of {@code defaultValue}. */
@TargetApi(HONEYCOMB)
@CheckResult @NonNull
public Preference<Set<String>> getStringSet(@NonNull String key,
@NonNull Set<String> defaultValue) {
checkNotNull(key, "key == null");
return new Preference<>(preferences, key, defaultValue, StringSetAdapter.INSTANCE, keyChanges);
}
}

View File

@@ -1,17 +0,0 @@
package com.f2prateek.rx.preferences;
import android.content.SharedPreferences;
import android.support.annotation.NonNull;
final class StringAdapter implements Preference.Adapter<String> {
static final StringAdapter INSTANCE = new StringAdapter();
@Override public String get(@NonNull String key, @NonNull SharedPreferences preferences) {
return preferences.getString(key, null);
}
@Override public void set(@NonNull String key, @NonNull String value,
@NonNull SharedPreferences.Editor editor) {
editor.putString(key, value);
}
}

View File

@@ -1,22 +0,0 @@
package com.f2prateek.rx.preferences;
import android.annotation.TargetApi;
import android.content.SharedPreferences;
import android.support.annotation.NonNull;
import java.util.Set;
import static android.os.Build.VERSION_CODES.HONEYCOMB;
@TargetApi(HONEYCOMB)
final class StringSetAdapter implements Preference.Adapter<Set<String>> {
static final StringSetAdapter INSTANCE = new StringSetAdapter();
@Override public Set<String> get(@NonNull String key, @NonNull SharedPreferences preferences) {
return preferences.getStringSet(key, null);
}
@Override public void set(@NonNull String key, @NonNull Set<String> value,
@NonNull SharedPreferences.Editor editor) {
editor.putStringSet(key, value);
}
}

View File

@@ -1,7 +0,0 @@
package com.github.pwittchen.reactivenetwork.library
import android.net.NetworkInfo
class Connectivity {
val state = NetworkInfo.State.CONNECTED
}

View File

@@ -1,14 +0,0 @@
package com.github.pwittchen.reactivenetwork.library
import android.content.Context
import rx.Observable
/**
* Created by nulldev on 12/29/16.
*/
class ReactiveNetwork {
companion object {
fun observeNetworkConnectivity(context: Context) = Observable.just(Connectivity())!!
}
}

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.squareup.duktape;
import kotlin.NotImplementedError;
@@ -22,11 +23,18 @@ import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.io.Closeable;
/** A simple EMCAScript (Javascript) interpreter. */
/* Note (March 2021):
* The old implementation for duktape-android used the nashorn engine which is deprecated.
* This new implementation uses Mozilla's Rhino: https://github.com/mozilla/rhino
*/
/**
* A simple EMCAScript (Javascript) interpreter.
*/
public final class Duktape implements Closeable, AutoCloseable {
private ScriptEngineManager factory = new ScriptEngineManager();
private ScriptEngine engine = factory.getEngineByName("JavaScript");
private ScriptEngine engine = factory.getEngineByName("rhino");
/**
* Create a new interpreter instance. Calls to this method <strong>must</strong> matched with
@@ -38,17 +46,6 @@ public final class Duktape implements Closeable, AutoCloseable {
private Duktape() {}
/**
* Evaluate {@code script} and return a result. {@code fileName} will be used in error
* reporting. Note that the result must be one of the supported Java types or the call will
* return null.
*
* @throws DuktapeException if there is an error evaluating the script.
*/
public synchronized Object evaluate(String script, String fileName) {
throw new NotImplementedError("Not implemented!");
}
/**
* Evaluate {@code script} and return a result. Note that the result must be one of the
* supported Java types or the call will return null.

View File

@@ -0,0 +1,30 @@
package com.squareup.duktape;
/* part of tachiyomi-extensions which is licensed under Apache License Version 2.0 */
import java.io.Closeable;
import java.io.IOException;
/** This is the reference Duktape stub that tachiyomi's extensions depend on.
* Intended to be used as a reference.
*/
public class DuktapeStub implements Closeable {
public static Duktape create() {
throw new RuntimeException("Stub!");
}
@Override
public synchronized void close() throws IOException {
throw new RuntimeException("Stub!");
}
public synchronized Object evaluate(String script) {
throw new RuntimeException("Stub!");
}
public synchronized <T> void set(String name, Class<T> type, T object) {
throw new RuntimeException("Stub!");
}
}

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

@@ -1,5 +0,0 @@
package kotlinx.coroutines.experimental.android
import kotlinx.coroutines.GlobalScope
val UI = GlobalScope.coroutineContext

View File

@@ -1,5 +1,6 @@
package rx.android.schedulers
import rx.Scheduler
import rx.internal.schedulers.ImmediateScheduler
class AndroidSchedulers {
@@ -11,6 +12,7 @@ class AndroidSchedulers {
/**
* Simulated main thread scheduler
*/
fun mainThread() = mainThreadScheduler
@JvmStatic
fun mainThread(): Scheduler = mainThreadScheduler
}
}

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

@@ -2,7 +2,6 @@ package xyz.nulldev.androidcompat
import org.kodein.di.DI
import org.kodein.di.conf.global
import xyz.nulldev.androidcompat.bytecode.ModApplier
import xyz.nulldev.androidcompat.config.ApplicationInfoConfigModule
import xyz.nulldev.androidcompat.config.FilesConfigModule
import xyz.nulldev.androidcompat.config.SystemConfigModule
@@ -12,19 +11,20 @@ import xyz.nulldev.ts.config.GlobalConfigManager
* Initializes the Android compatibility module
*/
class AndroidCompatInitializer {
val modApplier by lazy { ModApplier() }
fun init() {
modApplier.apply()
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",
)
}
}

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

@@ -38,7 +38,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import xyz.nulldev.androidcompat.info.ApplicationInfoImpl;
import xyz.nulldev.androidcompat.io.AndroidFiles;
import xyz.nulldev.androidcompat.io.sharedprefs.JsonSharedPreferences;
import xyz.nulldev.androidcompat.io.sharedprefs.JavaSharedPreferences;
import xyz.nulldev.androidcompat.service.ServiceSupport;
import xyz.nulldev.androidcompat.util.KodeinGlobalHelper;
@@ -50,10 +50,9 @@ import java.util.Map;
/**
* Custom context implementation.
*
* TODO Deal with packagemanager for extension sources
*/
public class CustomContext extends Context implements DIAware {
private DI kodein;
private final DI kodein;
public CustomContext() {
this(KodeinGlobalHelper.kodein());
}
@@ -165,23 +164,22 @@ public class CustomContext extends Context implements DIAware {
/** Fake shared prefs! **/
private Map<String, SharedPreferences> prefs = new HashMap<>(); //Cache
private File sharedPrefsFileFromString(String s) {
return new File(androidFiles.getPrefsDir(), s + ".json");
}
@Override
public synchronized SharedPreferences getSharedPreferences(String s, int i) {
SharedPreferences preferences = prefs.get(s);
//Create new shared preferences if one does not exist
if(preferences == null) {
preferences = getSharedPreferences(sharedPrefsFileFromString(s), i);
preferences = new JavaSharedPreferences(s);
prefs.put(s, preferences);
}
return preferences;
}
public SharedPreferences getSharedPreferences(File file, int mode) {
return new JsonSharedPreferences(file);
@Override
public SharedPreferences getSharedPreferences(@NotNull File file, int mode) {
String path = file.getAbsolutePath().replace('\\', '/');
int firstSlash = path.indexOf("/");
return new JavaSharedPreferences(path.substring(firstSlash));
}
@Override
@@ -191,8 +189,8 @@ public class CustomContext extends Context implements DIAware {
@Override
public boolean deleteSharedPreferences(String name) {
prefs.remove(name);
return sharedPrefsFileFromString(name).delete();
JavaSharedPreferences item = (JavaSharedPreferences) prefs.remove(name);
return item.deleteAll();
}
@Override
@@ -735,4 +733,3 @@ public class CustomContext extends Context implements DIAware {
}
}

View File

@@ -1,22 +0,0 @@
package xyz.nulldev.androidcompat.bytecode
import javassist.CtClass
import mu.KotlinLogging
/**
* Applies Javassist modifications
*/
class ModApplier {
val logger = KotlinLogging.logger {}
fun apply() {
logger.info { "Applying Javassist mods..." }
val modifiedClasses = mutableListOf<CtClass>()
modifiedClasses.forEach {
it.toClass()
}
}
}

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

@@ -0,0 +1,283 @@
package xyz.nulldev.androidcompat.io.sharedprefs
/*
* 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/. */
import android.content.SharedPreferences
import com.russhwolf.settings.ExperimentalSettingsApi
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.serializer
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(ExperimentalSerializationApi::class, ExperimentalSettingsApi::class)
class JavaSharedPreferences(key: String) : SharedPreferences {
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? {
return if (defValue != null) {
preferences.getString(key, defValue)
} else {
preferences.getStringOrNull(key)
}
}
override fun getStringSet(
key: String,
defValues: Set<String>?,
): Set<String>? {
try {
return if (defValues != null) {
preferences.decodeValue(SetSerializer(String.serializer()), key, defValues)
} else {
preferences.decodeValueOrNull(SetSerializer(String.serializer()), key)
}
} catch (e: SerializationException) {
throw ClassCastException("$key was not a StringSet")
}
}
override fun getInt(
key: String,
defValue: Int,
): Int {
return preferences.getInt(key, defValue)
}
override fun getLong(
key: String,
defValue: Long,
): Long {
return preferences.getLong(key, defValue)
}
override fun getFloat(
key: String,
defValue: Float,
): Float {
return preferences.getFloat(key, defValue)
}
override fun getBoolean(
key: String,
defValue: Boolean,
): Boolean {
return preferences.getBoolean(key, defValue)
}
override fun contains(key: String): Boolean {
return key in preferences.keys
}
override fun edit(): SharedPreferences.Editor {
return Editor(preferences) { key ->
listeners.forEach { (_, listener) ->
listener(key)
}
}
}
class Editor(private val preferences: Settings, private val notify: (String) -> Unit) : SharedPreferences.Editor {
private val actions = mutableListOf<Action>()
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) {
actions += Action.Add(key, value)
} else {
actions += Action.Remove(key)
}
return this
}
override fun putStringSet(
key: String,
values: MutableSet<String>?,
): SharedPreferences.Editor {
if (values != null) {
actions += Action.Add(key, values)
} else {
actions += Action.Remove(key)
}
return this
}
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 {
actions += Action.Add(key, value)
return this
}
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 {
actions += Action.Add(key, value)
return this
}
override fun remove(key: String): SharedPreferences.Editor {
actions += Action.Remove(key)
return this
}
override fun clear(): SharedPreferences.Editor {
actions.add(Action.Clear)
return this
}
override fun commit(): Boolean {
addToPreferences()
return true
}
override fun apply() {
addToPreferences()
}
private fun addToPreferences() {
actions.forEach {
@Suppress("UNCHECKED_CAST")
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: (String) -> Unit = {
listener.onSharedPreferenceChanged(this, it)
}
listeners[listener] = javaListener
}
override fun unregisterOnSharedPreferenceChangeListener(listener: SharedPreferences.OnSharedPreferenceChangeListener) {
listeners.remove(listener)
}
fun deleteAll(): Boolean {
preferences.clear()
return true
}
}

View File

@@ -233,7 +233,7 @@ public class JsonSharedPreferences implements SharedPreferences {
private JsonSharedPreferencesEditor() {
}
private void recordChange(String key) {
private void recordChange(String key) {
if (!affectedKeys.contains(key)) {
affectedKeys.add(key);
}

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(root, 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,17 +85,19 @@ data class InstalledPackage(val root: File) {
fun writeJar() {
try {
Dex2jar.from(apk).to(jar.toPath())
} catch(e: Exception) {
} catch (e: Exception) {
jar.delete()
}
}
private fun NodeList.toList(): List<Node> {
val out = mutableListOf<Node>()
companion object {
fun NodeList.toList(): List<Node> {
val out = mutableListOf<Node>()
for(i in 0 until length)
out += item(i)
for (i in 0 until length)
out += item(i)
return out
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

@@ -6,22 +6,24 @@ import android.content.pm.PackageInfo
import net.dongliu.apk.parser.bean.ApkMeta
import java.io.File
fun ApkMeta.toPackageInfo(root: File, apk: File): PackageInfo {
fun ApkMeta.toPackageInfo(apk: File): PackageInfo {
return PackageInfo().also {
it.packageName = packageName
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

@@ -0,0 +1,249 @@
package xyz.nulldev.androidcompat.replace.java.text;
/*
* 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/. */
import com.ibm.icu.text.DisplayContext;
import com.ibm.icu.util.Currency;
import com.ibm.icu.util.CurrencyAmount;
import com.ibm.icu.util.ULocale;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.AttributedCharacterIterator;
import java.text.FieldPosition;
import java.text.ParseException;
import java.text.ParsePosition;
import java.util.Locale;
public class NumberFormat extends java.text.NumberFormat {
private com.ibm.icu.text.NumberFormat delegate;
public NumberFormat(com.ibm.icu.text.NumberFormat delegate) {
this.delegate = delegate;
}
public StringBuffer format(Object number, StringBuffer toAppendTo, FieldPosition pos) {
return delegate.format(number, toAppendTo, pos);
}
public String format(BigInteger number) {
return delegate.format(number);
}
public String format(BigDecimal number) {
return delegate.format(number);
}
public String format(com.ibm.icu.math.BigDecimal number) {
return delegate.format(number);
}
public String format(CurrencyAmount currAmt) {
return delegate.format(currAmt);
}
public StringBuffer format(double number, StringBuffer toAppendTo, FieldPosition pos) {
return delegate.format(number, toAppendTo, pos);
}
public StringBuffer format(long number, StringBuffer toAppendTo, FieldPosition pos) {
return delegate.format(number, toAppendTo, pos);
}
public StringBuffer format(BigInteger number, StringBuffer toAppendTo, FieldPosition pos) {
return delegate.format(number, toAppendTo, pos);
}
public StringBuffer format(BigDecimal number, StringBuffer toAppendTo, FieldPosition pos) {
return delegate.format(number, toAppendTo, pos);
}
public StringBuffer format(com.ibm.icu.math.BigDecimal number, StringBuffer toAppendTo, FieldPosition pos) {
return delegate.format(number, toAppendTo, pos);
}
public StringBuffer format(CurrencyAmount currAmt, StringBuffer toAppendTo, FieldPosition pos) {
return delegate.format(currAmt, toAppendTo, pos);
}
public Number parse(String text, ParsePosition parsePosition) {
return delegate.parse(text, parsePosition);
}
public Number parse(String text) throws ParseException {
return delegate.parse(text);
}
public CurrencyAmount parseCurrency(CharSequence text, ParsePosition pos) {
return delegate.parseCurrency(text, pos);
}
public boolean isParseIntegerOnly() {
return delegate.isParseIntegerOnly();
}
public void setParseIntegerOnly(boolean value) {
delegate.setParseIntegerOnly(value);
}
public void setParseStrict(boolean value) {
delegate.setParseStrict(value);
}
public boolean isParseStrict() {
return delegate.isParseStrict();
}
public void setContext(DisplayContext context) {
delegate.setContext(context);
}
public DisplayContext getContext(DisplayContext.Type type) {
return delegate.getContext(type);
}
public static java.text.NumberFormat getInstance(Locale inLocale) {
return new NumberFormat(com.ibm.icu.text.NumberFormat.getInstance(inLocale));
}
public static com.ibm.icu.text.NumberFormat getInstance(ULocale inLocale) {
return com.ibm.icu.text.NumberFormat.getInstance(inLocale);
}
public static com.ibm.icu.text.NumberFormat getInstance(int style) {
return com.ibm.icu.text.NumberFormat.getInstance(style);
}
public static com.ibm.icu.text.NumberFormat getInstance(Locale inLocale, int style) {
return com.ibm.icu.text.NumberFormat.getInstance(inLocale, style);
}
public static com.ibm.icu.text.NumberFormat getNumberInstance(ULocale inLocale) {
return com.ibm.icu.text.NumberFormat.getNumberInstance(inLocale);
}
public static com.ibm.icu.text.NumberFormat getIntegerInstance(ULocale inLocale) {
return com.ibm.icu.text.NumberFormat.getIntegerInstance(inLocale);
}
public static com.ibm.icu.text.NumberFormat getCurrencyInstance(ULocale inLocale) {
return com.ibm.icu.text.NumberFormat.getCurrencyInstance(inLocale);
}
public static com.ibm.icu.text.NumberFormat getPercentInstance(ULocale inLocale) {
return com.ibm.icu.text.NumberFormat.getPercentInstance(inLocale);
}
public static com.ibm.icu.text.NumberFormat getScientificInstance(ULocale inLocale) {
return com.ibm.icu.text.NumberFormat.getScientificInstance(inLocale);
}
public static Locale[] getAvailableLocales() {
return com.ibm.icu.text.NumberFormat.getAvailableLocales();
}
public static ULocale[] getAvailableULocales() {
return com.ibm.icu.text.NumberFormat.getAvailableULocales();
}
public static Object registerFactory(com.ibm.icu.text.NumberFormat.NumberFormatFactory factory) {
return com.ibm.icu.text.NumberFormat.registerFactory(factory);
}
public static boolean unregister(Object registryKey) {
return com.ibm.icu.text.NumberFormat.unregister(registryKey);
}
@Override
public int hashCode() {
return delegate.hashCode();
}
@Override
public boolean equals(Object obj) {
return delegate.equals(obj);
}
@Override
public Object clone() {
return delegate.clone();
}
public boolean isGroupingUsed() {
return delegate.isGroupingUsed();
}
public void setGroupingUsed(boolean newValue) {
delegate.setGroupingUsed(newValue);
}
public int getMaximumIntegerDigits() {
return delegate.getMaximumIntegerDigits();
}
public void setMaximumIntegerDigits(int newValue) {
delegate.setMaximumIntegerDigits(newValue);
}
public int getMinimumIntegerDigits() {
return delegate.getMinimumIntegerDigits();
}
public void setMinimumIntegerDigits(int newValue) {
delegate.setMinimumIntegerDigits(newValue);
}
public int getMaximumFractionDigits() {
return delegate.getMaximumFractionDigits();
}
public void setMaximumFractionDigits(int newValue) {
delegate.setMaximumFractionDigits(newValue);
}
public int getMinimumFractionDigits() {
return delegate.getMinimumFractionDigits();
}
public void setMinimumFractionDigits(int newValue) {
delegate.setMinimumFractionDigits(newValue);
}
public void setCurrency(Currency theCurrency) {
delegate.setCurrency(theCurrency);
}
public java.util.Currency getCurrency() {
return java.util.Currency.getInstance(delegate.getCurrency().getCurrencyCode());
}
public void setRoundingMode(int roundingMode) {
delegate.setRoundingMode(roundingMode);
}
public static com.ibm.icu.text.NumberFormat getInstance(ULocale desiredLocale, int choice) {
return com.ibm.icu.text.NumberFormat.getInstance(desiredLocale, choice);
}
@Deprecated
public static String getPatternForStyle(ULocale forLocale, int choice) {
return com.ibm.icu.text.NumberFormat.getPatternForStyle(forLocale, choice);
}
public ULocale getLocale(ULocale.Type type) {
return delegate.getLocale(type);
}
public AttributedCharacterIterator formatToCharacterIterator(Object obj) {
return delegate.formatToCharacterIterator(obj);
}
public Object parseObject(String source) throws ParseException {
return delegate.parseObject(source);
}
}

View File

@@ -0,0 +1,346 @@
package xyz.nulldev.androidcompat.replace.java.text;
/*
* 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/. */
import com.ibm.icu.text.DateFormatSymbols;
import com.ibm.icu.text.DisplayContext;
import com.ibm.icu.text.TimeZoneFormat;
import com.ibm.icu.util.ULocale;
import xyz.nulldev.androidcompat.replace.java.util.Calendar;
import xyz.nulldev.androidcompat.replace.java.util.TimeZone;
import java.text.*;
import java.util.Date;
import java.util.Locale;
/**
* Overridden to switch to Android implementation
*/
public class SimpleDateFormat extends java.text.DateFormat {
private com.ibm.icu.text.SimpleDateFormat delegate;
public SimpleDateFormat() {
delegate = new com.ibm.icu.text.SimpleDateFormat();
}
private SimpleDateFormat(com.ibm.icu.text.SimpleDateFormat delegate) {
this.delegate = delegate;
}
public SimpleDateFormat(String pattern) {
delegate = new com.ibm.icu.text.SimpleDateFormat(pattern);
}
public SimpleDateFormat(String pattern, Locale loc) {
delegate = new com.ibm.icu.text.SimpleDateFormat(pattern, loc);
}
public SimpleDateFormat(String pattern, ULocale loc) {
delegate = new com.ibm.icu.text.SimpleDateFormat(pattern, loc);
}
public SimpleDateFormat(String pattern, String override, ULocale loc) {
delegate = new com.ibm.icu.text.SimpleDateFormat(pattern, override, loc);
}
public SimpleDateFormat(String pattern, DateFormatSymbols formatData) {
delegate = new com.ibm.icu.text.SimpleDateFormat(pattern, formatData);
}
public SimpleDateFormat(String pattern, DateFormatSymbols formatData, ULocale loc) {
delegate = new com.ibm.icu.text.SimpleDateFormat(pattern, formatData, loc);
}
@Deprecated
public static SimpleDateFormat getInstance(com.ibm.icu.util.Calendar.FormatConfiguration formatConfig) {
return new SimpleDateFormat(com.ibm.icu.text.SimpleDateFormat.getInstance(formatConfig));
}
public void set2DigitYearStart(Date startDate) {
delegate.set2DigitYearStart(startDate);
}
public Date get2DigitYearStart() {
return delegate.get2DigitYearStart();
}
public void setContext(DisplayContext context) {
delegate.setContext(context);
}
public StringBuffer format(com.ibm.icu.util.Calendar cal, StringBuffer toAppendTo, FieldPosition pos) {
return delegate.format(cal, toAppendTo, pos);
}
public void setNumberFormat(com.ibm.icu.text.NumberFormat newNumberFormat) {
delegate.setNumberFormat(newNumberFormat);
}
public void parse(String text, com.ibm.icu.util.Calendar cal, ParsePosition parsePos) {
delegate.parse(text, cal, parsePos);
}
public String toPattern() {
return delegate.toPattern();
}
public String toLocalizedPattern() {
return delegate.toLocalizedPattern();
}
public void applyPattern(String pat) {
delegate.applyPattern(pat);
}
public void applyLocalizedPattern(String pat) {
delegate.applyLocalizedPattern(pat);
}
public DateFormatSymbols getDateFormatSymbols() {
return delegate.getDateFormatSymbols();
}
public void setDateFormatSymbols(DateFormatSymbols newFormatSymbols) {
delegate.setDateFormatSymbols(newFormatSymbols);
}
public TimeZoneFormat getTimeZoneFormat() {
return delegate.getTimeZoneFormat();
}
public void setTimeZoneFormat(TimeZoneFormat tzfmt) {
delegate.setTimeZoneFormat(tzfmt);
}
@Override
public Object clone() {
return delegate.clone();
}
@Override
public int hashCode() {
return delegate.hashCode();
}
@Override
public boolean equals(Object obj) {
return delegate.equals(obj);
}
@Override
public AttributedCharacterIterator formatToCharacterIterator(Object obj) {
return delegate.formatToCharacterIterator(obj);
}
@Deprecated
public StringBuffer intervalFormatByAlgorithm(com.ibm.icu.util.Calendar fromCalendar, com.ibm.icu.util.Calendar toCalendar, StringBuffer appendTo, FieldPosition pos) throws IllegalArgumentException {
return delegate.intervalFormatByAlgorithm(fromCalendar, toCalendar, appendTo, pos);
}
public void setNumberFormat(String fields, com.ibm.icu.text.NumberFormat overrideNF) {
delegate.setNumberFormat(fields, overrideNF);
}
public com.ibm.icu.text.NumberFormat getNumberFormat(char field) {
return delegate.getNumberFormat(field);
}
@Override
public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition) {
return delegate.format(date, toAppendTo, fieldPosition);
}
@Override
public Date parse(String text) throws ParseException {
return delegate.parse(text);
}
@Override
public Date parse(String text, ParsePosition pos) {
return delegate.parse(text, pos);
}
@Override
public Object parseObject(String source, ParsePosition pos) {
return delegate.parseObject(source, pos);
}
public static com.ibm.icu.text.DateFormat getTimeInstance(int style, ULocale locale) {
return com.ibm.icu.text.DateFormat.getTimeInstance(style, locale);
}
public static com.ibm.icu.text.DateFormat getDateInstance(int style, ULocale locale) {
return com.ibm.icu.text.DateFormat.getDateInstance(style, locale);
}
public static com.ibm.icu.text.DateFormat getDateTimeInstance(int dateStyle, int timeStyle, ULocale locale) {
return com.ibm.icu.text.DateFormat.getDateTimeInstance(dateStyle, timeStyle, locale);
}
public static Locale[] getAvailableLocales() {
return com.ibm.icu.text.DateFormat.getAvailableLocales();
}
public static ULocale[] getAvailableULocales() {
return com.ibm.icu.text.DateFormat.getAvailableULocales();
}
@Override
public void setCalendar(java.util.Calendar newCalendar) {
com.ibm.icu.util.Calendar cal = com.ibm.icu.util.Calendar.getInstance(com.ibm.icu.util.TimeZone.getTimeZone(newCalendar.getTimeZone().getID()));
cal.setTimeInMillis(newCalendar.getTimeInMillis());
delegate.setCalendar(cal);
}
@Override
public java.util.Calendar getCalendar() {
return new Calendar(delegate.getCalendar());
}
@Override
public java.text.NumberFormat getNumberFormat() {
return new NumberFormat(delegate.getNumberFormat());
}
@Override
public void setTimeZone(java.util.TimeZone zone) {
delegate.setTimeZone(com.ibm.icu.util.TimeZone.getTimeZone(zone.getID()));
}
@Override
public java.util.TimeZone getTimeZone() {
return new TimeZone(delegate.getTimeZone());
}
@Override
public void setLenient(boolean lenient) {
delegate.setLenient(lenient);
}
@Override
public boolean isLenient() {
return delegate.isLenient();
}
public void setCalendarLenient(boolean lenient) {
delegate.setCalendarLenient(lenient);
}
public boolean isCalendarLenient() {
return delegate.isCalendarLenient();
}
public com.ibm.icu.text.DateFormat setBooleanAttribute(com.ibm.icu.text.DateFormat.BooleanAttribute key, boolean value) {
return delegate.setBooleanAttribute(key, value);
}
public boolean getBooleanAttribute(com.ibm.icu.text.DateFormat.BooleanAttribute key) {
return delegate.getBooleanAttribute(key);
}
public DisplayContext getContext(DisplayContext.Type type) {
return delegate.getContext(type);
}
public static com.ibm.icu.text.DateFormat getDateInstance(com.ibm.icu.util.Calendar cal, int dateStyle, Locale locale) {
return com.ibm.icu.text.DateFormat.getDateInstance(cal, dateStyle, locale);
}
public static com.ibm.icu.text.DateFormat getDateInstance(com.ibm.icu.util.Calendar cal, int dateStyle, ULocale locale) {
return com.ibm.icu.text.DateFormat.getDateInstance(cal, dateStyle, locale);
}
public static com.ibm.icu.text.DateFormat getTimeInstance(com.ibm.icu.util.Calendar cal, int timeStyle, Locale locale) {
return com.ibm.icu.text.DateFormat.getTimeInstance(cal, timeStyle, locale);
}
public static com.ibm.icu.text.DateFormat getTimeInstance(com.ibm.icu.util.Calendar cal, int timeStyle, ULocale locale) {
return com.ibm.icu.text.DateFormat.getTimeInstance(cal, timeStyle, locale);
}
public static com.ibm.icu.text.DateFormat getDateTimeInstance(com.ibm.icu.util.Calendar cal, int dateStyle, int timeStyle, Locale locale) {
return com.ibm.icu.text.DateFormat.getDateTimeInstance(cal, dateStyle, timeStyle, locale);
}
public static com.ibm.icu.text.DateFormat getDateTimeInstance(com.ibm.icu.util.Calendar cal, int dateStyle, int timeStyle, ULocale locale) {
return com.ibm.icu.text.DateFormat.getDateTimeInstance(cal, dateStyle, timeStyle, locale);
}
public static com.ibm.icu.text.DateFormat getInstance(com.ibm.icu.util.Calendar cal, Locale locale) {
return com.ibm.icu.text.DateFormat.getInstance(cal, locale);
}
public static com.ibm.icu.text.DateFormat getInstance(com.ibm.icu.util.Calendar cal, ULocale locale) {
return com.ibm.icu.text.DateFormat.getInstance(cal, locale);
}
public static com.ibm.icu.text.DateFormat getInstance(com.ibm.icu.util.Calendar cal) {
return com.ibm.icu.text.DateFormat.getInstance(cal);
}
public static com.ibm.icu.text.DateFormat getDateInstance(com.ibm.icu.util.Calendar cal, int dateStyle) {
return com.ibm.icu.text.DateFormat.getDateInstance(cal, dateStyle);
}
public static com.ibm.icu.text.DateFormat getTimeInstance(com.ibm.icu.util.Calendar cal, int timeStyle) {
return com.ibm.icu.text.DateFormat.getTimeInstance(cal, timeStyle);
}
public static com.ibm.icu.text.DateFormat getDateTimeInstance(com.ibm.icu.util.Calendar cal, int dateStyle, int timeStyle) {
return com.ibm.icu.text.DateFormat.getDateTimeInstance(cal, dateStyle, timeStyle);
}
public static com.ibm.icu.text.DateFormat getInstanceForSkeleton(String skeleton) {
return com.ibm.icu.text.DateFormat.getInstanceForSkeleton(skeleton);
}
public static com.ibm.icu.text.DateFormat getInstanceForSkeleton(String skeleton, Locale locale) {
return com.ibm.icu.text.DateFormat.getInstanceForSkeleton(skeleton, locale);
}
public static com.ibm.icu.text.DateFormat getInstanceForSkeleton(String skeleton, ULocale locale) {
return com.ibm.icu.text.DateFormat.getInstanceForSkeleton(skeleton, locale);
}
public static com.ibm.icu.text.DateFormat getInstanceForSkeleton(com.ibm.icu.util.Calendar cal, String skeleton, Locale locale) {
return com.ibm.icu.text.DateFormat.getInstanceForSkeleton(cal, skeleton, locale);
}
public static com.ibm.icu.text.DateFormat getInstanceForSkeleton(com.ibm.icu.util.Calendar cal, String skeleton, ULocale locale) {
return com.ibm.icu.text.DateFormat.getInstanceForSkeleton(cal, skeleton, locale);
}
public static com.ibm.icu.text.DateFormat getPatternInstance(String skeleton) {
return com.ibm.icu.text.DateFormat.getPatternInstance(skeleton);
}
public static com.ibm.icu.text.DateFormat getPatternInstance(String skeleton, Locale locale) {
return com.ibm.icu.text.DateFormat.getPatternInstance(skeleton, locale);
}
public static com.ibm.icu.text.DateFormat getPatternInstance(String skeleton, ULocale locale) {
return com.ibm.icu.text.DateFormat.getPatternInstance(skeleton, locale);
}
public static com.ibm.icu.text.DateFormat getPatternInstance(com.ibm.icu.util.Calendar cal, String skeleton, Locale locale) {
return com.ibm.icu.text.DateFormat.getPatternInstance(cal, skeleton, locale);
}
public static com.ibm.icu.text.DateFormat getPatternInstance(com.ibm.icu.util.Calendar cal, String skeleton, ULocale locale) {
return com.ibm.icu.text.DateFormat.getPatternInstance(cal, skeleton, locale);
}
public ULocale getLocale(ULocale.Type type) {
return delegate.getLocale(type);
}
@Override
public Object parseObject(String source) throws ParseException {
return delegate.parseObject(source);
}
}

View File

@@ -0,0 +1,294 @@
package xyz.nulldev.androidcompat.replace.java.util;
/*
* 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/. */
import com.ibm.icu.text.DateFormat;
import com.ibm.icu.util.ULocale;
import java.util.Date;
import java.util.Locale;
public class Calendar extends java.util.Calendar {
private com.ibm.icu.util.Calendar delegate;
public Calendar(com.ibm.icu.util.Calendar delegate) {
this.delegate = delegate;
}
public static java.util.Calendar getInstance() {
return new Calendar(com.ibm.icu.util.Calendar.getInstance());
}
public static com.ibm.icu.util.Calendar getInstance(com.ibm.icu.util.TimeZone zone) {
return com.ibm.icu.util.Calendar.getInstance(zone);
}
public static java.util.Calendar getInstance(Locale aLocale) {
return new Calendar(com.ibm.icu.util.Calendar.getInstance(aLocale));
}
public static com.ibm.icu.util.Calendar getInstance(ULocale locale) {
return com.ibm.icu.util.Calendar.getInstance(locale);
}
public static com.ibm.icu.util.Calendar getInstance(com.ibm.icu.util.TimeZone zone, Locale aLocale) {
return com.ibm.icu.util.Calendar.getInstance(zone, aLocale);
}
public static com.ibm.icu.util.Calendar getInstance(com.ibm.icu.util.TimeZone zone, ULocale locale) {
return com.ibm.icu.util.Calendar.getInstance(zone, locale);
}
public static Locale[] getAvailableLocales() {
return com.ibm.icu.util.Calendar.getAvailableLocales();
}
@Override
protected void computeTime() {}
@Override
protected void computeFields() {}
public static ULocale[] getAvailableULocales() {
return com.ibm.icu.util.Calendar.getAvailableULocales();
}
public static String[] getKeywordValuesForLocale(String key, ULocale locale, boolean commonlyUsed) {
return com.ibm.icu.util.Calendar.getKeywordValuesForLocale(key, locale, commonlyUsed);
}
@Override
public long getTimeInMillis() {
return delegate.getTimeInMillis();
}
@Override
public void setTimeInMillis(long millis) {
delegate.setTimeInMillis(millis);
}
@Deprecated
public int getRelatedYear() {
return delegate.getRelatedYear();
}
@Deprecated
public void setRelatedYear(int year) {
delegate.setRelatedYear(year);
}
@Override
public boolean equals(Object obj) {
return delegate.equals(obj);
}
public boolean isEquivalentTo(com.ibm.icu.util.Calendar other) {
return delegate.isEquivalentTo(other);
}
@Override
public int hashCode() {
return delegate.hashCode();
}
@Override
public boolean before(Object when) {
return delegate.before(when);
}
@Override
public boolean after(Object when) {
return delegate.after(when);
}
@Override
public int getActualMaximum(int field) {
return delegate.getActualMaximum(field);
}
@Override
public int getActualMinimum(int field) {
return delegate.getActualMinimum(field);
}
@Override
public void roll(int field, int amount) {
delegate.roll(field, amount);
}
@Override
public void add(int field, int amount) {
delegate.add(field, amount);
}
@Override
public void roll(int field, boolean up) {
roll(field, up ? 1 : -1);
}
public String getDisplayName(Locale loc) {
return delegate.getDisplayName(loc);
}
public String getDisplayName(ULocale loc) {
return delegate.getDisplayName(loc);
}
public int compareTo(com.ibm.icu.util.Calendar that) {
return delegate.compareTo(that);
}
public DateFormat getDateTimeFormat(int dateStyle, int timeStyle, Locale loc) {
return delegate.getDateTimeFormat(dateStyle, timeStyle, loc);
}
public DateFormat getDateTimeFormat(int dateStyle, int timeStyle, ULocale loc) {
return delegate.getDateTimeFormat(dateStyle, timeStyle, loc);
}
@Deprecated
public static String getDateTimePattern(com.ibm.icu.util.Calendar cal, ULocale uLocale, int dateStyle) {
return com.ibm.icu.util.Calendar.getDateTimePattern(cal, uLocale, dateStyle);
}
public int fieldDifference(Date when, int field) {
return delegate.fieldDifference(when, field);
}
public void setTimeZone(com.ibm.icu.util.TimeZone value) {
delegate.setTimeZone(value);
}
@Override
public java.util.TimeZone getTimeZone() {
return new TimeZone(delegate.getTimeZone());
}
@Override
public void setLenient(boolean lenient) {
delegate.setLenient(lenient);
}
@Override
public boolean isLenient() {
return delegate.isLenient();
}
public void setRepeatedWallTimeOption(int option) {
delegate.setRepeatedWallTimeOption(option);
}
public int getRepeatedWallTimeOption() {
return delegate.getRepeatedWallTimeOption();
}
public void setSkippedWallTimeOption(int option) {
delegate.setSkippedWallTimeOption(option);
}
public int getSkippedWallTimeOption() {
return delegate.getSkippedWallTimeOption();
}
@Override
public void setFirstDayOfWeek(int value) {
delegate.setFirstDayOfWeek(value);
}
@Override
public int getFirstDayOfWeek() {
return delegate.getFirstDayOfWeek();
}
@Override
public void setMinimalDaysInFirstWeek(int value) {
delegate.setMinimalDaysInFirstWeek(value);
}
@Override
public int getMinimalDaysInFirstWeek() {
return delegate.getMinimalDaysInFirstWeek();
}
@Override
public int getMinimum(int field) {
return delegate.getMinimum(field);
}
@Override
public int getMaximum(int field) {
return delegate.getMaximum(field);
}
@Override
public int getGreatestMinimum(int field) {
return delegate.getGreatestMinimum(field);
}
@Override
public int getLeastMaximum(int field) {
return delegate.getLeastMaximum(field);
}
@Deprecated
public int getDayOfWeekType(int dayOfWeek) {
return delegate.getDayOfWeekType(dayOfWeek);
}
@Deprecated
public int getWeekendTransition(int dayOfWeek) {
return delegate.getWeekendTransition(dayOfWeek);
}
public boolean isWeekend(Date date) {
return delegate.isWeekend(date);
}
public boolean isWeekend() {
return delegate.isWeekend();
}
@Override
public Object clone() {
return delegate.clone();
}
@Override
public String toString() {
return delegate.toString();
}
public static com.ibm.icu.util.Calendar.WeekData getWeekDataForRegion(String region) {
return com.ibm.icu.util.Calendar.getWeekDataForRegion(region);
}
public com.ibm.icu.util.Calendar.WeekData getWeekData() {
return delegate.getWeekData();
}
public com.ibm.icu.util.Calendar setWeekData(com.ibm.icu.util.Calendar.WeekData wdata) {
return delegate.setWeekData(wdata);
}
public int getFieldCount() {
return delegate.getFieldCount();
}
public String getType() {
return delegate.getType();
}
@Deprecated
public boolean haveDefaultCentury() {
return delegate.haveDefaultCentury();
}
public ULocale getLocale(ULocale.Type type) {
return delegate.getLocale(type);
}
}

View File

@@ -0,0 +1,196 @@
package xyz.nulldev.androidcompat.replace.java.util;
/*
* 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/. */
import com.ibm.icu.util.ULocale;
import java.util.Date;
import java.util.Locale;
import java.util.Set;
public class TimeZone extends java.util.TimeZone {
private com.ibm.icu.util.TimeZone delegate;
public TimeZone(com.ibm.icu.util.TimeZone delegate) {
this.delegate = delegate;
}
@Override
public int getOffset(int era, int year, int month, int day, int dayOfWeek, int milliseconds) {
return delegate.getOffset(era, year, month, day, dayOfWeek, milliseconds);
}
@Override
public int getOffset(long date) {
return delegate.getOffset(date);
}
public void getOffset(long date, boolean local, int[] offsets) {
delegate.getOffset(date, local, offsets);
}
@Override
public void setRawOffset(int offsetMillis) {
delegate.setRawOffset(offsetMillis);
}
@Override
public int getRawOffset() {
return delegate.getRawOffset();
}
@Override
public String getID() {
return delegate.getID();
}
@Override
public void setID(String ID) {
delegate.setID(ID);
}
public String getDisplayName(ULocale locale) {
return delegate.getDisplayName(locale);
}
@Override
public String getDisplayName(boolean daylight, int style, Locale locale) {
return delegate.getDisplayName(daylight, style, locale);
}
public String getDisplayName(boolean daylight, int style, ULocale locale) {
return delegate.getDisplayName(daylight, style, locale);
}
@Override
public int getDSTSavings() {
return delegate.getDSTSavings();
}
@Override
public boolean useDaylightTime() {
return delegate.useDaylightTime();
}
@Override
public boolean observesDaylightTime() {
return delegate.observesDaylightTime();
}
@Override
public boolean inDaylightTime(Date date) {
return delegate.inDaylightTime(date);
}
public static java.util.TimeZone getTimeZone(String ID) {
return new TimeZone(com.ibm.icu.util.TimeZone.getTimeZone(ID));
}
public static com.ibm.icu.util.TimeZone getFrozenTimeZone(String ID) {
return com.ibm.icu.util.TimeZone.getFrozenTimeZone(ID);
}
public static com.ibm.icu.util.TimeZone getTimeZone(String ID, int type) {
return com.ibm.icu.util.TimeZone.getTimeZone(ID, type);
}
public static void setDefaultTimeZoneType(int type) {
com.ibm.icu.util.TimeZone.setDefaultTimeZoneType(type);
}
public static int getDefaultTimeZoneType() {
return com.ibm.icu.util.TimeZone.getDefaultTimeZoneType();
}
public static Set<String> getAvailableIDs(com.ibm.icu.util.TimeZone.SystemTimeZoneType zoneType, String region, Integer rawOffset) {
return com.ibm.icu.util.TimeZone.getAvailableIDs(zoneType, region, rawOffset);
}
public static String[] getAvailableIDs(int rawOffset) {
return com.ibm.icu.util.TimeZone.getAvailableIDs(rawOffset);
}
public static String[] getAvailableIDs(String country) {
return com.ibm.icu.util.TimeZone.getAvailableIDs(country);
}
public static String[] getAvailableIDs() {
return com.ibm.icu.util.TimeZone.getAvailableIDs();
}
public static int countEquivalentIDs(String id) {
return com.ibm.icu.util.TimeZone.countEquivalentIDs(id);
}
public static String getEquivalentID(String id, int index) {
return com.ibm.icu.util.TimeZone.getEquivalentID(id, index);
}
public static java.util.TimeZone getDefault() {
return new TimeZone(com.ibm.icu.util.TimeZone.getDefault());
}
public static void setDefault(com.ibm.icu.util.TimeZone tz) {
com.ibm.icu.util.TimeZone.setDefault(tz);
}
public boolean hasSameRules(com.ibm.icu.util.TimeZone other) {
return delegate.hasSameRules(other);
}
@Override
public Object clone() {
return delegate.clone();
}
@Override
public boolean equals(Object obj) {
return delegate.equals(obj);
}
@Override
public int hashCode() {
return delegate.hashCode();
}
public static String getTZDataVersion() {
return com.ibm.icu.util.TimeZone.getTZDataVersion();
}
public static String getCanonicalID(String id) {
return com.ibm.icu.util.TimeZone.getCanonicalID(id);
}
public static String getCanonicalID(String id, boolean[] isSystemID) {
return com.ibm.icu.util.TimeZone.getCanonicalID(id, isSystemID);
}
public static String getRegion(String id) {
return com.ibm.icu.util.TimeZone.getRegion(id);
}
public static String getWindowsID(String id) {
return com.ibm.icu.util.TimeZone.getWindowsID(id);
}
public static String getIDForWindowsID(String winid, String region) {
return com.ibm.icu.util.TimeZone.getIDForWindowsID(winid, region);
}
public boolean isFrozen() {
return delegate.isFrozen();
}
public com.ibm.icu.util.TimeZone freeze() {
return delegate.freeze();
}
public com.ibm.icu.util.TimeZone cloneAsThawed() {
return delegate.cloneAsThawed();
}
}

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(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(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

@@ -25,8 +25,12 @@ object KodeinGlobalHelper {
* Get a dependency
*/
@JvmStatic
fun <T : Any> instance(type: Class<T>, kodein: DI? = null): T {
return when(type) {
@Suppress("UNCHECKED_CAST")
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
@@ -63,5 +67,4 @@ object KodeinGlobalHelper {
fun <T : Any> instance(type: Class<T>): T {
return instance(type, null)
}
}

View File

@@ -0,0 +1,47 @@
package xyz.nulldev.androidcompat.util
/*
* 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/. */
// adopted from: https://github.com/tachiyomiorg/tachiyomi/blob/4cefbce7c34e724b409b6ba127f3c6c5c346ad8d/app/src/main/java/eu/kanade/tachiyomi/util/storage/DiskUtil.kt
object SafePath {
/**
* Mutate the given filename to make it valid for a FAT filesystem,
* replacing any invalid characters with "_". This method doesn't allow hidden files (starting
* with a dot), but you can manually add it later.
*/
fun buildValidFilename(origName: String): String {
val name = origName.trim('.', ' ')
if (name.isEmpty()) {
return "(invalid)"
}
val sb = StringBuilder(name.length)
name.forEach { c ->
if (isValidFatFilenameChar(c)) {
sb.append(c)
} else {
sb.append('_')
}
}
// Even though vfat allows 255 UCS-2 chars, we might eventually write to
// ext4 through a FUSE layer, so use that limit minus 15 reserved characters.
return sb.toString().take(240)
}
/**
* Returns true if the given character is a valid filename character, false otherwise.
*/
private fun isValidFatFilenameChar(c: Char): Boolean {
if (0x00.toChar() <= c && c <= 0x1f.toChar()) {
return false
}
return when (c) {
'"', '*', '/', ':', '<', '>', '?', '\\', '|', 0x7f.toChar() -> false
else -> true
}
}
}

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