Convert java threads to kotlin coroutines

This commit is contained in:
Jobobby04 2020-10-29 15:29:43 -04:00
parent 46998d81f4
commit 3b5249c8bc
10 changed files with 117 additions and 77 deletions

View File

@ -43,6 +43,7 @@ import exh.md.utils.MdUtil
import exh.metadata.metadata.MangaDexSearchMetadata import exh.metadata.metadata.MangaDexSearchMetadata
import exh.source.DelegatedHttpSource import exh.source.DelegatedHttpSource
import exh.ui.metadata.adapters.MangaDexDescriptionAdapter import exh.ui.metadata.adapters.MangaDexDescriptionAdapter
import exh.util.asObservable
import exh.util.urlImportFetchSearchManga import exh.util.urlImportFetchSearchManga
import exh.widget.preference.MangadexLoginDialog import exh.widget.preference.MangadexLoginDialog
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@ -266,9 +267,11 @@ class MangaDex(delegate: HttpSource, val context: Context) :
private fun importIdToMdId(query: String, fail: () -> Observable<MangasPage>): Observable<MangasPage> = private fun importIdToMdId(query: String, fail: () -> Observable<MangasPage>): Observable<MangasPage> =
when { when {
query.toIntOrNull() != null -> { query.toIntOrNull() != null -> {
Observable.fromCallable { flow {
// MdUtil. emit(GalleryAdder().addGallery(context, MdUtil.baseUrl + MdUtil.mapMdIdToMangaUrl(query.toInt()), false, this@MangaDex))
val res = GalleryAdder().addGallery(context, MdUtil.baseUrl + MdUtil.mapMdIdToMangaUrl(query.toInt()), false, this) }
.asObservable()
.map { res ->
MangasPage( MangasPage(
( (
if (res is GalleryAddEvent.Success) { if (res is GalleryAddEvent.Success) {

View File

@ -91,9 +91,9 @@ class ChapterLoader(
return when { return when {
// SY --> // SY -->
source is MergedSource -> { source is MergedSource -> {
val mangaReference = mergedReferences.firstOrNull { it.mangaId == chapter.chapter.manga_id } ?: throw Exception("Merge reference null") val mangaReference = mergedReferences.firstOrNull { it.mangaId == chapter.chapter.manga_id } ?: error("Merge reference null")
val source = sourceManager.get(mangaReference.mangaSourceId) ?: throw Exception("Source ${mangaReference.mangaSourceId} was null") val source = sourceManager.get(mangaReference.mangaSourceId) ?: error("Source ${mangaReference.mangaSourceId} was null")
val manga = mergedManga.firstOrNull { it.id == chapter.chapter.manga_id } ?: throw Exception("Manga for merged chapter was null") val manga = mergedManga.firstOrNull { it.id == chapter.chapter.manga_id } ?: error("Manga for merged chapter was null")
val isMergedMangaDownloaded = downloadManager.isChapterDownloaded(chapter.chapter, manga, true) val isMergedMangaDownloaded = downloadManager.isChapterDownloaded(chapter.chapter, manga, true)
when { when {
isMergedMangaDownloaded -> DownloadPageLoader(chapter, manga, source, downloadManager) isMergedMangaDownloaded -> DownloadPageLoader(chapter, manga, source, downloadManager)

View File

@ -11,6 +11,8 @@ import eu.kanade.tachiyomi.source.online.UrlImportableSource
import eu.kanade.tachiyomi.source.online.all.EHentai import eu.kanade.tachiyomi.source.online.all.EHentai
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
import exh.source.getMainSource import exh.source.getMainSource
import exh.util.await
import exh.util.awaitSingle
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import java.util.Date import java.util.Date
@ -34,7 +36,7 @@ class GalleryAdder {
} }
} }
fun addGallery( suspend fun addGallery(
context: Context, context: Context,
url: String, url: String,
fav: Boolean = false, fav: Boolean = false,
@ -84,7 +86,7 @@ class GalleryAdder {
} ?: return GalleryAddEvent.Fail.UnknownType(url, context) } ?: return GalleryAddEvent.Fail.UnknownType(url, context)
// Use manga in DB if possible, otherwise, make a new manga // Use manga in DB if possible, otherwise, make a new manga
val manga = db.getManga(cleanedUrl, source.id).executeAsBlocking() val manga = db.getManga(cleanedUrl, source.id).await()
?: Manga.create(source.id).apply { ?: Manga.create(source.id).apply {
this.url = cleanedUrl this.url = cleanedUrl
title = realUrl title = realUrl
@ -93,13 +95,13 @@ class GalleryAdder {
// Insert created manga if not in DB before fetching details // Insert created manga if not in DB before fetching details
// This allows us to keep the metadata when fetching details // This allows us to keep the metadata when fetching details
if (manga.id == null) { if (manga.id == null) {
db.insertManga(manga).executeAsBlocking().insertedId()?.let { db.insertManga(manga).await().insertedId()?.let {
manga.id = it manga.id = it
} }
} }
// Fetch and copy details // Fetch and copy details
val newManga = source.fetchMangaDetails(manga).toBlocking().first() val newManga = source.fetchMangaDetails(manga).awaitSingle()
manga.copyFrom(newManga) manga.copyFrom(newManga)
manga.initialized = true manga.initialized = true
@ -108,7 +110,7 @@ class GalleryAdder {
manga.date_added = Date().time manga.date_added = Date().time
} }
db.insertManga(manga).executeAsBlocking() db.insertManga(manga).await()
// Fetch and copy chapters // Fetch and copy chapters
try { try {
@ -119,7 +121,7 @@ class GalleryAdder {
} }
chapterListObs.map { chapterListObs.map {
syncChaptersWithSource(db, it, manga, source) syncChaptersWithSource(db, it, manga, source)
}.toBlocking().first() }.awaitSingle()
} catch (e: Exception) { } catch (e: Exception) {
XLog.w(context.getString(R.string.gallery_adder_chapter_fetch_error, manga.title), e) XLog.w(context.getString(R.string.gallery_adder_chapter_fetch_error, manga.title), e)
return GalleryAddEvent.Fail.Error(url, context.getString(R.string.gallery_adder_chapter_fetch_error, url)) return GalleryAddEvent.Fail.Error(url, context.getString(R.string.gallery_adder_chapter_fetch_error, url))

View File

@ -10,6 +10,7 @@ import eu.kanade.tachiyomi.data.database.models.Category
import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.database.models.MangaCategory import eu.kanade.tachiyomi.data.database.models.MangaCategory
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.network.await
import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.source.online.all.EHentai import eu.kanade.tachiyomi.source.online.all.EHentai
import eu.kanade.tachiyomi.util.lang.launchUI import eu.kanade.tachiyomi.util.lang.launchUI
@ -21,22 +22,28 @@ import exh.GalleryAddEvent
import exh.GalleryAdder import exh.GalleryAdder
import exh.eh.EHentaiThrottleManager import exh.eh.EHentaiThrottleManager
import exh.eh.EHentaiUpdateWorker import exh.eh.EHentaiUpdateWorker
import exh.util.await
import exh.util.ignore import exh.util.ignore
import exh.util.trans import exh.util.trans
import exh.util.wifiManager import exh.util.wifiManager
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import okhttp3.FormBody import okhttp3.FormBody
import okhttp3.Request import okhttp3.Request
import rx.subjects.BehaviorSubject import rx.subjects.BehaviorSubject
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import kotlin.concurrent.thread
class FavoritesSyncHelper(val context: Context) { class FavoritesSyncHelper(val context: Context) {
private val db: DatabaseHelper by injectLazy() private val db: DatabaseHelper by injectLazy()
private val prefs: PreferencesHelper by injectLazy() private val prefs: PreferencesHelper by injectLazy()
private val scope = CoroutineScope(Job() + Dispatchers.Main)
private val exh by lazy { private val exh by lazy {
Injekt.get<SourceManager>().get(EXH_SOURCE_ID) as? EHentai Injekt.get<SourceManager>().get(EXH_SOURCE_ID) as? EHentai
?: EHentai(0, true, context) ?: EHentai(0, true, context)
@ -53,7 +60,7 @@ class FavoritesSyncHelper(val context: Context) {
private val logger = XLog.tag("EHFavSync").build() private val logger = XLog.tag("EHFavSync").build()
val status: BehaviorSubject<FavoritesSyncStatus> = BehaviorSubject.create<FavoritesSyncStatus>(FavoritesSyncStatus.Idle(context)) val status: BehaviorSubject<FavoritesSyncStatus> = BehaviorSubject.create(FavoritesSyncStatus.Idle(context))
@Synchronized @Synchronized
fun runSync() { fun runSync() {
@ -63,10 +70,10 @@ class FavoritesSyncHelper(val context: Context) {
status.onNext(FavoritesSyncStatus.Initializing(context)) status.onNext(FavoritesSyncStatus.Initializing(context))
thread { beginSync() } scope.launch(Dispatchers.IO) { beginSync() }
} }
private fun beginSync() { private suspend fun beginSync() {
// Check if logged in // Check if logged in
if (!prefs.enableExhentai().get()) { if (!prefs.enableExhentai().get()) {
status.onNext(FavoritesSyncStatus.Error(context.getString(R.string.please_login))) status.onNext(FavoritesSyncStatus.Error(context.getString(R.string.please_login)))
@ -75,13 +82,13 @@ class FavoritesSyncHelper(val context: Context) {
// Validate library state // Validate library state
status.onNext(FavoritesSyncStatus.Processing(context.getString(R.string.favorites_sync_verifying_library), context = context)) status.onNext(FavoritesSyncStatus.Processing(context.getString(R.string.favorites_sync_verifying_library), context = context))
val libraryManga = db.getLibraryMangas().executeAsBlocking() val libraryManga = db.getLibraryMangas().await()
val seenManga = HashSet<Long>(libraryManga.size) val seenManga = HashSet<Long>(libraryManga.size)
libraryManga.forEach { libraryManga.forEach {
if (it.source != EXH_SOURCE_ID && it.source != EH_SOURCE_ID) return@forEach if (it.source != EXH_SOURCE_ID && it.source != EH_SOURCE_ID) return@forEach
if (it.id in seenManga) { if (it.id in seenManga) {
val inCategories = db.getCategoriesForManga(it).executeAsBlocking() val inCategories = db.getCategoriesForManga(it).await()
status.onNext( status.onNext(
FavoritesSyncStatus.BadLibraryState FavoritesSyncStatus.BadLibraryState
.MangaInMultipleCategories(it, inCategories, context) .MangaInMultipleCategories(it, inCategories, context)
@ -153,9 +160,8 @@ class FavoritesSyncHelper(val context: Context) {
} }
} }
val theContext = context
launchUI { launchUI {
theContext.toast(context.getString(R.string.favorites_sync_complete)) context.toast(context.getString(R.string.favorites_sync_complete))
} }
} catch (e: IgnoredException) { } catch (e: IgnoredException) {
// Do not display error as this error has already been reported // Do not display error as this error has already been reported
@ -187,8 +193,8 @@ class FavoritesSyncHelper(val context: Context) {
} }
} }
private fun applyRemoteCategories(categories: List<String>) { private suspend fun applyRemoteCategories(categories: List<String>) {
val localCategories = db.getCategories().executeAsBlocking() val localCategories = db.getCategories().await()
val newLocalCategories = localCategories.toMutableList() val newLocalCategories = localCategories.toMutableList()
@ -226,11 +232,11 @@ class FavoritesSyncHelper(val context: Context) {
// Only insert categories if changed // Only insert categories if changed
if (changed) { if (changed) {
db.insertCategories(newLocalCategories).executeAsBlocking() db.insertCategories(newLocalCategories).await()
} }
} }
private fun addGalleryRemote(errorList: MutableList<String>, gallery: FavoriteEntry) { private suspend fun addGalleryRemote(errorList: MutableList<String>, gallery: FavoriteEntry) {
val url = "${exh.baseUrl}/gallerypopups.php?gid=${gallery.gid}&t=${gallery.token}&act=addfav" val url = "${exh.baseUrl}/gallerypopups.php?gid=${gallery.gid}&t=${gallery.token}&act=addfav"
val request = Request.Builder() val request = Request.Builder()
@ -257,12 +263,12 @@ class FavoritesSyncHelper(val context: Context) {
} }
} }
private fun explicitlyRetryExhRequest(retryCount: Int, request: Request): Boolean { private suspend fun explicitlyRetryExhRequest(retryCount: Int, request: Request): Boolean {
var success = false var success = false
for (i in 1..retryCount) { for (i in 1..retryCount) {
try { try {
val resp = exh.client.newCall(request).execute() val resp = exh.client.newCall(request).await()
if (resp.isSuccessful) { if (resp.isSuccessful) {
success = true success = true
@ -276,7 +282,7 @@ class FavoritesSyncHelper(val context: Context) {
return success return success
} }
private fun applyChangeSetToRemote(errorList: MutableList<String>, changeSet: ChangeSet) { private suspend fun applyChangeSetToRemote(errorList: MutableList<String>, changeSet: ChangeSet) {
// Apply removals // Apply removals
if (changeSet.removed.isNotEmpty()) { if (changeSet.removed.isNotEmpty()) {
status.onNext(FavoritesSyncStatus.Processing(context.getString(R.string.favorites_sync_removing_galleries, changeSet.removed.size), context = context)) status.onNext(FavoritesSyncStatus.Processing(context.getString(R.string.favorites_sync_removing_galleries, changeSet.removed.size), context = context))
@ -324,7 +330,7 @@ class FavoritesSyncHelper(val context: Context) {
} }
} }
private fun applyChangeSetToLocal(errorList: MutableList<String>, changeSet: ChangeSet) { private suspend fun applyChangeSetToLocal(errorList: MutableList<String>, changeSet: ChangeSet) {
val removedManga = mutableListOf<Manga>() val removedManga = mutableListOf<Manga>()
// Apply removals // Apply removals
@ -337,12 +343,12 @@ class FavoritesSyncHelper(val context: Context) {
db.getManga(url, EXH_SOURCE_ID), db.getManga(url, EXH_SOURCE_ID),
db.getManga(url, EH_SOURCE_ID) db.getManga(url, EH_SOURCE_ID)
).forEach { ).forEach {
val manga = it.executeAsBlocking() val manga = it.await()
if (manga?.favorite == true) { if (manga?.favorite == true) {
manga.favorite = false manga.favorite = false
manga.date_added = 0 manga.date_added = 0
db.updateMangaFavorite(manga).executeAsBlocking() db.updateMangaFavorite(manga).await()
removedManga += manga removedManga += manga
} }
} }
@ -350,11 +356,11 @@ class FavoritesSyncHelper(val context: Context) {
// Can't do too many DB OPs in one go // Can't do too many DB OPs in one go
removedManga.chunked(10).forEach { removedManga.chunked(10).forEach {
db.deleteOldMangasCategories(it).executeAsBlocking() db.deleteOldMangasCategories(it).await()
} }
val insertedMangaCategories = mutableListOf<Pair<MangaCategory, Manga>>() val insertedMangaCategories = mutableListOf<Pair<MangaCategory, Manga>>()
val categories = db.getCategories().executeAsBlocking() val categories = db.getCategories().await()
// Apply additions // Apply additions
throttleManager.resetThrottle() throttleManager.resetThrottle()

View File

@ -9,22 +9,27 @@ import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.ui.base.controller.DialogController import eu.kanade.tachiyomi.ui.base.controller.DialogController
import eu.kanade.tachiyomi.util.lang.launchUI import eu.kanade.tachiyomi.util.lang.launchUI
import eu.kanade.tachiyomi.util.system.toast import eu.kanade.tachiyomi.util.system.toast
import kotlin.concurrent.thread import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
class ConfiguringDialogController : DialogController() { class ConfiguringDialogController : DialogController() {
private var materialDialog: MaterialDialog? = null private var materialDialog: MaterialDialog? = null
val scope = CoroutineScope(Job() + Dispatchers.Main)
override fun onCreateDialog(savedViewState: Bundle?): Dialog { override fun onCreateDialog(savedViewState: Bundle?): Dialog {
if (savedViewState == null) { if (savedViewState == null) {
thread { scope.launch(Dispatchers.IO) {
try { try {
EHConfigurator(activity!!).configureAll() EHConfigurator(activity!!).configureAll()
launchUI { launchUI {
activity?.toast(activity?.getString(R.string.eh_settings_successfully_uploaded)) activity?.toast(activity?.getString(R.string.eh_settings_successfully_uploaded))
} }
} catch (e: Exception) { } catch (e: Exception) {
withContext(Dispatchers.Main) {
activity?.let { activity?.let {
it.runOnUiThread {
MaterialDialog(it) MaterialDialog(it)
.title(R.string.eh_settings_configuration_failed) .title(R.string.eh_settings_configuration_failed)
.message(text = it.getString(R.string.eh_settings_configuration_failed_message, e.message)) .message(text = it.getString(R.string.eh_settings_configuration_failed_message, e.message))

View File

@ -4,6 +4,7 @@ import android.content.Context
import com.elvishew.xlog.XLog import com.elvishew.xlog.XLog
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.network.await
import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.source.online.all.EHentai import eu.kanade.tachiyomi.source.online.all.EHentai
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
@ -26,7 +27,7 @@ class EHConfigurator(val context: Context) {
private fun EHentai.requestWithCreds(sp: Int = 1) = Request.Builder() private fun EHentai.requestWithCreds(sp: Int = 1) = Request.Builder()
.addHeader("Cookie", cookiesHeader(sp)) .addHeader("Cookie", cookiesHeader(sp))
private fun EHentai.execProfileActions( private suspend fun EHentai.execProfileActions(
action: String, action: String,
name: String, name: String,
set: String, set: String,
@ -44,11 +45,11 @@ class EHConfigurator(val context: Context) {
) )
.build() .build()
) )
.execute() .await()
private val EHentai.uconfigUrl get() = baseUrl + UCONFIG_URL private val EHentai.uconfigUrl get() = baseUrl + UCONFIG_URL
fun configureAll() { suspend fun configureAll() {
val ehSource = sources.get(EH_SOURCE_ID) as EHentai val ehSource = sources.get(EH_SOURCE_ID) as EHentai
val exhSource = sources.get(EXH_SOURCE_ID) as EHentai val exhSource = sources.get(EXH_SOURCE_ID) as EHentai
@ -58,7 +59,7 @@ class EHConfigurator(val context: Context) {
.url(HATH_PERKS_URL) .url(HATH_PERKS_URL)
.build() .build()
) )
.execute().asJsoup() .await().asJsoup()
val hathPerks = EHHathPerksResponse() val hathPerks = EHHathPerksResponse()
@ -85,10 +86,10 @@ class EHConfigurator(val context: Context) {
configure(exhSource, hathPerks) configure(exhSource, hathPerks)
} }
private fun configure(source: EHentai, hathPerks: EHHathPerksResponse) { private suspend fun configure(source: EHentai, hathPerks: EHHathPerksResponse) {
// Delete old app profiles // Delete old app profiles
val scanReq = source.requestWithCreds().url(source.uconfigUrl).build() val scanReq = source.requestWithCreds().url(source.uconfigUrl).build()
val resp = configuratorClient.newCall(scanReq).execute().asJsoup() val resp = configuratorClient.newCall(scanReq).await().asJsoup()
var lastDoc = resp var lastDoc = resp
resp.select(PROFILE_SELECTOR).forEach { resp.select(PROFILE_SELECTOR).forEach {
if (it.text() == PROFILE_NAME) { if (it.text() == PROFILE_NAME) {
@ -127,7 +128,7 @@ class EHConfigurator(val context: Context) {
.url(source.uconfigUrl) .url(source.uconfigUrl)
.post(form) .post(form)
.build() .build()
).execute() ).await()
// Persist slot + sk // Persist slot + sk
source.spPref().set(slot) source.spPref().set(slot)

View File

@ -1,6 +1,7 @@
package exh.ui.batchadd package exh.ui.batchadd
import android.content.Context import android.content.Context
import com.elvishew.xlog.XLog
import com.jakewharton.rxrelay.BehaviorRelay import com.jakewharton.rxrelay.BehaviorRelay
import com.jakewharton.rxrelay.ReplayRelay import com.jakewharton.rxrelay.ReplayRelay
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
@ -9,13 +10,20 @@ import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
import exh.GalleryAddEvent import exh.GalleryAddEvent
import exh.GalleryAdder import exh.GalleryAdder
import exh.util.trimOrNull import exh.util.trimOrNull
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.ensureActive
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import kotlin.concurrent.thread
class BatchAddPresenter : BasePresenter<BatchAddController>() { class BatchAddPresenter : BasePresenter<BatchAddController>() {
private val galleryAdder by lazy { GalleryAdder() } private val galleryAdder by lazy { GalleryAdder() }
private val scope = CoroutineScope(Job() + Dispatchers.Main)
val progressTotalRelay = BehaviorRelay.create(0)!! val progressTotalRelay = BehaviorRelay.create(0)!!
val progressRelay = BehaviorRelay.create(0)!! val progressRelay = BehaviorRelay.create(0)!!
@ -50,12 +58,17 @@ class BatchAddPresenter : BasePresenter<BatchAddController>() {
currentlyAddingRelay.call(STATE_INPUT_TO_PROGRESS) currentlyAddingRelay.call(STATE_INPUT_TO_PROGRESS)
thread { val handler = CoroutineExceptionHandler { _, throwable ->
XLog.e(throwable)
}
scope.launch(Dispatchers.IO + handler) {
val succeeded = mutableListOf<String>() val succeeded = mutableListOf<String>()
val failed = mutableListOf<String>() val failed = mutableListOf<String>()
splitGalleries.forEachIndexed { i, s -> splitGalleries.forEachIndexed { i, s ->
val result = galleryAdder.addGallery(context, s, true) ensureActive()
val result = withContext(Dispatchers.IO) { galleryAdder.addGallery(context, s, true) }
if (result is GalleryAddEvent.Success) { if (result is GalleryAddEvent.Success) {
succeeded.add(s) succeeded.add(s)
} else { } else {

View File

@ -25,6 +25,9 @@ import exh.source.DelegatedHttpSource
import exh.util.melt import exh.util.melt
import kotlinx.android.synthetic.main.eh_activity_captcha.toolbar import kotlinx.android.synthetic.main.eh_activity_captcha.toolbar
import kotlinx.android.synthetic.main.eh_activity_captcha.webview import kotlinx.android.synthetic.main.eh_activity_captcha.webview
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import kotlinx.serialization.decodeFromString import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonObject
@ -179,13 +182,13 @@ class BrowserActionActivity : AppCompatActivity() {
return true return true
} }
fun captchaSolveFail() { suspend fun captchaSolveFail() {
currentLoopId = null currentLoopId = null
validateCurrentLoopId = null validateCurrentLoopId = null
XLog.e(IllegalStateException("Captcha solve failure!")) XLog.e(IllegalStateException("Captcha solve failure!"))
runOnUiThread { withContext(Dispatchers.Main) {
webview.evaluateJavascript(SOLVE_UI_SCRIPT_HIDE, null) webview.evaluateJavascript(SOLVE_UI_SCRIPT_HIDE, null)
MaterialDialog(this) MaterialDialog(this@BrowserActionActivity)
.title(R.string.captcha_solve_failure) .title(R.string.captcha_solve_failure)
.message(R.string.captcha_solve_failure_message) .message(R.string.captcha_solve_failure_message)
.cancelable(true) .cancelable(true)
@ -196,7 +199,7 @@ class BrowserActionActivity : AppCompatActivity() {
} }
@JavascriptInterface @JavascriptInterface
fun callback(result: String?, loopId: String, stage: Int) { suspend fun callback(result: String?, loopId: String, stage: Int) {
if (loopId != currentLoopId) return if (loopId != currentLoopId) return
when (stage) { when (stage) {
@ -259,7 +262,7 @@ class BrowserActionActivity : AppCompatActivity() {
} }
}, },
{ {
captchaSolveFail() runBlocking { captchaSolveFail() }
} }
) )
} else { } else {
@ -456,7 +459,7 @@ class BrowserActionActivity : AppCompatActivity() {
} }
@JavascriptInterface @JavascriptInterface
fun validateCaptchaCallback(result: Boolean, loopId: String) { suspend fun validateCaptchaCallback(result: Boolean, loopId: String) {
if (loopId != validateCurrentLoopId) return if (loopId != validateCurrentLoopId) return
if (result) { if (result) {

View File

@ -16,10 +16,11 @@ import eu.kanade.tachiyomi.ui.main.MainActivity
import eu.kanade.tachiyomi.ui.manga.MangaController import eu.kanade.tachiyomi.ui.manga.MangaController
import exh.GalleryAddEvent import exh.GalleryAddEvent
import exh.GalleryAdder import exh.GalleryAdder
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import rx.Subscription import rx.Subscription
import rx.android.schedulers.AndroidSchedulers import rx.android.schedulers.AndroidSchedulers
import rx.subjects.BehaviorSubject import rx.subjects.BehaviorSubject
import kotlin.concurrent.thread
class InterceptActivity : BaseActivity<EhActivityInterceptBinding>() { class InterceptActivity : BaseActivity<EhActivityInterceptBinding>() {
private var statusSubscription: Subscription? = null private var statusSubscription: Subscription? = null
@ -119,14 +120,14 @@ class InterceptActivity : BaseActivity<EhActivityInterceptBinding>() {
@Synchronized @Synchronized
private fun loadGalleryEnd(gallery: String, source: UrlImportableSource? = null) { private fun loadGalleryEnd(gallery: String, source: UrlImportableSource? = null) {
// Load gallery async // Load gallery async
thread { scope.launch(Dispatchers.IO) {
val result = galleryAdder.addGallery(this, gallery, forceSource = source) val result = galleryAdder.addGallery(this@InterceptActivity, gallery, forceSource = source)
status.onNext( status.onNext(
when (result) { when (result) {
is GalleryAddEvent.Success -> result.manga.id?.let { is GalleryAddEvent.Success -> result.manga.id?.let {
InterceptResult.Success(it) InterceptResult.Success(it)
} ?: InterceptResult.Failure(this.getString(R.string.manga_id_is_null)) } ?: InterceptResult.Failure(this@InterceptActivity.getString(R.string.manga_id_is_null))
is GalleryAddEvent.Fail -> InterceptResult.Failure(result.logMessage) is GalleryAddEvent.Fail -> InterceptResult.Failure(result.logMessage)
} }
) )

View File

@ -5,6 +5,7 @@ import eu.kanade.tachiyomi.source.model.MangasPage
import eu.kanade.tachiyomi.source.online.UrlImportableSource import eu.kanade.tachiyomi.source.online.UrlImportableSource
import exh.GalleryAddEvent import exh.GalleryAddEvent
import exh.GalleryAdder import exh.GalleryAdder
import kotlinx.coroutines.flow.flow
import rx.Observable import rx.Observable
private val galleryAdder by lazy { private val galleryAdder by lazy {
@ -17,8 +18,13 @@ private val galleryAdder by lazy {
fun UrlImportableSource.urlImportFetchSearchManga(context: Context, query: String, fail: () -> Observable<MangasPage>): Observable<MangasPage> = fun UrlImportableSource.urlImportFetchSearchManga(context: Context, query: String, fail: () -> Observable<MangasPage>): Observable<MangasPage> =
when { when {
query.startsWith("http://") || query.startsWith("https://") -> { query.startsWith("http://") || query.startsWith("https://") -> {
Observable.fromCallable { flow {
val res = galleryAdder.addGallery(context, query, false, this) emit(
galleryAdder.addGallery(context, query, false, this@urlImportFetchSearchManga)
)
}
.asObservable()
.map { res ->
MangasPage( MangasPage(
( (
if (res is GalleryAddEvent.Success) { if (res is GalleryAddEvent.Success) {