From 968f4a69e80b0906eb59019fa5b362b479a6b4ed Mon Sep 17 00:00:00 2001 From: inorichi Date: Sun, 22 Apr 2018 13:15:47 +0200 Subject: [PATCH 01/22] Separate 'en' locale into 'en-US' and 'en-GB' for displaying dates --- .../kanade/tachiyomi/ui/setting/SettingsGeneralController.kt | 5 +++-- build.gradle | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsGeneralController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsGeneralController.kt index 59d3276d5..a4611da39 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsGeneralController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsGeneralController.kt @@ -29,8 +29,9 @@ class SettingsGeneralController : SettingsController() { listPreference { key = Keys.lang titleRes = R.string.pref_language - entryValues = arrayOf("", "ar", "bg", "bn", "de", "en", "es", "fr", "hi", "hu", "id", - "it", "ja", "ko", "lv", "ms", "nl", "pl", "pt", "pt-BR", "ro", "ru", "vi") + entryValues = arrayOf("", "ar", "bg", "bn", "de", "en-US", "en-GB", "es", "fr", "hi", + "hu", "id", "it", "ja", "ko", "lv", "ms", "nl", "pl", "pt", "pt-BR", "ro", + "ru", "vi") entries = entryValues.map { value -> val locale = LocaleHelper.getLocaleFromString(value.toString()) locale?.getDisplayName(locale)?.capitalize() ?: diff --git a/build.gradle b/build.gradle index 2a39702a8..733287c0a 100644 --- a/build.gradle +++ b/build.gradle @@ -7,7 +7,7 @@ buildscript { google() } dependencies { - classpath 'com.android.tools.build:gradle:3.1.0' + classpath 'com.android.tools.build:gradle:3.1.1' classpath 'com.github.ben-manes:gradle-versions-plugin:0.17.0' classpath 'com.github.zellius:android-shortcut-gradle-plugin:0.1.2' // NOTE: Do not place your application dependencies here; they belong From 00981cf4e8f1080e7f7d84fdfbf103132baaf9cf Mon Sep 17 00:00:00 2001 From: inorichi Date: Wed, 25 Apr 2018 13:46:57 +0200 Subject: [PATCH 02/22] Include firebase analytics --- .travis/build.sh | 2 + .travis/google-services.json | 73 ++++++++++++++++++++++++++++++++++++ app/build.gradle | 8 +++- build.gradle | 3 +- 4 files changed, 84 insertions(+), 2 deletions(-) create mode 100644 .travis/google-services.json diff --git a/.travis/build.sh b/.travis/build.sh index 049fd015b..cb7afd13c 100755 --- a/.travis/build.sh +++ b/.travis/build.sh @@ -2,6 +2,8 @@ git fetch --unshallow #required for commit count +cp .travis/google-services.json app/ + if [ -z "$TRAVIS_TAG" ]; then ./gradlew clean assembleStandardDebug diff --git a/.travis/google-services.json b/.travis/google-services.json new file mode 100644 index 000000000..72d54700e --- /dev/null +++ b/.travis/google-services.json @@ -0,0 +1,73 @@ +{ + "project_info": { + "project_number": "777921915939", + "firebase_url": "https://tachiyomi-47364.firebaseio.com", + "project_id": "tachiyomi-47364", + "storage_bucket": "tachiyomi-47364.appspot.com" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:777921915939:android:36544cd2d96c50c7", + "android_client_info": { + "package_name": "eu.kanade.tachiyomi" + } + }, + "oauth_client": [ + { + "client_id": "777921915939-9q25jvgbdtpk91daqlk7sa1cbdcg77o6.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyAHr8RxyeiSPC_MxJTnivz-hmdo5oX0QQQ" + } + ], + "services": { + "analytics_service": { + "status": 1 + }, + "appinvite_service": { + "status": 1, + "other_platform_oauth_client": [] + }, + "ads_service": { + "status": 2 + } + } + }, + { + "client_info": { + "mobilesdk_app_id": "1:777921915939:android:564fdc1d62efd1de", + "android_client_info": { + "package_name": "eu.kanade.tachiyomi.debug" + } + }, + "oauth_client": [ + { + "client_id": "777921915939-9q25jvgbdtpk91daqlk7sa1cbdcg77o6.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyAHr8RxyeiSPC_MxJTnivz-hmdo5oX0QQQ" + } + ], + "services": { + "analytics_service": { + "status": 1 + }, + "appinvite_service": { + "status": 1, + "other_platform_oauth_client": [] + }, + "ads_service": { + "status": 2 + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 128071c98..a084f78cb 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -120,6 +120,8 @@ dependencies { implementation 'com.android.support:multidex:1.0.2' + standardImplementation 'com.google.firebase:firebase-core:12.0.1' + // ReactiveX implementation 'io.reactivex:rxandroid:1.2.1' implementation 'io.reactivex:rxjava:1.3.6' @@ -153,7 +155,7 @@ dependencies { // Job scheduling implementation 'com.evernote:android-job:1.2.4' - implementation 'com.google.android.gms:play-services-gcm:11.8.0' + implementation 'com.google.android.gms:play-services-gcm:12.0.1' // Changelog implementation 'com.github.gabrielemariotti.changeloglib:changelog:2.1.0' @@ -254,3 +256,7 @@ kotlin { androidExtensions { experimental = true } + +if (getGradle().getStartParameter().getTaskRequests().toString().contains("Standard")) { + apply plugin: 'com.google.gms.google-services' +} diff --git a/build.gradle b/build.gradle index 733287c0a..3cf40cda9 100644 --- a/build.gradle +++ b/build.gradle @@ -7,9 +7,10 @@ buildscript { google() } dependencies { - classpath 'com.android.tools.build:gradle:3.1.1' + classpath 'com.android.tools.build:gradle:3.1.2' classpath 'com.github.ben-manes:gradle-versions-plugin:0.17.0' classpath 'com.github.zellius:android-shortcut-gradle-plugin:0.1.2' + classpath 'com.google.gms:google-services:3.2.0' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } From 5c31271e917a92ab9b2be1cf45f262ef851de129 Mon Sep 17 00:00:00 2001 From: inorichi Date: Wed, 25 Apr 2018 16:26:46 +0200 Subject: [PATCH 03/22] Workaround a crash related to saving instance state and child controllers --- .../tachiyomi/ui/base/presenter/NucleusConductorDelegate.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/base/presenter/NucleusConductorDelegate.java b/app/src/main/java/eu/kanade/tachiyomi/ui/base/presenter/NucleusConductorDelegate.java index ddc4aba5a..5210a3a2a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/base/presenter/NucleusConductorDelegate.java +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/base/presenter/NucleusConductorDelegate.java @@ -28,7 +28,7 @@ public class NucleusConductorDelegate

{ Bundle onSaveInstanceState() { Bundle bundle = new Bundle(); - getPresenter(); +// getPresenter(); // Workaround a crash related to saving instance state with child routers if (presenter != null) { presenter.save(bundle); } From 18883f1ba3642dc220dac5355c0b207c4407cefb Mon Sep 17 00:00:00 2001 From: inorichi Date: Fri, 27 Apr 2018 16:55:12 +0200 Subject: [PATCH 04/22] Crop borders for webtoon now have a separate setting. Close #972 --- .../data/preference/PreferenceKeys.kt | 2 ++ .../data/preference/PreferencesHelper.kt | 2 ++ .../ui/reader/ReaderSettingsDialog.kt | 20 ++++++++++++++++++- .../ui/reader/viewer/webtoon/WebtoonReader.kt | 9 +++++++-- .../ui/setting/SettingsReaderController.kt | 7 ++++++- .../kanade/tachiyomi/util/ViewExtensions.kt | 6 +++++- .../res/layout/reader_settings_dialog.xml | 8 +++++++- 7 files changed, 48 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt index 66e9d4181..6caa902f5 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt @@ -39,6 +39,8 @@ object PreferenceKeys { const val cropBorders = "crop_borders" + const val cropBordersWebtoon = "crop_borders_webtoon" + const val readWithTapping = "reader_tap" const val readWithVolumeKeys = "reader_volume_keys" diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt index ed10fa7d3..cf594838e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt @@ -67,6 +67,8 @@ class PreferencesHelper(val context: Context) { fun cropBorders() = rxPrefs.getBoolean(Keys.cropBorders, false) + fun cropBordersWebtoon() = rxPrefs.getBoolean(Keys.cropBordersWebtoon, false) + fun readWithTapping() = rxPrefs.getBoolean(Keys.readWithTapping, true) fun readWithVolumeKeys() = rxPrefs.getBoolean(Keys.readWithVolumeKeys, false) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderSettingsDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderSettingsDialog.kt index 8927ad4fe..f40f47e2c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderSettingsDialog.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderSettingsDialog.kt @@ -9,6 +9,7 @@ import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.getOrDefault import eu.kanade.tachiyomi.util.plusAssign +import eu.kanade.tachiyomi.util.visibleIf import eu.kanade.tachiyomi.widget.IgnoreFirstSpinnerListener import kotlinx.android.synthetic.main.reader_settings_dialog.view.* import rx.Observable @@ -91,6 +92,23 @@ class ReaderSettingsDialog : DialogFragment() { crop_borders.setOnCheckedChangeListener { _, isChecked -> preferences.cropBorders().set(isChecked) } + + crop_borders_webtoon.isChecked = preferences.cropBordersWebtoon().getOrDefault() + crop_borders_webtoon.setOnCheckedChangeListener { _, isChecked -> + preferences.cropBordersWebtoon().set(isChecked) + } + + val readerActivity = activity as? ReaderActivity + val isWebtoonViewer = if (readerActivity != null) { + val mangaViewer = readerActivity.presenter.manga.viewer + val viewer = if (mangaViewer == 0) preferences.defaultViewer() else mangaViewer + viewer == ReaderActivity.WEBTOON + } else { + false + } + + crop_borders.visibleIf { !isWebtoonViewer } + crop_borders_webtoon.visibleIf { isWebtoonViewer } } override fun onDestroyView() { @@ -98,4 +116,4 @@ class ReaderSettingsDialog : DialogFragment() { super.onDestroyView() } -} \ No newline at end of file +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonReader.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonReader.kt index d2164f9e7..3ac0c5085 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonReader.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonReader.kt @@ -4,7 +4,12 @@ import android.os.Build import android.os.Bundle import android.support.v7.widget.RecyclerView import android.util.DisplayMetrics -import android.view.* +import android.view.Display +import android.view.GestureDetector +import android.view.LayoutInflater +import android.view.MotionEvent +import android.view.View +import android.view.ViewGroup import android.view.ViewGroup.LayoutParams.MATCH_PARENT import android.view.ViewGroup.LayoutParams.WRAP_CONTENT import eu.kanade.tachiyomi.source.model.Page @@ -123,7 +128,7 @@ class WebtoonReader : BaseReader() { .distinctUntilChanged() .subscribe { refreshAdapter() }) - subscriptions.add(readerActivity.preferences.cropBorders() + subscriptions.add(readerActivity.preferences.cropBordersWebtoon() .asObservable() .doOnNext { cropBorders = it } .skip(1) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsReaderController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsReaderController.kt index aa3188f03..7b0cb48bd 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsReaderController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsReaderController.kt @@ -90,6 +90,11 @@ class SettingsReaderController : SettingsController() { titleRes = R.string.pref_crop_borders defaultValue = false } + switchPreference { + key = Keys.cropBordersWebtoon + titleRes = R.string.pref_crop_borders_webtoon + defaultValue = false + } switchPreference { key = Keys.keepScreenOn titleRes = R.string.pref_keep_screen_on @@ -116,4 +121,4 @@ class SettingsReaderController : SettingsController() { } } -} \ No newline at end of file +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/ViewExtensions.kt b/app/src/main/java/eu/kanade/tachiyomi/util/ViewExtensions.kt index e3f6bbb01..af9b041e2 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/ViewExtensions.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/ViewExtensions.kt @@ -47,6 +47,10 @@ inline fun View.gone() { visibility = View.GONE } +inline fun View.visibleIf(block: () -> Boolean) { + visibility = if (block()) View.VISIBLE else View.GONE +} + /** * Returns a TextDrawable determined by input * @@ -63,4 +67,4 @@ fun View.getRound(text: String, random : Boolean = true): TextDrawable { .useFont(Typeface.DEFAULT) .endConfig() .buildRound(text, if (random) ColorGenerator.MATERIAL.randomColor else ColorGenerator.MATERIAL.getColor(text)) -} \ No newline at end of file +} diff --git a/app/src/main/res/layout/reader_settings_dialog.xml b/app/src/main/res/layout/reader_settings_dialog.xml index 2ac02900b..ea9793236 100644 --- a/app/src/main/res/layout/reader_settings_dialog.xml +++ b/app/src/main/res/layout/reader_settings_dialog.xml @@ -171,10 +171,16 @@ android:layout_height="wrap_content" android:text="@string/pref_crop_borders"/> + + - \ No newline at end of file + From 303e6c010262b997efd8e89b55e13fa30c6ff2ab Mon Sep 17 00:00:00 2001 From: inorichi Date: Sat, 28 Apr 2018 10:40:08 +0200 Subject: [PATCH 05/22] Reorganize reader settings. Update Conductor version --- app/build.gradle | 2 +- .../ui/setting/SettingsReaderController.kt | 38 +++++++++++-------- app/src/main/res/values/strings.xml | 1 + 3 files changed, 25 insertions(+), 16 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index a084f78cb..8d58c4a6b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -203,7 +203,7 @@ dependencies { implementation 'me.gujun.android.taggroup:library:1.4@aar' // Conductor - implementation "com.github.inorichi.Conductor:conductor:05c4d4d" + implementation "com.github.inorichi.Conductor:conductor:be8b3c5" implementation ("com.bluelinelabs:conductor-support:2.1.5-SNAPSHOT") { exclude group: "com.bluelinelabs", module: "conductor" } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsReaderController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsReaderController.kt index 7b0cb48bd..ae9f739f6 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsReaderController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsReaderController.kt @@ -76,8 +76,8 @@ class SettingsReaderController : SettingsController() { defaultValue = true } switchPreference { - key = Keys.enableTransitions - titleRes = R.string.pref_page_transitions + key = Keys.keepScreenOn + titleRes = R.string.pref_keep_screen_on defaultValue = true } switchPreference { @@ -85,20 +85,28 @@ class SettingsReaderController : SettingsController() { titleRes = R.string.pref_show_page_number defaultValue = true } - switchPreference { - key = Keys.cropBorders - titleRes = R.string.pref_crop_borders - defaultValue = false + preferenceCategory { + titleRes = R.string.pager_viewer + + switchPreference { + key = Keys.enableTransitions + titleRes = R.string.pref_page_transitions + defaultValue = true + } + switchPreference { + key = Keys.cropBorders + titleRes = R.string.pref_crop_borders + defaultValue = false + } } - switchPreference { - key = Keys.cropBordersWebtoon - titleRes = R.string.pref_crop_borders_webtoon - defaultValue = false - } - switchPreference { - key = Keys.keepScreenOn - titleRes = R.string.pref_keep_screen_on - defaultValue = true + preferenceCategory { + titleRes = R.string.webtoon_viewer + + switchPreference { + key = Keys.cropBordersWebtoon + titleRes = R.string.pref_crop_borders + defaultValue = false + } } preferenceCategory { titleRes = R.string.pref_reader_navigation diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f62610451..c4ef4bfb4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -190,6 +190,7 @@ Right to left Vertical Webtoon + Pager Image decoder Scale type Fit screen From 32db1e3045a3c6c787668fdca8a9b480497e0864 Mon Sep 17 00:00:00 2001 From: inorichi Date: Sat, 28 Apr 2018 10:54:27 +0200 Subject: [PATCH 06/22] Run downloader in foreground service --- app/.gitignore | 3 ++- .../tachiyomi/data/download/DownloadService.kt | 18 +++++++++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/app/.gitignore b/app/.gitignore index 90de2b9c8..4f8f315a1 100644 --- a/app/.gitignore +++ b/app/.gitignore @@ -1,4 +1,5 @@ /build *iml *.iml -custom.gradle \ No newline at end of file +custom.gradle +google-services.json diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadService.kt b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadService.kt index ae2cf2111..8fdb4f626 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadService.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadService.kt @@ -1,16 +1,20 @@ package eu.kanade.tachiyomi.data.download +import android.app.Notification import android.app.Service import android.content.Context import android.content.Intent import android.net.NetworkInfo.State.CONNECTED import android.net.NetworkInfo.State.DISCONNECTED +import android.os.Build import android.os.IBinder import android.os.PowerManager +import android.support.v4.app.NotificationCompat import com.github.pwittchen.reactivenetwork.library.Connectivity import com.github.pwittchen.reactivenetwork.library.ReactiveNetwork import com.jakewharton.rxrelay.BehaviorRelay import eu.kanade.tachiyomi.R +import eu.kanade.tachiyomi.data.notification.Notifications import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.util.connectivityManager import eu.kanade.tachiyomi.util.plusAssign @@ -41,7 +45,12 @@ class DownloadService : Service() { * @param context the application context. */ fun start(context: Context) { - context.startService(Intent(context, DownloadService::class.java)) + val intent = Intent(context, DownloadService::class.java) + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { + context.startService(intent) + } else { + context.startForegroundService(intent) + } } /** @@ -81,6 +90,7 @@ class DownloadService : Service() { */ override fun onCreate() { super.onCreate() + startForeground(Notifications.ID_DOWNLOAD_CHAPTER, getPlaceholderNotification()) runningRelay.call(true) subscriptions = CompositeSubscription() listenDownloaderState() @@ -176,4 +186,10 @@ class DownloadService : Service() { if (!isHeld) acquire() } + private fun getPlaceholderNotification(): Notification { + return NotificationCompat.Builder(this, Notifications.CHANNEL_DOWNLOADER) + .setContentTitle(getString(R.string.download_notifier_downloader_title)) + .build() + } + } From f8a03226ee8662e43603bb37050ccb3e804211e6 Mon Sep 17 00:00:00 2001 From: inorichi Date: Sat, 28 Apr 2018 11:10:29 +0200 Subject: [PATCH 07/22] Release v0.7.3 --- app/build.gradle | 4 ++-- app/src/main/res/raw/changelog_release.xml | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 8d58c4a6b..ecd9280df 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -38,8 +38,8 @@ android { minSdkVersion 16 targetSdkVersion 27 testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" - versionCode 35 - versionName "0.7.2" + versionCode 36 + versionName "0.7.3" buildConfigField "String", "COMMIT_COUNT", "\"${getCommitCount()}\"" buildConfigField "String", "COMMIT_SHA", "\"${getGitSha()}\"" diff --git a/app/src/main/res/raw/changelog_release.xml b/app/src/main/res/raw/changelog_release.xml index 916cc7c74..c61969bef 100644 --- a/app/src/main/res/raw/changelog_release.xml +++ b/app/src/main/res/raw/changelog_release.xml @@ -1,5 +1,19 @@ + + Fixed the tracking search layout when there are many results. + + Separate english language into american and british so that dates are formatted according to that locale. + + Added Firebase analytics, for Android API distribution. + + Crop borders for webtoons now has a separate setting. + + The downloader now runs in a foreground service to prevent it from being killed. + + Fixed a few weird crashes. + + Fixed missing downloaded label in chapters screen. From 8874fe973c9cc94c057cd6d5f2d34d5032f92948 Mon Sep 17 00:00:00 2001 From: inorichi Date: Mon, 30 Apr 2018 18:31:31 +0200 Subject: [PATCH 08/22] Bugfixes --- app/build.gradle | 4 ++-- .../tachiyomi/ui/base/presenter/BasePresenter.kt | 10 ++++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index ecd9280df..a816d0742 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -120,7 +120,7 @@ dependencies { implementation 'com.android.support:multidex:1.0.2' - standardImplementation 'com.google.firebase:firebase-core:12.0.1' + standardImplementation 'com.google.firebase:firebase-core:11.8.0' // ReactiveX implementation 'io.reactivex:rxandroid:1.2.1' @@ -155,7 +155,7 @@ dependencies { // Job scheduling implementation 'com.evernote:android-job:1.2.4' - implementation 'com.google.android.gms:play-services-gcm:12.0.1' + implementation 'com.google.android.gms:play-services-gcm:11.8.0' // Changelog implementation 'com.github.gabrielemariotti.changeloglib:changelog:2.1.0' diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/base/presenter/BasePresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/base/presenter/BasePresenter.kt index cfe4191d9..130362f51 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/base/presenter/BasePresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/base/presenter/BasePresenter.kt @@ -1,11 +1,21 @@ package eu.kanade.tachiyomi.ui.base.presenter +import android.os.Bundle import nucleus.presenter.RxPresenter import nucleus.presenter.delivery.Delivery import rx.Observable open class BasePresenter : RxPresenter() { + override fun onCreate(savedState: Bundle?) { + try { + super.onCreate(savedState) + } catch (e: NullPointerException) { + // Swallow this error. This should be fixed in the library but since it's not critical + // (only used by restartables) it should be enough. It saves me a fork. + } + } + /** * Subscribes an observable with [deliverFirst] and adds it to the presenter's lifecycle * subscription list. From 0cf81e6f7aa4e9e66f93fc93ee89fd6c3b8c91e2 Mon Sep 17 00:00:00 2001 From: vchen30 Date: Fri, 4 May 2018 07:35:34 -0700 Subject: [PATCH 09/22] Update README.md (#1341) * Update README.md thought it would be cool to have hyperlinks to the sites * Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index fb06b5cf9..57326c61c 100644 --- a/README.md +++ b/README.md @@ -14,11 +14,11 @@ Features include: * Online reading from sources such as KissManga, MangaFox, [and more](https://github.com/inorichi/tachiyomi-extensions) * Local reading of downloaded manga * Configurable reader with multiple viewers, reading directions and other settings -* MyAnimeList, AniList, and Kitsu support +* [MyAnimeList](https://myanimelist.net/), [AniList](https://anilist.co/), and [Kitsu](https://kitsu.io/explore/anime) support * Categories to organize your library * Light and dark themes * Schedule updating your library for new chapters -* Create backups locally or to your cloud service of choice +* Create backups locally to read offline or to your desired cloud service ## Download Get the app from our [releases page](https://github.com/inorichi/tachiyomi/releases). From 86a599d13ffb03be155be28bf99c3e6dea7bdae9 Mon Sep 17 00:00:00 2001 From: jFields99 <7573219+jfields99@users.noreply.github.com> Date: Fri, 4 May 2018 09:36:06 -0500 Subject: [PATCH 10/22] Added Github link to about. (#1389) * Added Github link to about. * Added github link to About page (Fixed) Fixed based on jogerj's comment in #1389 * Changed Github link to correct URL. * Balanced brackets --- .../tachiyomi/ui/setting/SettingsAboutController.kt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAboutController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAboutController.kt index d36927b1f..e235f9951 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAboutController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAboutController.kt @@ -93,6 +93,15 @@ class SettingsAboutController : SettingsController() { titleRes = R.string.build_time summary = getFormattedBuildTime() } + preference { + title = "Github" + val url = "https://github.com/inorichi/tachiyomi" + summary = url + onClick { + val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url)) + startActivity(intent) + } + } } override fun onDestroyView(view: View) { From 51144aa45e11499f059749c1ea02eb0bf6251cff Mon Sep 17 00:00:00 2001 From: Ken Swenson <2048861+Flat@users.noreply.github.com> Date: Sat, 5 May 2018 08:05:02 -0400 Subject: [PATCH 11/22] Implement Anilist API v2 (closes #1159) (#1383) * Implement Anilist API v2 (closes #1159) Switches to using the Anilist v2 API. Login is now done by implicit grant and tokens are good for one year. Users will need to login again after token expiration. "clientId" on line 289 of AnilistApi.kt should be changed to Tachiyomi's own client ID number. * Code style formatting Revert to kotlin 1.2.30 Use correct client ID Rename AnilistApi.login to AnilistApi.createOAuth to reflect changed implementation Rename json mimetype variable from json to jsonMime for clarity Don't read response if it's ignored Remove unused parameters from api requests * Close netResponse after read * Refactor remote_id into media_id and library_id * DB: Refactor RemoteId Refactor RemoteId into library_id and media_id Implement function to fetch library_id if user is migrating rom APIv1 * Remove logging interceptor * Compatability and sql simplification * Fix score and minor improvements * Revert changes to Kitsu API --- .../tachiyomi/data/backup/BackupManager.kt | 7 +- .../backup/serializer/TrackTypeAdapter.kt | 13 +- .../tachiyomi/data/database/DbOpenHelper.kt | 5 +- .../data/database/mappers/TrackTypeMapping.kt | 9 +- .../tachiyomi/data/database/models/Track.kt | 4 +- .../data/database/models/TrackImpl.kt | 8 +- .../data/database/tables/TrackTable.kt | 10 +- .../data/preference/PreferencesHelper.kt | 2 +- .../tachiyomi/data/track/anilist/Anilist.kt | 114 ++++-- .../data/track/anilist/AnilistApi.kt | 342 ++++++++++++------ .../data/track/anilist/AnilistInterceptor.kt | 26 +- .../data/track/anilist/AnilistModels.kt | 49 ++- .../tachiyomi/data/track/anilist/OAuth.kt | 3 +- .../tachiyomi/data/track/kitsu/Kitsu.kt | 4 +- .../tachiyomi/data/track/kitsu/KitsuApi.kt | 14 +- .../tachiyomi/data/track/kitsu/KitsuModels.kt | 8 +- .../tachiyomi/data/track/model/TrackSearch.kt | 8 +- .../data/track/myanimelist/MyanimelistApi.kt | 14 +- .../ui/setting/AnilistLoginActivity.kt | 7 +- app/src/main/res/values/strings.xml | 1 + 20 files changed, 411 insertions(+), 237 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt index 4fcbafc2f..c58b3e603 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt @@ -402,8 +402,11 @@ class BackupManager(val context: Context, version: Int = CURRENT_VERSION) { for (dbTrack in dbTracks) { if (track.sync_id == dbTrack.sync_id) { // The sync is already in the db, only update its fields - if (track.remote_id != dbTrack.remote_id) { - dbTrack.remote_id = track.remote_id + if (track.media_id != dbTrack.media_id) { + dbTrack.media_id = track.media_id + } + if (track.library_id != dbTrack.library_id) { + dbTrack.library_id = track.library_id } dbTrack.last_chapter_read = Math.max(dbTrack.last_chapter_read, track.last_chapter_read) isInDatabase = true diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/serializer/TrackTypeAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/serializer/TrackTypeAdapter.kt index 6f01fa023..d9f3b8cac 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/serializer/TrackTypeAdapter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/serializer/TrackTypeAdapter.kt @@ -1,5 +1,6 @@ package eu.kanade.tachiyomi.data.backup.serializer +import android.telecom.DisconnectCause.REMOTE import com.github.salomonbrys.kotson.typeAdapter import com.google.gson.TypeAdapter import com.google.gson.stream.JsonToken @@ -11,7 +12,8 @@ import eu.kanade.tachiyomi.data.database.models.TrackImpl object TrackTypeAdapter { private const val SYNC = "s" - private const val REMOTE = "r" + private const val MEDIA = "r" + private const val LIBRARY = "ml" private const val TITLE = "t" private const val LAST_READ = "l" private const val TRACKING_URL = "u" @@ -24,8 +26,10 @@ object TrackTypeAdapter { value(it.title) name(SYNC) value(it.sync_id) - name(REMOTE) - value(it.remote_id) + name(MEDIA) + value(it.media_id) + name(LIBRARY) + value(it.library_id) name(LAST_READ) value(it.last_chapter_read) name(TRACKING_URL) @@ -43,7 +47,8 @@ object TrackTypeAdapter { when (name) { TITLE -> track.title = nextString() SYNC -> track.sync_id = nextInt() - REMOTE -> track.remote_id = nextInt() + MEDIA -> track.media_id = nextInt() + LIBRARY -> track.library_id = nextLong() LAST_READ -> track.last_chapter_read = nextInt() TRACKING_URL -> track.tracking_url = nextString() } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/DbOpenHelper.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/DbOpenHelper.kt index 5330e1ab5..998a5a1a7 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/DbOpenHelper.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/DbOpenHelper.kt @@ -17,7 +17,7 @@ class DbOpenHelper(context: Context) /** * Version of the database. */ - const val DATABASE_VERSION = 6 + const val DATABASE_VERSION = 7 } override fun onCreate(db: SQLiteDatabase) = with(db) { @@ -57,6 +57,9 @@ class DbOpenHelper(context: Context) if (oldVersion < 6) { db.execSQL(TrackTable.addTrackingUrl) } + if (oldVersion < 7) { + db.execSQL(TrackTable.addLibraryId) + } } override fun onConfigure(db: SQLiteDatabase) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/TrackTypeMapping.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/TrackTypeMapping.kt index aaf64f23a..6759316de 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/TrackTypeMapping.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/TrackTypeMapping.kt @@ -13,8 +13,9 @@ import eu.kanade.tachiyomi.data.database.models.Track import eu.kanade.tachiyomi.data.database.models.TrackImpl import eu.kanade.tachiyomi.data.database.tables.TrackTable.COL_ID import eu.kanade.tachiyomi.data.database.tables.TrackTable.COL_LAST_CHAPTER_READ +import eu.kanade.tachiyomi.data.database.tables.TrackTable.COL_LIBRARY_ID import eu.kanade.tachiyomi.data.database.tables.TrackTable.COL_MANGA_ID -import eu.kanade.tachiyomi.data.database.tables.TrackTable.COL_REMOTE_ID +import eu.kanade.tachiyomi.data.database.tables.TrackTable.COL_MEDIA_ID import eu.kanade.tachiyomi.data.database.tables.TrackTable.COL_SCORE import eu.kanade.tachiyomi.data.database.tables.TrackTable.COL_STATUS import eu.kanade.tachiyomi.data.database.tables.TrackTable.COL_SYNC_ID @@ -45,7 +46,8 @@ class TrackPutResolver : DefaultPutResolver() { put(COL_ID, obj.id) put(COL_MANGA_ID, obj.manga_id) put(COL_SYNC_ID, obj.sync_id) - put(COL_REMOTE_ID, obj.remote_id) + put(COL_MEDIA_ID, obj.media_id) + put(COL_LIBRARY_ID, obj.library_id) put(COL_TITLE, obj.title) put(COL_LAST_CHAPTER_READ, obj.last_chapter_read) put(COL_TOTAL_CHAPTERS, obj.total_chapters) @@ -62,7 +64,8 @@ class TrackGetResolver : DefaultGetResolver() { id = cursor.getLong(cursor.getColumnIndex(COL_ID)) manga_id = cursor.getLong(cursor.getColumnIndex(COL_MANGA_ID)) sync_id = cursor.getInt(cursor.getColumnIndex(COL_SYNC_ID)) - remote_id = cursor.getInt(cursor.getColumnIndex(COL_REMOTE_ID)) + media_id = cursor.getInt(cursor.getColumnIndex(COL_MEDIA_ID)) + library_id = cursor.getLong(cursor.getColumnIndex(COL_LIBRARY_ID)) title = cursor.getString(cursor.getColumnIndex(COL_TITLE)) last_chapter_read = cursor.getInt(cursor.getColumnIndex(COL_LAST_CHAPTER_READ)) total_chapters = cursor.getInt(cursor.getColumnIndex(COL_TOTAL_CHAPTERS)) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/models/Track.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/models/Track.kt index 3b883a874..19133e037 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/models/Track.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/models/Track.kt @@ -10,7 +10,9 @@ interface Track : Serializable { var sync_id: Int - var remote_id: Int + var media_id: Int + + var library_id: Long? var title: String diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/models/TrackImpl.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/models/TrackImpl.kt index b7c445168..65f6ec7ab 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/models/TrackImpl.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/models/TrackImpl.kt @@ -8,7 +8,9 @@ class TrackImpl : Track { override var sync_id: Int = 0 - override var remote_id: Int = 0 + override var media_id: Int = 0 + + override var library_id: Long? = null override lateinit var title: String @@ -30,13 +32,13 @@ class TrackImpl : Track { if (manga_id != other.manga_id) return false if (sync_id != other.sync_id) return false - return remote_id == other.remote_id + return media_id == other.media_id } override fun hashCode(): Int { var result = (manga_id xor manga_id.ushr(32)).toInt() result = 31 * result + sync_id - result = 31 * result + remote_id + result = 31 * result + media_id return result } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/tables/TrackTable.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/tables/TrackTable.kt index 79aba5523..82c863fb9 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/tables/TrackTable.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/tables/TrackTable.kt @@ -10,7 +10,9 @@ object TrackTable { const val COL_SYNC_ID = "sync_id" - const val COL_REMOTE_ID = "remote_id" + const val COL_MEDIA_ID = "remote_id" + + const val COL_LIBRARY_ID = "library_id" const val COL_TITLE = "title" @@ -29,7 +31,8 @@ object TrackTable { $COL_ID INTEGER NOT NULL PRIMARY KEY, $COL_MANGA_ID INTEGER NOT NULL, $COL_SYNC_ID INTEGER NOT NULL, - $COL_REMOTE_ID INTEGER NOT NULL, + $COL_MEDIA_ID INTEGER NOT NULL, + $COL_LIBRARY_ID INTEGER, $COL_TITLE TEXT NOT NULL, $COL_LAST_CHAPTER_READ INTEGER NOT NULL, $COL_TOTAL_CHAPTERS INTEGER NOT NULL, @@ -43,4 +46,7 @@ object TrackTable { val addTrackingUrl: String get() = "ALTER TABLE $TABLE ADD COLUMN $COL_TRACKING_URL TEXT DEFAULT ''" + + val addLibraryId: String + get() = "ALTER TABLE $TABLE ADD COLUMN $COL_LIBRARY_ID INTEGER NULL" } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt index cf594838e..f329bd904 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt @@ -119,7 +119,7 @@ class PreferencesHelper(val context: Context) { fun trackToken(sync: TrackService) = rxPrefs.getString(Keys.trackToken(sync.id), "") - fun anilistScoreType() = rxPrefs.getInteger("anilist_score_type", 0) + fun anilistScoreType() = rxPrefs.getString("anilist_score_type", "POINT_10") fun backupsDirectory() = rxPrefs.getString(Keys.backupDirectory, defaultBackupDir.toString()) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/Anilist.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/Anilist.kt index 0b71e3e85..eea78051f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/Anilist.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/Anilist.kt @@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.data.track.anilist import android.content.Context import android.graphics.Color +import com.google.gson.Gson import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.database.models.Track import eu.kanade.tachiyomi.data.preference.getOrDefault @@ -9,6 +10,7 @@ import eu.kanade.tachiyomi.data.track.TrackService import eu.kanade.tachiyomi.data.track.model.TrackSearch import rx.Completable import rx.Observable +import uy.kohesive.injekt.injectLazy class Anilist(private val context: Context, id: Int) : TrackService(id) { @@ -17,24 +19,45 @@ class Anilist(private val context: Context, id: Int) : TrackService(id) { const val COMPLETED = 2 const val ON_HOLD = 3 const val DROPPED = 4 - const val PLAN_TO_READ = 5 + const val PLANNING = 5 + const val REPEATING = 6 const val DEFAULT_STATUS = READING const val DEFAULT_SCORE = 0 + + const val POINT_100 = "POINT_100" + const val POINT_10 = "POINT_10" + const val POINT_10_DECIMAL = "POINT_10_DECIMAL" + const val POINT_5 = "POINT_5" + const val POINT_3 = "POINT_3" } override val name = "AniList" - private val interceptor by lazy { AnilistInterceptor(getPassword()) } + private val gson: Gson by injectLazy() + + private val interceptor by lazy { AnilistInterceptor(this, getPassword()) } private val api by lazy { AnilistApi(client, interceptor) } + private val scorePreference = preferences.anilistScoreType() + + init { + // If the preference is an int from APIv1, logout user to force using APIv2 + try { + scorePreference.get() + } catch (e: ClassCastException) { + logout() + scorePreference.delete() + } + } + override fun getLogo() = R.drawable.al override fun getLogoColor() = Color.rgb(18, 25, 35) override fun getStatusList(): List { - return listOf(READING, COMPLETED, ON_HOLD, DROPPED, PLAN_TO_READ) + return listOf(READING, COMPLETED, ON_HOLD, DROPPED, PLANNING, REPEATING) } override fun getStatus(status: Int): String = with(context) { @@ -43,48 +66,50 @@ class Anilist(private val context: Context, id: Int) : TrackService(id) { COMPLETED -> getString(R.string.completed) ON_HOLD -> getString(R.string.on_hold) DROPPED -> getString(R.string.dropped) - PLAN_TO_READ -> getString(R.string.plan_to_read) + PLANNING -> getString(R.string.plan_to_read) + REPEATING -> getString(R.string.repeating) else -> "" } } override fun getScoreList(): List { - return when (preferences.anilistScoreType().getOrDefault()) { + return when (scorePreference.getOrDefault()) { // 10 point - 0 -> IntRange(0, 10).map(Int::toString) + POINT_10 -> IntRange(0, 10).map(Int::toString) // 100 point - 1 -> IntRange(0, 100).map(Int::toString) + POINT_100 -> IntRange(0, 100).map(Int::toString) // 5 stars - 2 -> IntRange(0, 5).map { "$it ★" } + POINT_5 -> IntRange(0, 5).map { "$it ★" } // Smiley - 3 -> listOf("-", "😦", "😐", "😊") + POINT_3 -> listOf("-", "😦", "😐", "😊") // 10 point decimal - 4 -> IntRange(0, 100).map { (it / 10f).toString() } + POINT_10_DECIMAL -> IntRange(0, 100).map { (it / 10f).toString() } else -> throw Exception("Unknown score type") } } override fun indexToScore(index: Int): Float { - return when (preferences.anilistScoreType().getOrDefault()) { + return when (scorePreference.getOrDefault()) { // 10 point - 0 -> index * 10f + POINT_10 -> index * 10f // 100 point - 1 -> index.toFloat() + POINT_100 -> index.toFloat() // 5 stars - 2 -> index * 20f + POINT_5 -> index * 20f // Smiley - 3 -> index * 30f + POINT_3 -> index * 30f // 10 point decimal - 4 -> index.toFloat() + POINT_10_DECIMAL -> index.toFloat() else -> throw Exception("Unknown score type") } } override fun displayScore(track: Track): String { val score = track.score - return when (preferences.anilistScoreType().getOrDefault()) { - 2 -> "${(score / 20).toInt()} ★" - 3 -> when { + + return when (scorePreference.getOrDefault()) { + POINT_5 -> "${(score / 20).toInt()} ★" + POINT_3 -> when { score == 0f -> "0" score <= 30 -> "😦" score <= 60 -> "😐" @@ -102,15 +127,26 @@ class Anilist(private val context: Context, id: Int) : TrackService(id) { if (track.total_chapters != 0 && track.last_chapter_read == track.total_chapters) { track.status = COMPLETED } + // If user was using API v1 fetch library_id + if (track.library_id == null || track.library_id!! == 0L){ + return api.findLibManga(track, getUsername().toInt()).flatMap { + if (it == null) { + throw Exception("$track not found on user library") + } + track.library_id = it.library_id + api.updateLibManga(track) + } + } return api.updateLibManga(track) } override fun bind(track: Track): Observable { - return api.findLibManga(track, getUsername()) + return api.findLibManga(track, getUsername().toInt()) .flatMap { remoteTrack -> if (remoteTrack != null) { track.copyPersonalFrom(remoteTrack) + track.library_id = remoteTrack.library_id update(track) } else { // Set default fields if it's not found in the list @@ -126,7 +162,7 @@ class Anilist(private val context: Context, id: Int) : TrackService(id) { } override fun refresh(track: Track): Observable { - return api.getLibManga(track, getUsername()) + return api.getLibManga(track, getUsername().toInt()) .map { remoteTrack -> track.copyPersonalFrom(remoteTrack) track.total_chapters = remoteTrack.total_chapters @@ -136,26 +172,34 @@ class Anilist(private val context: Context, id: Int) : TrackService(id) { override fun login(username: String, password: String) = login(password) - fun login(authCode: String): Completable { - return api.login(authCode) - // Save the token in the interceptor. - .doOnNext { interceptor.setAuth(it) } - // Obtain the authenticated user from the API. - .zipWith(api.getCurrentUser().map { pair -> - preferences.anilistScoreType().set(pair.second) - pair.first - }, { oauth, user -> Pair(user, oauth.refresh_token!!) }) - // Save service credentials (username and refresh token). - .doOnNext { saveCredentials(it.first, it.second) } - // Logout on any error. - .doOnError { logout() } - .toCompletable() + fun login(token: String): Completable { + val oauth = api.createOAuth(token) + interceptor.setAuth(oauth) + return api.getCurrentUser().map { (username, scoreType) -> + scorePreference.set(scoreType) + saveCredentials(username.toString(), oauth.access_token) + }.doOnError{ + logout() + }.toCompletable() } override fun logout() { super.logout() + preferences.trackToken(this).set(null) interceptor.setAuth(null) } + fun saveOAuth(oAuth: OAuth?) { + preferences.trackToken(this).set(gson.toJson(oAuth)) + } + + fun loadOAuth(): OAuth? { + return try { + gson.fromJson(preferences.trackToken(this).get(), OAuth::class.java) + } catch (e: Exception) { + null + } + } + } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistApi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistApi.kt index ee2864352..37d1eb14a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistApi.kt @@ -1,167 +1,275 @@ package eu.kanade.tachiyomi.data.track.anilist import android.net.Uri -import com.github.salomonbrys.kotson.int -import com.github.salomonbrys.kotson.string +import com.github.salomonbrys.kotson.* import com.google.gson.JsonObject +import com.google.gson.JsonParser import eu.kanade.tachiyomi.data.database.models.Track import eu.kanade.tachiyomi.data.track.model.TrackSearch -import eu.kanade.tachiyomi.network.POST -import okhttp3.FormBody +import eu.kanade.tachiyomi.network.asObservableSuccess +import okhttp3.MediaType import okhttp3.OkHttpClient -import okhttp3.ResponseBody -import retrofit2.Response -import retrofit2.Retrofit -import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory -import retrofit2.converter.gson.GsonConverterFactory -import retrofit2.http.* +import okhttp3.Request +import okhttp3.RequestBody import rx.Observable + class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) { - private val rest = restBuilder() - .client(client.newBuilder().addInterceptor(interceptor).build()) - .build() - .create(Rest::class.java) + private val parser = JsonParser() + private val jsonMime = MediaType.parse("application/json; charset=utf-8") + private val authClient = client.newBuilder().addInterceptor(interceptor).build() + fun addLibManga(track: Track): Observable { - return rest.addLibManga(track.remote_id, track.last_chapter_read, track.toAnilistStatus()) - .map { response -> - response.body()?.close() - if (!response.isSuccessful) { - throw Exception("Could not add manga") + val query = """ + mutation AddManga(${'$'}mangaId: Int, ${'$'}progress: Int, ${'$'}status: MediaListStatus) { + SaveMediaListEntry (mediaId: ${'$'}mangaId, progress: ${'$'}progress, status: ${'$'}status) + { id status } } + """ + val variables = jsonObject( + "mangaId" to track.media_id, + "progress" to track.last_chapter_read, + "status" to track.toAnilistStatus() + ) + val payload = jsonObject( + "query" to query, + "variables" to variables + ) + val body = RequestBody.create(jsonMime, payload.toString()) + val request = Request.Builder() + .url(apiUrl) + .post(body) + .build() + return authClient.newCall(request) + .asObservableSuccess() + .map { netResponse -> + val responseBody = netResponse.body()?.string().orEmpty() + netResponse.close() + if (responseBody.isEmpty()) { + throw Exception("Null Response") } + val response = parser.parse(responseBody).obj + track.library_id = response["data"]["SaveMediaListEntry"]["id"].asLong track } } fun updateLibManga(track: Track): Observable { - return rest.updateLibManga(track.remote_id, track.last_chapter_read, track.toAnilistStatus(), - track.toAnilistScore()) - .map { response -> - response.body()?.close() - if (!response.isSuccessful) { - throw Exception("Could not update manga") + val query = """ + mutation UpdateManga(${'$'}listId: Int, ${'$'}progress: Int, ${'$'}status: MediaListStatus, ${'$'}score: Int) { + SaveMediaListEntry (id: ${'$'}listId, progress: ${'$'}progress, status: ${'$'}status, scoreRaw: ${'$'}score) { + id + status + progress + } } + """ + val variables = jsonObject( + "listId" to track.library_id, + "progress" to track.last_chapter_read, + "status" to track.toAnilistStatus(), + "score" to track.score.toInt() + ) + val payload = jsonObject( + "query" to query, + "variables" to variables + ) + val body = RequestBody.create(jsonMime, payload.toString()) + val request = Request.Builder() + .url(apiUrl) + .post(body) + .build() + return authClient.newCall(request) + .asObservableSuccess() + .map { track } } - fun search(query: String): Observable> { - return rest.search(query, 1) - .map { list -> - list.filter { it.type != "Novel" }.map { it.toTrack() } + fun search(search: String): Observable> { + val query = """ + query Search(${'$'}query: String) { + Page (perPage: 25) { + media(search: ${'$'}query, type: MANGA, format: MANGA) { + id + title { + romaji + } + coverImage { + large + } + type + status + chapters + startDate { + year + month + day + } + } + } } - .onErrorReturn { emptyList() } - } - - fun getList(username: String): Observable> { - return rest.getLib(username) - .map { lib -> - lib.flatten().map { it.toTrack() } + """ + val variables = jsonObject( + "query" to search + ) + val payload = jsonObject( + "query" to query, + "variables" to variables + ) + val body = RequestBody.create(jsonMime, payload.toString()) + val request = Request.Builder() + .url(apiUrl) + .post(body) + .build() + return authClient.newCall(request) + .asObservableSuccess() + .map { netResponse -> + val responseBody = netResponse.body()?.string().orEmpty() + if (responseBody.isEmpty()) { + throw Exception("Null Response") + } + val response = parser.parse(responseBody).obj + val data = response["data"]!!.obj + val page = data["Page"].obj + val media = page["media"].array + val entries = media.map { jsonToALManga(it.obj) } + entries.map { it.toTrack() } } } - fun findLibManga(track: Track, username: String) : Observable { - // TODO avoid getting the entire list - return getList(username) - .map { list -> list.find { it.remote_id == track.remote_id } } + + fun findLibManga(track: Track, userid: Int) : Observable { + val query = """ + query (${'$'}id: Int!, ${'$'}manga_id: Int!) { + Page { + mediaList(userId: ${'$'}id, type: MANGA, mediaId: ${'$'}manga_id) { + id + status + scoreRaw: score(format: POINT_100) + progress + media{ + id + title { + romaji + } + coverImage { + large + } + type + status + chapters + startDate { + year + month + day + } + } + } + } + } + """ + val variables = jsonObject( + "id" to userid, + "manga_id" to track.media_id + ) + val payload = jsonObject( + "query" to query, + "variables" to variables + ) + val body = RequestBody.create(jsonMime, payload.toString()) + val request = Request.Builder() + .url(apiUrl) + .post(body) + .build() + return authClient.newCall(request) + .asObservableSuccess() + .map { netResponse -> + val responseBody = netResponse.body()?.string().orEmpty() + if (responseBody.isEmpty()) { + throw Exception("Null Response") + } + val response = parser.parse(responseBody).obj + val data = response["data"]!!.obj + val page = data["Page"].obj + val media = page["mediaList"].array + val entries = media.map { jsonToALUserManga(it.obj) } + entries.firstOrNull()?.toTrack() + + } } - fun getLibManga(track: Track, username: String): Observable { - return findLibManga(track, username) + fun getLibManga(track: Track, userid: Int): Observable { + return findLibManga(track, userid) .map { it ?: throw Exception("Could not find manga") } } - fun login(authCode: String): Observable { - return restBuilder() - .client(client) + fun createOAuth(token: String): OAuth { + return OAuth(token, "Bearer", System.currentTimeMillis() + 31536000000, 31536000000) + } + + fun getCurrentUser(): Observable> { + val query = """ + query User + { + Viewer { + id + mediaListOptions { + scoreFormat + } + } + } + """ + val payload = jsonObject( + "query" to query + ) + val body = RequestBody.create(jsonMime, payload.toString()) + val request = Request.Builder() + .url(apiUrl) + .post(body) .build() - .create(Rest::class.java) - .requestAccessToken(authCode) + return authClient.newCall(request) + .asObservableSuccess() + .map { netResponse -> + val responseBody = netResponse.body()?.string().orEmpty() + if (responseBody.isEmpty()) { + throw Exception("Null Response") + } + val response = parser.parse(responseBody).obj + val data = response["data"]!!.obj + val viewer = data["Viewer"].obj + Pair(viewer["id"].asInt, viewer["mediaListOptions"]["scoreFormat"].asString) + } } - fun getCurrentUser(): Observable> { - return rest.getCurrentUser() - .map { it["id"].string to it["score_type"].int } + fun jsonToALManga(struct: JsonObject): ALManga{ + return ALManga(struct["id"].asInt, struct["title"]["romaji"].asString, struct["coverImage"]["large"].asString, + null, struct["type"].asString, struct["status"].asString, + struct["startDate"]["year"].nullString.orEmpty() + struct["startDate"]["month"].nullString.orEmpty() + + struct["startDate"]["day"].nullString.orEmpty(), struct["chapters"].nullInt ?: 0) } - private fun restBuilder() = Retrofit.Builder() - .baseUrl(baseUrl) - .addConverterFactory(GsonConverterFactory.create()) - .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) - - private interface Rest { - - @FormUrlEncoded - @POST("auth/access_token") - fun requestAccessToken( - @Field("code") code: String, - @Field("grant_type") grant_type: String = "authorization_code", - @Field("client_id") client_id: String = clientId, - @Field("client_secret") client_secret: String = clientSecret, - @Field("redirect_uri") redirect_uri: String = clientUrl - ) : Observable - - @GET("user") - fun getCurrentUser(): Observable - - @GET("manga/search/{query}") - fun search( - @Path("query") query: String, - @Query("page") page: Int - ): Observable> - - @GET("user/{username}/mangalist") - fun getLib( - @Path("username") username: String - ): Observable - - @FormUrlEncoded - @PUT("mangalist") - fun addLibManga( - @Field("id") id: Int, - @Field("chapters_read") chapters_read: Int, - @Field("list_status") list_status: String - ) : Observable> - - @FormUrlEncoded - @PUT("mangalist") - fun updateLibManga( - @Field("id") id: Int, - @Field("chapters_read") chapters_read: Int, - @Field("list_status") list_status: String, - @Field("score") score_raw: String - ) : Observable> - + fun jsonToALUserManga(struct: JsonObject): ALUserManga{ + return ALUserManga(struct["id"].asLong, struct["status"].asString, struct["scoreRaw"].asInt, struct["progress"].asInt, jsonToALManga(struct["media"].obj) ) } + companion object { - private const val clientId = "tachiyomi-hrtje" - private const val clientSecret = "nlGB5OmgE9YWq5dr3gIDbTQV0C" + private const val clientId = "385" private const val clientUrl = "tachiyomi://anilist-auth" - private const val baseUrl = "https://anilist.co/api/" + private const val apiUrl = "https://graphql.anilist.co/" + private const val baseUrl = "https://anilist.co/api/v2/" private const val baseMangaUrl = "https://anilist.co/manga/" - fun mangaUrl(remoteId: Int): String { - return baseMangaUrl + remoteId + fun mangaUrl(mediaId: Int): String { + return baseMangaUrl + mediaId } - fun authUrl() = Uri.parse("${baseUrl}auth/authorize").buildUpon() - .appendQueryParameter("grant_type", "authorization_code") + fun authUrl() = Uri.parse("${baseUrl}oauth/authorize").buildUpon() .appendQueryParameter("client_id", clientId) - .appendQueryParameter("redirect_uri", clientUrl) - .appendQueryParameter("response_type", "code") + .appendQueryParameter("response_type", "token") .build() - - fun refreshTokenRequest(token: String) = POST("${baseUrl}auth/access_token", - body = FormBody.Builder() - .add("grant_type", "refresh_token") - .add("client_id", clientId) - .add("client_secret", clientSecret) - .add("refresh_token", token) - .build()) - } -} \ No newline at end of file +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistInterceptor.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistInterceptor.kt index 2bb8525d3..427b0acfe 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistInterceptor.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistInterceptor.kt @@ -1,10 +1,10 @@ package eu.kanade.tachiyomi.data.track.anilist -import com.google.gson.Gson import okhttp3.Interceptor import okhttp3.Response -class AnilistInterceptor(private var refreshToken: String?) : Interceptor { + +class AnilistInterceptor(val anilist: Anilist, private var token: String?) : Interceptor { /** * OAuth object used for authenticated requests. @@ -20,24 +20,21 @@ class AnilistInterceptor(private var refreshToken: String?) : Interceptor { override fun intercept(chain: Interceptor.Chain): Response { val originalRequest = chain.request() - if (refreshToken.isNullOrEmpty()) { + if (token.isNullOrEmpty()) { throw Exception("Not authenticated with Anilist") } - + if (oauth == null){ + oauth = anilist.loadOAuth() + } // Refresh access token if null or expired. - if (oauth == null || oauth!!.isExpired()) { - val response = chain.proceed(AnilistApi.refreshTokenRequest(refreshToken!!)) - oauth = if (response.isSuccessful) { - Gson().fromJson(response.body()!!.string(), OAuth::class.java) - } else { - response.close() - null - } + if (oauth!!.isExpired()) { + anilist.logout() + throw Exception("Token expired") } // Throw on null auth. if (oauth == null) { - throw Exception("Access token wasn't refreshed") + throw Exception("No authentication token") } // Add the authorization header to the original request. @@ -53,8 +50,9 @@ class AnilistInterceptor(private var refreshToken: String?) : Interceptor { * and the oauth object. */ fun setAuth(oauth: OAuth?) { - refreshToken = oauth?.refresh_token + token = oauth?.access_token this.oauth = oauth + anilist.saveOAuth(oauth) } } \ No newline at end of file diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistModels.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistModels.kt index 8398477dc..3083f3b69 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistModels.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistModels.kt @@ -11,7 +11,7 @@ import java.text.SimpleDateFormat import java.util.* data class ALManga( - val id: Int, + val media_id: Int, val title_romaji: String, val image_url_lge: String, val description: String?, @@ -21,12 +21,12 @@ data class ALManga( val total_chapters: Int) { fun toTrack() = TrackSearch.create(TrackManager.ANILIST).apply { - remote_id = this@ALManga.id + media_id = this@ALManga.media_id title = title_romaji total_chapters = this@ALManga.total_chapters cover_url = image_url_lge summary = description ?: "" - tracking_url = AnilistApi.mangaUrl(remote_id) + tracking_url = AnilistApi.mangaUrl(media_id) publishing_status = this@ALManga.publishing_status publishing_type = type if (!start_date_fuzzy.isNullOrBlank()) { @@ -43,40 +43,37 @@ data class ALManga( } data class ALUserManga( - val id: Int, + val library_id: Long, val list_status: String, val score_raw: Int, val chapters_read: Int, val manga: ALManga) { fun toTrack() = Track.create(TrackManager.ANILIST).apply { - remote_id = manga.id + media_id = manga.media_id status = toTrackStatus() score = score_raw.toFloat() last_chapter_read = chapters_read + library_id = this@ALUserManga.library_id } fun toTrackStatus() = when (list_status) { - "reading" -> Anilist.READING - "completed" -> Anilist.COMPLETED - "on-hold" -> Anilist.ON_HOLD - "dropped" -> Anilist.DROPPED - "plan to read" -> Anilist.PLAN_TO_READ + "CURRENT" -> Anilist.READING + "COMPLETED" -> Anilist.COMPLETED + "PAUSED" -> Anilist.ON_HOLD + "DROPPED" -> Anilist.DROPPED + "PLANNING" -> Anilist.PLANNING else -> throw NotImplementedError("Unknown status") } } -data class ALUserLists(val lists: Map>) { - - fun flatten() = lists.values.flatten() -} - fun Track.toAnilistStatus() = when (status) { - Anilist.READING -> "reading" - Anilist.COMPLETED -> "completed" - Anilist.ON_HOLD -> "on-hold" - Anilist.DROPPED -> "dropped" - Anilist.PLAN_TO_READ -> "plan to read" + Anilist.READING -> "CURRENT" + Anilist.COMPLETED -> "COMPLETED" + Anilist.ON_HOLD -> "PAUSED" + Anilist.DROPPED -> "DROPPED" + Anilist.PLANNING -> "PLANNING" + Anilist.REPEATING -> "REPEATING" else -> throw NotImplementedError("Unknown status") } @@ -84,11 +81,11 @@ private val preferences: PreferencesHelper by injectLazy() fun Track.toAnilistScore(): String = when (preferences.anilistScoreType().getOrDefault()) { // 10 point - 0 -> (score.toInt() / 10).toString() + "POINT_10" -> (score.toInt() / 10).toString() // 100 point - 1 -> score.toInt().toString() + "POINT_100" -> score.toInt().toString() // 5 stars - 2 -> when { + "POINT_5" -> when { score == 0f -> "0" score < 30 -> "1" score < 50 -> "2" @@ -97,13 +94,13 @@ fun Track.toAnilistScore(): String = when (preferences.anilistScoreType().getOrD else -> "5" } // Smiley - 3 -> when { + "POINT_3" -> when { score == 0f -> "0" score <= 30 -> ":(" score <= 60 -> ":|" else -> ":)" } // 10 point decimal - 4 -> (score / 10).toString() + "POINT_10_DECIMAL" -> (score / 10).toString() else -> throw Exception("Unknown score type") -} \ No newline at end of file +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/OAuth.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/OAuth.kt index 6f5238b37..1d7a31ac5 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/OAuth.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/OAuth.kt @@ -4,8 +4,7 @@ data class OAuth( val access_token: String, val token_type: String, val expires: Long, - val expires_in: Long, - val refresh_token: String?) { + val expires_in: Long) { fun isExpired() = System.currentTimeMillis() > expires } \ No newline at end of file diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/Kitsu.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/Kitsu.kt index c7f4f94dd..14be0ddb7 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/Kitsu.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/Kitsu.kt @@ -87,7 +87,7 @@ class Kitsu(private val context: Context, id: Int) : TrackService(id) { .flatMap { remoteTrack -> if (remoteTrack != null) { track.copyPersonalFrom(remoteTrack) - track.remote_id = remoteTrack.remote_id + track.media_id = remoteTrack.media_id update(track) } else { track.score = DEFAULT_SCORE @@ -141,4 +141,4 @@ class Kitsu(private val context: Context, id: Int) : TrackService(id) { } } -} \ No newline at end of file +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuApi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuApi.kt index 03226896e..9d16ddb5b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuApi.kt @@ -42,7 +42,7 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor) ), "media" to jsonObject( "data" to jsonObject( - "id" to track.remote_id, + "id" to track.media_id, "type" to "manga" ) ) @@ -52,7 +52,7 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor) rest.addLibManga(jsonObject("data" to data)) .map { json -> - track.remote_id = json["data"]["id"].int + track.media_id = json["data"]["id"].int track } } @@ -63,7 +63,7 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor) // @formatter:off val data = jsonObject( "type" to "libraryEntries", - "id" to track.remote_id, + "id" to track.media_id, "attributes" to jsonObject( "status" to track.toKitsuStatus(), "progress" to track.last_chapter_read, @@ -72,7 +72,7 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor) ) // @formatter:on - rest.updateLibManga(track.remote_id, jsonObject("data" to data)) + rest.updateLibManga(track.media_id, jsonObject("data" to data)) .map { track } } } @@ -88,7 +88,7 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor) } fun findLibManga(track: Track, userId: String): Observable { - return rest.findLibManga(track.remote_id, userId) + return rest.findLibManga(track.media_id, userId) .map { json -> val data = json["data"].array if (data.size() > 0) { @@ -101,7 +101,7 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor) } fun getLibManga(track: Track): Observable { - return rest.getLibManga(track.remote_id) + return rest.getLibManga(track.media_id) .map { json -> val data = json["data"].array if (data.size() > 0) { @@ -204,4 +204,4 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor) } -} \ No newline at end of file +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuModels.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuModels.kt index be4ca5034..70fdef6d9 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuModels.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuModels.kt @@ -19,12 +19,12 @@ open class KitsuManga(obj: JsonObject) { @CallSuper open fun toTrack() = TrackSearch.create(TrackManager.KITSU).apply { - remote_id = this@KitsuManga.id + media_id = this@KitsuManga.id title = canonicalTitle total_chapters = chapterCount ?: 0 cover_url = original summary = synopsis - tracking_url = KitsuApi.mangaUrl(remote_id) + tracking_url = KitsuApi.mangaUrl(media_id) publishing_status = this@KitsuManga.status publishing_type = type start_date = startDate.orEmpty() @@ -32,13 +32,13 @@ open class KitsuManga(obj: JsonObject) { } class KitsuLibManga(obj: JsonObject, manga: JsonObject) : KitsuManga(manga) { - val remoteId by obj.byInt("id") + val libraryId by obj.byInt("id") override val status by obj["attributes"].byString val ratingTwenty = obj["attributes"].obj.get("ratingTwenty").nullString val progress by obj["attributes"].byInt override fun toTrack() = super.toTrack().apply { - remote_id = remoteId + media_id = libraryId // TODO migrate media ids to library ids status = toTrackStatus() score = ratingTwenty?.let { it.toInt() / 2f } ?: 0f last_chapter_read = progress diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/model/TrackSearch.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/model/TrackSearch.kt index 0e701730f..a7fb8b80d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/model/TrackSearch.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/model/TrackSearch.kt @@ -10,7 +10,9 @@ class TrackSearch : Track { override var sync_id: Int = 0 - override var remote_id: Int = 0 + override var media_id: Int = 0 + + override var library_id: Long? = null override lateinit var title: String @@ -42,13 +44,13 @@ class TrackSearch : Track { if (manga_id != other.manga_id) return false if (sync_id != other.sync_id) return false - return remote_id == other.remote_id + return media_id == other.media_id } override fun hashCode(): Int { var result = (manga_id xor manga_id.ushr(32)).toInt() result = 31 * result + sync_id - result = 31 * result + remote_id + result = 31 * result + media_id return result } companion object { diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyanimelistApi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyanimelistApi.kt index 392ff220b..16c9269aa 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyanimelistApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/myanimelist/MyanimelistApi.kt @@ -54,11 +54,11 @@ class MyanimelistApi(private val client: OkHttpClient, username: String, passwor .map { TrackSearch.create(TrackManager.MYANIMELIST).apply { title = it.selectText("title")!! - remote_id = it.selectInt("id") + media_id = it.selectInt("id") total_chapters = it.selectInt("chapters") summary = it.selectText("synopsis")!! cover_url = it.selectText("image")!! - tracking_url = MyanimelistApi.mangaUrl(remote_id) + tracking_url = MyanimelistApi.mangaUrl(media_id) publishing_status = it.selectText("status")!! publishing_type = it.selectText("type")!! start_date = it.selectText("start_date")!! @@ -77,13 +77,13 @@ class MyanimelistApi(private val client: OkHttpClient, username: String, passwor .map { TrackSearch.create(TrackManager.MYANIMELIST).apply { title = it.selectText("series_title")!! - remote_id = it.selectInt("series_mangadb_id") + media_id = it.selectInt("series_mangadb_id") last_chapter_read = it.selectInt("my_read_chapters") status = it.selectInt("my_status") score = it.selectInt("my_score").toFloat() total_chapters = it.selectInt("series_chapters") cover_url = it.selectText("series_image")!! - tracking_url = MyanimelistApi.mangaUrl(remote_id) + tracking_url = MyanimelistApi.mangaUrl(media_id) } } .toList() @@ -91,7 +91,7 @@ class MyanimelistApi(private val client: OkHttpClient, username: String, passwor fun findLibManga(track: Track, username: String): Observable { return getList(username) - .map { list -> list.find { it.remote_id == track.remote_id } } + .map { list -> list.find { it.media_id == track.media_id } } } fun getLibManga(track: Track, username: String): Observable { @@ -169,12 +169,12 @@ class MyanimelistApi(private val client: OkHttpClient, username: String, passwor fun getUpdateUrl(track: Track) = Uri.parse(baseUrl).buildUpon() .appendEncodedPath("api/mangalist/update") - .appendPath("${track.remote_id}.xml") + .appendPath("${track.media_id}.xml") .toString() fun getAddUrl(track: Track) = Uri.parse(baseUrl).buildUpon() .appendEncodedPath("api/mangalist/add") - .appendPath("${track.remote_id}.xml") + .appendPath("${track.media_id}.xml") .toString() fun createHeaders(username: String, password: String): Headers { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/AnilistLoginActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/AnilistLoginActivity.kt index 982e74fe1..6b5da186e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/AnilistLoginActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/AnilistLoginActivity.kt @@ -23,9 +23,10 @@ class AnilistLoginActivity : AppCompatActivity() { val view = ProgressBar(this) setContentView(view, FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT, CENTER)) - val code = intent.data?.getQueryParameter("code") - if (code != null) { - trackManager.aniList.login(code) + val regex = "(?:access_token=)(.*?)(?:&)".toRegex() + val matchResult = regex.find(intent.data?.fragment.toString()) + if (matchResult?.groups?.get(1) != null) { + trackManager.aniList.login(matchResult.groups[1]!!.value) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe({ diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c4ef4bfb4..5ae68a606 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -385,6 +385,7 @@ Dropped On hold Plan to read + Re-reading Score Title Status From 345f96055d61985b329f24aaee5251a713f4f6b7 Mon Sep 17 00:00:00 2001 From: inorichi Date: Sat, 5 May 2018 14:23:34 +0200 Subject: [PATCH 12/22] Fix indonesian language. Closes #1387 --- .../eu/kanade/tachiyomi/ui/setting/SettingsGeneralController.kt | 2 +- app/src/main/res/{values-id => values-in}/strings.xml | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename app/src/main/res/{values-id => values-in}/strings.xml (100%) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsGeneralController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsGeneralController.kt index a4611da39..464d59831 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsGeneralController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsGeneralController.kt @@ -30,7 +30,7 @@ class SettingsGeneralController : SettingsController() { key = Keys.lang titleRes = R.string.pref_language entryValues = arrayOf("", "ar", "bg", "bn", "de", "en-US", "en-GB", "es", "fr", "hi", - "hu", "id", "it", "ja", "ko", "lv", "ms", "nl", "pl", "pt", "pt-BR", "ro", + "hu", "in", "it", "ja", "ko", "lv", "ms", "nl", "pl", "pt", "pt-BR", "ro", "ru", "vi") entries = entryValues.map { value -> val locale = LocaleHelper.getLocaleFromString(value.toString()) diff --git a/app/src/main/res/values-id/strings.xml b/app/src/main/res/values-in/strings.xml similarity index 100% rename from app/src/main/res/values-id/strings.xml rename to app/src/main/res/values-in/strings.xml From 263198dd89a4c81813ae38ce6868415b2b0efb23 Mon Sep 17 00:00:00 2001 From: inorichi Date: Sat, 5 May 2018 15:29:08 +0200 Subject: [PATCH 13/22] Minor fix --- .../main/java/eu/kanade/tachiyomi/ui/catalogue/LangHolder.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/LangHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/LangHolder.kt index 9604e7340..66c94967d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/LangHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/LangHolder.kt @@ -7,9 +7,9 @@ import eu.kanade.tachiyomi.util.LocaleHelper import kotlinx.android.synthetic.main.catalogue_main_controller_card.* class LangHolder(view: View, adapter: FlexibleAdapter<*>) : - BaseFlexibleViewHolder(view, adapter, true) { + BaseFlexibleViewHolder(view, adapter) { fun bind(item: LangItem) { title.text = LocaleHelper.getDisplayName(item.code, itemView.context) } -} \ No newline at end of file +} From 75fc16020422fed9a4e1848053fb7798c9ece439 Mon Sep 17 00:00:00 2001 From: inorichi Date: Sat, 5 May 2018 15:44:17 +0200 Subject: [PATCH 14/22] Update okhttp version --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index a816d0742..e77516719 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -130,7 +130,7 @@ dependencies { implementation 'com.github.pwittchen:reactivenetwork:0.7.0' // Network client - implementation "com.squareup.okhttp3:okhttp:3.9.1" + implementation "com.squareup.okhttp3:okhttp:3.10.0" implementation 'com.squareup.okio:okio:1.14.0' // REST From c6245f4fa3431e8dbbb1de618214d82dbe7910d4 Mon Sep 17 00:00:00 2001 From: inorichi Date: Fri, 11 May 2018 15:08:12 +0200 Subject: [PATCH 15/22] Reenable cipher suites after upgrading to okhttp 3.10. Fixes #1411 --- app/build.gradle | 2 +- .../eu/kanade/tachiyomi/network/NetworkHelper.kt | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index e77516719..f3faa0394 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -154,7 +154,7 @@ dependencies { implementation 'org.jsoup:jsoup:1.10.2' // Job scheduling - implementation 'com.evernote:android-job:1.2.4' + implementation 'com.evernote:android-job:1.2.5' implementation 'com.google.android.gms:play-services-gcm:11.8.0' // Changelog diff --git a/app/src/main/java/eu/kanade/tachiyomi/network/NetworkHelper.kt b/app/src/main/java/eu/kanade/tachiyomi/network/NetworkHelper.kt index 97d4b4d7d..5e9389483 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/network/NetworkHelper.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/network/NetworkHelper.kt @@ -3,7 +3,10 @@ package eu.kanade.tachiyomi.network import android.content.Context import android.os.Build import okhttp3.Cache +import okhttp3.CipherSuite +import okhttp3.ConnectionSpec import okhttp3.OkHttpClient +import okhttp3.TlsVersion import java.io.File import java.io.IOException import java.net.InetAddress @@ -108,6 +111,18 @@ class NetworkHelper(context: Context) { sslSocketFactory(TLSSocketFactory(), trustManagers[0] as X509TrustManager) } + val specCompat = ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS) + .tlsVersions(TlsVersion.TLS_1_2, TlsVersion.TLS_1_1, TlsVersion.TLS_1_0) + .cipherSuites( + *ConnectionSpec.MODERN_TLS.cipherSuites().orEmpty().toTypedArray(), + CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, + CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA + ) + .build() + + val specs = listOf(specCompat, ConnectionSpec.CLEARTEXT) + connectionSpecs(specs) + return this } } From 9abce0cca3136555d5997d7aa5443c1b0d5ae94e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jozef=20Holl=C3=BD?= Date: Sun, 13 May 2018 11:36:08 +0200 Subject: [PATCH 16/22] Vanity url (#1408) * vanity url * vanity url * vanity url --- .github/CONTRIBUTING.md | 2 +- README.md | 4 ++-- .../eu/kanade/tachiyomi/ui/setting/SettingsAboutController.kt | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index b77cf7f29..2d08379f9 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -1,5 +1,5 @@ 1. **Before reporting a new issue, take a look at the [FAQ](https://github.com/inorichi/tachiyomi/wiki/FAQ), the [changelog](https://github.com/inorichi/tachiyomi/releases) and the already opened [issues](https://github.com/inorichi/tachiyomi/issues).** -2. If you are unsure, ask here: [![Discord](https://img.shields.io/discord/349436576037732353.svg)](https://discord.gg/WrBkRk4) +2. If you are unsure, ask here: [![Discord](https://img.shields.io/discord/349436576037732353.svg)](https://discord.gg/tachiyomi) 3. What is your type of issue? * [Catalogue request](#catalogue-requests) * [Bugs](#bugs) diff --git a/README.md b/README.md index 57326c61c..6b2fd3baa 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ | Build | Stable | Dev | Contribute | Contact | |-------|----------|---------|------------|---------| -| [![Travis](https://img.shields.io/travis/inorichi/tachiyomi.svg)](https://travis-ci.org/inorichi/tachiyomi) | [![stable release](https://img.shields.io/github/release/inorichi/tachiyomi.svg?maxAge=3600&label=download%20(autoupdate%20included))](https://github.com/inorichi/tachiyomi/releases) | [![latest dev build](https://img.shields.io/badge/download-latest%20build-blue.svg)](http://tachiyomi.kanade.eu/latest) [![fdroid dev](https://img.shields.io/badge/autoupdate-wiki-blue.svg)](//github.com/inorichi/tachiyomi/wiki/F-Droid-for-dev-versions) | [![Translation status](https://hosted.weblate.org/widgets/tachiyomi/-/svg-badge.svg)](https://hosted.weblate.org/engage/tachiyomi/?utm_source=widget) | [![Discord](https://img.shields.io/discord/349436576037732353.svg)](https://discord.gg/2dDQBv2) | +| [![Travis](https://img.shields.io/travis/inorichi/tachiyomi.svg)](https://travis-ci.org/inorichi/tachiyomi) | [![stable release](https://img.shields.io/github/release/inorichi/tachiyomi.svg?maxAge=3600&label=download%20(autoupdate%20included))](https://github.com/inorichi/tachiyomi/releases) | [![latest dev build](https://img.shields.io/badge/download-latest%20build-blue.svg)](http://tachiyomi.kanade.eu/latest) [![fdroid dev](https://img.shields.io/badge/autoupdate-wiki-blue.svg)](//github.com/inorichi/tachiyomi/wiki/F-Droid-for-dev-versions) | [![Translation status](https://hosted.weblate.org/widgets/tachiyomi/-/svg-badge.svg)](https://hosted.weblate.org/engage/tachiyomi/?utm_source=widget) | [![Discord](https://img.shields.io/discord/349436576037732353.svg)](https://discord.gg/tachiyomi) | # ![app icon](./.github/readme-images/app-icon.png)Tachiyomi @@ -32,7 +32,7 @@ Please make sure to read the full guidelines. Your issue may be closed without w

Issues 1. **Before reporting a new issue, take a look at the [FAQ](https://github.com/inorichi/tachiyomi/wiki/FAQ), the [changelog](https://github.com/inorichi/tachiyomi/releases) and the already opened [issues](https://github.com/inorichi/tachiyomi/issues).** -2. If you are unsure, ask here: [![Discord](https://img.shields.io/discord/349436576037732353.svg)](https://discord.gg/WrBkRk4) +2. If you are unsure, ask here: [![Discord](https://img.shields.io/discord/349436576037732353.svg)](https://discord.gg/tachiyomi)
diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAboutController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAboutController.kt index e235f9951..a39a66f54 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAboutController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAboutController.kt @@ -71,7 +71,7 @@ class SettingsAboutController : SettingsController() { } preference { title = "Discord" - val url = "https://discord.gg/2dDQBv2" + val url = "https://discord.gg/tachiyomi" summary = url onClick { val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url)) From 9d5cf9163a104bac7aed1674212fa5882c7a1c45 Mon Sep 17 00:00:00 2001 From: inorichi Date: Sun, 13 May 2018 11:56:24 +0200 Subject: [PATCH 17/22] Release v0.7.4 --- app/build.gradle | 4 +- .../ui/setting/SettingsAboutController.kt | 21 ++++--- app/src/main/res/raw/changelog_release.xml | 62 ++++--------------- 3 files changed, 25 insertions(+), 62 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index f3faa0394..4c064f491 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -38,8 +38,8 @@ android { minSdkVersion 16 targetSdkVersion 27 testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" - versionCode 36 - versionName "0.7.3" + versionCode 37 + versionName "0.7.4" buildConfigField "String", "COMMIT_COUNT", "\"${getCommitCount()}\"" buildConfigField "String", "COMMIT_SHA", "\"${getGitSha()}\"" diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAboutController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAboutController.kt index a39a66f54..a736da2a5 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAboutController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAboutController.kt @@ -22,7 +22,8 @@ import timber.log.Timber import java.text.DateFormat import java.text.ParseException import java.text.SimpleDateFormat -import java.util.* +import java.util.Locale +import java.util.TimeZone import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys @@ -78,6 +79,15 @@ class SettingsAboutController : SettingsController() { startActivity(intent) } } + preference { + title = "Github" + val url = "https://github.com/inorichi/tachiyomi" + summary = url + onClick { + val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url)) + startActivity(intent) + } + } preference { titleRes = R.string.version summary = if (BuildConfig.DEBUG) @@ -93,15 +103,6 @@ class SettingsAboutController : SettingsController() { titleRes = R.string.build_time summary = getFormattedBuildTime() } - preference { - title = "Github" - val url = "https://github.com/inorichi/tachiyomi" - summary = url - onClick { - val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url)) - startActivity(intent) - } - } } override fun onDestroyView(view: View) { diff --git a/app/src/main/res/raw/changelog_release.xml b/app/src/main/res/raw/changelog_release.xml index c61969bef..51de2f10d 100644 --- a/app/src/main/res/raw/changelog_release.xml +++ b/app/src/main/res/raw/changelog_release.xml @@ -1,5 +1,17 @@ + + Updated Anilist's API to v2. + + Added Github link to about. + + Fixed indonesian language not working. + + Fixed an issue on KitKat that crashed the app when scheduling updates. + + Fixed a few more issues introduced on the previous release. + + Fixed the tracking search layout when there are many results. @@ -197,54 +209,4 @@ Fixed lost covers on some devices. - - Added support for Anilist and Kitsu. - - Added library refresh option to library updates tab. - - Back button closes drawers before exiting the app. - - Fixed issues when using custom app language. - - Fixed updater in Android N. - - Fixed Mangafox search. - - - - Added an app's language selector. - - Added options to sort the library and merged them with the filters. - - Added an option to automatically download chapters. - - Fixed performance issues when using a custom downloads directory, especially in the library updates tab. - - Fixed gesture conflicts with the contextual menu and the webtoon reader. - - Fixed wrong page direction when using volume keys for the right to left reader. - - Fixed many crashes. - - - - The download manager has been rewritten and it's possible some of your downloads - aren't recognized anymore. It's recommended to manually delete everything and start over. - - - Now it's possible to download to any folder in a SD card. - - The download directory setting has been reset. - - Active downloads now persist after restarts. - - Allow to bookmark chapters. - - Allow to share or save a single page while reading with a long tap. - - Added italian translation. - - Image is now the default decoder. - - From 10f36f40d616c3a90dc1594fab2fb2a2383598e5 Mon Sep 17 00:00:00 2001 From: inorichi Date: Wed, 23 May 2018 13:16:11 +0200 Subject: [PATCH 18/22] Bugfix on save instance state. Also improve initial page loading on Kissmanga --- .../tachiyomi/source/online/english/Kissmanga.kt | 16 ++++------------ .../ui/extension/ExtensionGroupHolder.kt | 2 +- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/english/Kissmanga.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/english/Kissmanga.kt index b311a942e..77aa99bcc 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/source/online/english/Kissmanga.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/online/english/Kissmanga.kt @@ -154,17 +154,9 @@ class Kissmanga : ParsedHttpSource() { it.evaluate(ca) it.evaluate(lo) - // There are two functions in an inline script needed to decrypt the urls. We find and - // execute them. - var p = Pattern.compile("(.*CryptoJS.*)") - var m = p.matcher(body) - while (m.find()) { - it.evaluate(m.group(1)) - } - - // Finally find all the urls and decrypt them in JS. - p = Pattern.compile("""lstImages.push\((.*)\);""") - m = p.matcher(body) + // Find all the urls and decrypt them in JS. + val p = Pattern.compile("""lstImages.push\((.*)\);""") + val m = p.matcher(body) var i = 0 while (m.find()) { @@ -244,4 +236,4 @@ class Kissmanga : ParsedHttpSource() { Genre("Yaoi"), Genre("Yuri") ) -} \ No newline at end of file +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionGroupHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionGroupHolder.kt index 7edc3bd69..8bf0a6197 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionGroupHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/extension/ExtensionGroupHolder.kt @@ -8,7 +8,7 @@ import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder import kotlinx.android.synthetic.main.extension_card_header.* class ExtensionGroupHolder(view: View, adapter: FlexibleAdapter<*>) : - BaseFlexibleViewHolder(view, adapter, true) { + BaseFlexibleViewHolder(view, adapter) { @SuppressLint("SetTextI18n") fun bind(item: ExtensionGroupItem) { From c6cfd24f1938d76700d7719725d0c1af5b029101 Mon Sep 17 00:00:00 2001 From: inorichi Date: Sat, 26 May 2018 15:24:38 +0200 Subject: [PATCH 19/22] Fix kissmanga not loading for some people after the previous update --- .../tachiyomi/source/online/english/Kissmanga.kt | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/english/Kissmanga.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/english/Kissmanga.kt index 77aa99bcc..ae5669f4c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/source/online/english/Kissmanga.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/online/english/Kissmanga.kt @@ -154,9 +154,17 @@ class Kissmanga : ParsedHttpSource() { it.evaluate(ca) it.evaluate(lo) - // Find all the urls and decrypt them in JS. - val p = Pattern.compile("""lstImages.push\((.*)\);""") - val m = p.matcher(body) + // There are two functions in an inline script needed to decrypt the urls. We find and + // execute them. + var p = Pattern.compile("(var.*CryptoJS.*)") + var m = p.matcher(body) + while (m.find()) { + it.evaluate(m.group(1)) + } + + // Finally find all the urls and decrypt them in JS. + p = Pattern.compile("""lstImages.push\((.*)\);""") + m = p.matcher(body) var i = 0 while (m.find()) { From f4b838d8e227ab24ec3c8f6f1b6bff25cd410ea9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jozef=20Holl=C3=BD?= Date: Sat, 26 May 2018 15:24:44 +0200 Subject: [PATCH 20/22] Remove unused string (#1422) --- app/src/main/res/values/strings.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 5ae68a606..04edacc10 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -58,7 +58,6 @@ Edit the cover picture Sort up Sort down - Unread Downloaded Next unread Start From b19a4d297763acc1155f66edee83d347b4be433a Mon Sep 17 00:00:00 2001 From: ddmgy Date: Mon, 28 May 2018 16:54:41 -0400 Subject: [PATCH 21/22] Change AniList search query to show some previously hidden entries. (#1435) --- .../java/eu/kanade/tachiyomi/data/track/anilist/AnilistApi.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistApi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistApi.kt index 37d1eb14a..edb63931c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/anilist/AnilistApi.kt @@ -91,7 +91,7 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) { val query = """ query Search(${'$'}query: String) { Page (perPage: 25) { - media(search: ${'$'}query, type: MANGA, format: MANGA) { + media(search: ${'$'}query, type: MANGA, format_not_in: [NOVEL]) { id title { romaji From 56927927c86bcc77bab77d364a1f195f38756074 Mon Sep 17 00:00:00 2001 From: inorichi Date: Wed, 6 Jun 2018 12:42:57 +0200 Subject: [PATCH 22/22] =?UTF-8?q?Update=20user=20agent=20on=20kissmanga=20?= =?UTF-8?q?=C2=AF\=5F(=E3=83=84)=5F/=C2=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle | 1 + .../eu/kanade/tachiyomi/source/online/english/Kissmanga.kt | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/app/build.gradle b/app/build.gradle index 4c064f491..a0128b004 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -206,6 +206,7 @@ dependencies { implementation "com.github.inorichi.Conductor:conductor:be8b3c5" implementation ("com.bluelinelabs:conductor-support:2.1.5-SNAPSHOT") { exclude group: "com.bluelinelabs", module: "conductor" + exclude group: "com.android.support" } implementation 'com.github.inorichi:conductor-support-preference:27.0.2' diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/english/Kissmanga.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/english/Kissmanga.kt index ae5669f4c..0287c1fb5 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/source/online/english/Kissmanga.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/online/english/Kissmanga.kt @@ -6,6 +6,7 @@ import eu.kanade.tachiyomi.network.POST import eu.kanade.tachiyomi.source.model.* import eu.kanade.tachiyomi.source.online.ParsedHttpSource import okhttp3.FormBody +import okhttp3.Headers import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.Response @@ -29,6 +30,11 @@ class Kissmanga : ParsedHttpSource() { override val client: OkHttpClient = network.cloudflareClient + override fun headersBuilder(): Headers.Builder { + return Headers.Builder() + .add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) Gecko/20100101 Firefox/60") + } + override fun popularMangaSelector() = "table.listing tr:gt(1)" override fun latestUpdatesSelector() = "table.listing tr:gt(1)"