Do quite a bit of code cleanup

This commit is contained in:
Jobobby04 2021-01-17 22:17:15 -05:00
parent 8db57aef6c
commit 3b364c91f1
16 changed files with 95 additions and 480 deletions

View File

@ -1,374 +0,0 @@
package eu.kanade.tachiyomi.source.online
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.await
import eu.kanade.tachiyomi.network.newCallWithProgress
import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.source.model.MangasPage
import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.util.lang.runAsObservable
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import okhttp3.Request
import okhttp3.Response
import rx.Observable
import kotlin.jvm.Throws
/**
* A simple implementation for sources from a website, but for Coroutines.
*/
abstract class SuspendHttpSource : HttpSource() {
/**
* Returns an observable containing a page with a list of manga. Normally it's not needed to
* override this method.
*
* @param page the page number to retrieve.
*/
final override fun fetchPopularManga(page: Int): Observable<MangasPage> {
return runAsObservable({ fetchPopularMangaSuspended(page) })
}
open suspend fun fetchPopularMangaSuspended(page: Int): MangasPage {
return withContext(Dispatchers.IO) {
val response = client.newCall(popularMangaRequestSuspended(page)).await()
popularMangaParseSuspended(response)
}
}
/**
* Returns the request for the popular manga given the page.
*
* @param page the page number to retrieve.
*/
final override fun popularMangaRequest(page: Int): Request {
return runBlocking { popularMangaRequestSuspended(page) }
}
protected abstract suspend fun popularMangaRequestSuspended(page: Int): Request
/**
* Parses the response from the site and returns a [MangasPage] object.
*
* @param response the response from the site.
*/
final override fun popularMangaParse(response: Response): MangasPage {
return runBlocking { popularMangaParseSuspended(response) }
}
protected abstract suspend fun popularMangaParseSuspended(response: Response): MangasPage
/**
* Returns an observable containing a page with a list of manga. Normally it's not needed to
* override this method.
*
* @param page the page number to retrieve.
* @param query the search query.
* @param filters the list of filters to apply.
*/
final override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> {
return runAsObservable({ fetchSearchMangaSuspended(page, query, filters) })
}
open suspend fun fetchSearchMangaSuspended(page: Int, query: String, filters: FilterList): MangasPage {
return withContext(Dispatchers.IO) {
val response = client.newCall(searchMangaRequestSuspended(page, query, filters)).await()
searchMangaParseSuspended(response)
}
}
/**
* Returns the request for the search manga given the page.
*
* @param page the page number to retrieve.
* @param query the search query.
* @param filters the list of filters to apply.
*/
final override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
return runBlocking { searchMangaRequestSuspended(page, query, filters) }
}
protected abstract suspend fun searchMangaRequestSuspended(page: Int, query: String, filters: FilterList): Request
/**
* Parses the response from the site and returns a [MangasPage] object.
*
* @param response the response from the site.
*/
final override fun searchMangaParse(response: Response): MangasPage {
return runBlocking { searchMangaParseSuspended(response) }
}
protected abstract suspend fun searchMangaParseSuspended(response: Response): MangasPage
/**
* Returns an observable containing a page with a list of latest manga updates.
*
* @param page the page number to retrieve.
*/
final override fun fetchLatestUpdates(page: Int): Observable<MangasPage> {
return runAsObservable({ fetchLatestUpdatesSuspended(page) })
}
open suspend fun fetchLatestUpdatesSuspended(page: Int): MangasPage {
return withContext(Dispatchers.IO) {
val response = client.newCall(latestUpdatesRequestSuspended(page)).await()
latestUpdatesParseSuspended(response)
}
}
/**
* Returns the request for latest manga given the page.
*
* @param page the page number to retrieve.
*/
final override fun latestUpdatesRequest(page: Int): Request {
return runBlocking { latestUpdatesRequestSuspended(page) }
}
protected abstract suspend fun latestUpdatesRequestSuspended(page: Int): Request
/**
* Parses the response from the site and returns a [MangasPage] object.
*
* @param response the response from the site.
*/
final override fun latestUpdatesParse(response: Response): MangasPage {
return runBlocking { latestUpdatesParseSuspended(response) }
}
protected abstract suspend fun latestUpdatesParseSuspended(response: Response): MangasPage
/**
* Returns an observable with the updated details for a manga. Normally it's not needed to
* override this method.
*
* @param manga the manga to be updated.
*/
final override fun fetchMangaDetails(manga: SManga): Observable<SManga> {
return runAsObservable({ fetchMangaDetailsSuspended(manga) })
}
open suspend fun fetchMangaDetailsSuspended(manga: SManga): SManga {
return withContext(Dispatchers.IO) {
val response = client.newCall(mangaDetailsRequestSuspended(manga)).await()
mangaDetailsParseSuspended(response).apply { initialized = true }
}
}
/**
* Returns the request for the details of a manga. Override only if it's needed to change the
* url, send different headers or request method like POST.
*
* @param manga the manga to be updated.
*/
final override fun mangaDetailsRequest(manga: SManga): Request {
return runBlocking { mangaDetailsRequestSuspended(manga) }
}
open suspend fun mangaDetailsRequestSuspended(manga: SManga): Request {
return GET(baseUrl + manga.url, headers)
}
/**
* Parses the response from the site and returns the details of a manga.
*
* @param response the response from the site.
*/
final override fun mangaDetailsParse(response: Response): SManga {
return runBlocking { mangaDetailsParseSuspended(response) }
}
protected abstract suspend fun mangaDetailsParseSuspended(response: Response): SManga
/**
* Returns an observable with the updated chapter list for a manga. Normally it's not needed to
* override this method. If a manga is licensed an empty chapter list observable is returned
*
* @param manga the manga to look for chapters.
*/
final override fun fetchChapterList(manga: SManga): Observable<List<SChapter>> {
return try {
runAsObservable({ fetchChapterListSuspended(manga) })
} catch (e: LicencedException) {
Observable.error(Exception("Licensed - No chapters to show"))
}
}
@Throws(LicencedException::class)
open suspend fun fetchChapterListSuspended(manga: SManga): List<SChapter> {
return withContext(Dispatchers.IO) {
if (manga.status != SManga.LICENSED) {
val response = client.newCall(chapterListRequestSuspended(manga)).await()
chapterListParseSuspended(response)
} else {
throw LicencedException("Licensed - No chapters to show")
}
}
}
/**
* Returns the request for updating the chapter list. Override only if it's needed to override
* the url, send different headers or request method like POST.
*
* @param manga the manga to look for chapters.
*/
final override fun chapterListRequest(manga: SManga): Request {
return runBlocking { chapterListRequestSuspended(manga) }
}
protected open suspend fun chapterListRequestSuspended(manga: SManga): Request {
return GET(baseUrl + manga.url, headers)
}
/**
* Parses the response from the site and returns a list of chapters.
*
* @param response the response from the site.
*/
final override fun chapterListParse(response: Response): List<SChapter> {
return runBlocking { chapterListParseSuspended(response) }
}
protected abstract suspend fun chapterListParseSuspended(response: Response): List<SChapter>
/**
* Returns an observable with the page list for a chapter.
*
* @param chapter the chapter whose page list has to be fetched.
*/
final override fun fetchPageList(chapter: SChapter): Observable<List<Page>> {
return runAsObservable({ fetchPageListSuspended(chapter) })
}
open suspend fun fetchPageListSuspended(chapter: SChapter): List<Page> {
return withContext(Dispatchers.IO) {
val response = client.newCall(pageListRequestSuspended(chapter)).await()
pageListParseSuspended(response)
}
}
/**
* Returns the request for getting the page list. Override only if it's needed to override the
* url, send different headers or request method like POST.
*
* @param chapter the chapter whose page list has to be fetched.
*/
final override fun pageListRequest(chapter: SChapter): Request {
return runBlocking { pageListRequestSuspended(chapter) }
}
protected open suspend fun pageListRequestSuspended(chapter: SChapter): Request {
return GET(baseUrl + chapter.url, headers)
}
/**
* Parses the response from the site and returns a list of pages.
*
* @param response the response from the site.
*/
final override fun pageListParse(response: Response): List<Page> {
return runBlocking { pageListParseSuspended(response) }
}
protected abstract suspend fun pageListParseSuspended(response: Response): List<Page>
/**
* Returns an observable with the page containing the source url of the image. If there's any
* error, it will return null instead of throwing an exception.
*
* @param page the page whose source image has to be fetched.
*/
final override fun fetchImageUrl(page: Page): Observable<String> {
return runAsObservable({ fetchImageUrlSuspended(page) })
}
open suspend fun fetchImageUrlSuspended(page: Page): String {
return withContext(Dispatchers.IO) {
val response = client.newCall(imageUrlRequestSuspended(page)).await()
imageUrlParseSuspended(response)
}
}
/**
* Returns the request for getting the url to the source image. Override only if it's needed to
* override the url, send different headers or request method like POST.
*
* @param page the chapter whose page list has to be fetched
*/
final override fun imageUrlRequest(page: Page): Request {
return runBlocking { imageUrlRequestSuspended(page) }
}
protected open suspend fun imageUrlRequestSuspended(page: Page): Request {
return GET(page.url, headers)
}
/**
* Parses the response from the site and returns the absolute url to the source image.
*
* @param response the response from the site.
*/
final override fun imageUrlParse(response: Response): String {
return runBlocking { imageUrlParseSuspended(response) }
}
protected abstract suspend fun imageUrlParseSuspended(response: Response): String
/**
* Returns an observable with the response of the source image.
*
* @param page the page whose source image has to be downloaded.
*/
final override fun fetchImage(page: Page): Observable<Response> {
return runAsObservable({ fetchImageSuspended(page) })
}
open suspend fun fetchImageSuspended(page: Page): Response {
return withContext(Dispatchers.IO) {
client.newCallWithProgress(imageRequestSuspended(page), page).await()
}
}
/**
* Returns the request for getting the source image. Override only if it's needed to override
* the url, send different headers or request method like POST.
*
* @param page the chapter whose page list has to be fetched
*/
final override fun imageRequest(page: Page): Request {
return runBlocking { imageRequestSuspended(page) }
}
protected open suspend fun imageRequestSuspended(page: Page): Request {
return GET(page.imageUrl!!, headers)
}
/**
* Called before inserting a new chapter into database. Use it if you need to override chapter
* fields, like the title or the chapter number. Do not change anything to [manga].
*
* @param chapter the chapter to be added.
* @param manga the manga of the chapter.
*/
final override fun prepareNewChapter(chapter: SChapter, manga: SManga) {
runBlocking { prepareNewChapterSuspended(chapter, manga) }
}
open suspend fun prepareNewChapterSuspended(chapter: SChapter, manga: SManga) {
}
/**
* Returns the list of filters for the source.
*/
override fun getFilterList() = runBlocking { getFilterListSuspended() }
open suspend fun getFilterListSuspended() = FilterList()
companion object {
data class LicencedException(override val message: String?) : Exception()
}
}

View File

@ -30,6 +30,7 @@ import eu.kanade.tachiyomi.ui.base.controller.BaseController
import eu.kanade.tachiyomi.ui.base.controller.DialogController
import eu.kanade.tachiyomi.ui.manga.MangaController
import eu.kanade.tachiyomi.util.lang.runAsObservable
import eu.kanade.tachiyomi.util.lang.withIOContext
import exh.GalleryAddEvent
import exh.GalleryAdder
import exh.md.MangaDexFabHeaderAdapter
@ -47,12 +48,10 @@ import exh.source.DelegatedHttpSource
import exh.ui.metadata.adapters.MangaDexDescriptionAdapter
import exh.util.urlImportFetchSearchManga
import exh.widget.preference.MangadexLoginDialog
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import okhttp3.CacheControl
import okhttp3.FormBody
import okhttp3.Headers
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.Request
import okhttp3.Response
import rx.Observable
@ -184,7 +183,7 @@ class MangaDex(delegate: HttpSource, val context: Context) :
}
override fun isLogged(): Boolean {
val httpUrl = MdUtil.baseUrl.toHttpUrlOrNull()!!
val httpUrl = MdUtil.baseUrl.toHttpUrl()
return trackManager.mdList.isLogged && network.cookieManager.get(httpUrl).any { it.name == REMEMBER_ME }
}
@ -193,12 +192,13 @@ class MangaDex(delegate: HttpSource, val context: Context) :
password: String,
twoFactorCode: String
): Boolean {
return withContext(Dispatchers.IO) {
val formBody = FormBody.Builder()
.add("login_username", username)
.add("login_password", password)
.add("no_js", "1")
.add("remember_me", "1")
return withIOContext {
val formBody = FormBody.Builder().apply {
add("login_username", username)
add("login_password", password)
add("no_js", "1")
add("remember_me", "1")
}
twoFactorCode.let {
formBody.add("two_factor", it)
@ -212,11 +212,11 @@ class MangaDex(delegate: HttpSource, val context: Context) :
)
).await()
withContext(Dispatchers.IO) { response.body!!.string() }.let {
if (it.isEmpty()) {
withIOContext { response.body?.string() }.let { result ->
if (result != null && result.isEmpty()) {
true
} else {
val error = HtmlCompat.fromHtml(it, HtmlCompat.FROM_HTML_MODE_COMPACT).toString()
val error = result?.let { HtmlCompat.fromHtml(it, HtmlCompat.FROM_HTML_MODE_COMPACT).toString() }
throw Exception(error)
}
}
@ -224,23 +224,23 @@ class MangaDex(delegate: HttpSource, val context: Context) :
}
override suspend fun logout(): Boolean {
return withContext(Dispatchers.IO) {
return withIOContext {
// https://mangadex.org/ajax/actions.ajax.php?function=logout
val httpUrl = MdUtil.baseUrl.toHttpUrlOrNull()!!
val httpUrl = MdUtil.baseUrl.toHttpUrl()
val listOfDexCookies = network.cookieManager.get(httpUrl)
val cookie = listOfDexCookies.find { it.name == REMEMBER_ME }
val token = cookie?.value
if (token.isNullOrEmpty()) {
return@withContext true
return@withIOContext true
}
val result = client.newCall(
POST("${MdUtil.baseUrl}/ajax/actions.ajax.php?function=logout", headers).newBuilder().addHeader(REMEMBER_ME, token).build()
).await()
val resultStr = withContext(Dispatchers.IO) { result.body?.string() }
val resultStr = withIOContext { result.body?.string() }
if (resultStr?.contains("success", true) == true) {
network.cookieManager.remove(httpUrl)
trackManager.mdList.logout()
return@withContext true
return@withIOContext true
}
false
@ -248,19 +248,19 @@ class MangaDex(delegate: HttpSource, val context: Context) :
}
override suspend fun fetchAllFollows(forceHd: Boolean): List<Pair<SManga, MangaDexSearchMetadata>> {
return withContext(Dispatchers.IO) { FollowsHandler(client, headers, Injekt.get(), useLowQualityThumbnail()).fetchAllFollows(forceHd) }
return withIOContext { FollowsHandler(client, headers, Injekt.get(), useLowQualityThumbnail()).fetchAllFollows(forceHd) }
}
suspend fun updateReadingProgress(track: Track): Boolean {
return withContext(Dispatchers.IO) { FollowsHandler(client, headers, Injekt.get(), useLowQualityThumbnail()).updateReadingProgress(track) }
return withIOContext { FollowsHandler(client, headers, Injekt.get(), useLowQualityThumbnail()).updateReadingProgress(track) }
}
suspend fun updateRating(track: Track): Boolean {
return withContext(Dispatchers.IO) { FollowsHandler(client, headers, Injekt.get(), useLowQualityThumbnail()).updateRating(track) }
return withIOContext { FollowsHandler(client, headers, Injekt.get(), useLowQualityThumbnail()).updateRating(track) }
}
override suspend fun fetchTrackingInfo(url: String): Track {
return withContext(Dispatchers.IO) {
return withIOContext {
if (!isLogged()) {
throw Exception("Not Logged in")
}
@ -269,7 +269,7 @@ class MangaDex(delegate: HttpSource, val context: Context) :
}
override suspend fun updateFollowStatus(mangaID: String, followStatus: FollowStatus): Boolean {
return withContext(Dispatchers.IO) { FollowsHandler(client, headers, Injekt.get(), useLowQualityThumbnail()).updateFollowStatus(mangaID, followStatus) }
return withIOContext { FollowsHandler(client, headers, Injekt.get(), useLowQualityThumbnail()).updateFollowStatus(mangaID, followStatus) }
}
override fun getFilterHeader(controller: BaseController<*>): MangaDexFabHeaderAdapter {
@ -292,13 +292,11 @@ class MangaDex(delegate: HttpSource, val context: Context) :
})
.map { res ->
MangasPage(
(
if (res is GalleryAddEvent.Success) {
listOf(res.manga)
} else {
emptyList()
}
),
if (res is GalleryAddEvent.Success) {
listOf(res.manga)
} else {
emptyList()
},
false
)
}

View File

@ -15,7 +15,7 @@ import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.model.toSChapter
import eu.kanade.tachiyomi.source.model.toSManga
import eu.kanade.tachiyomi.source.online.SuspendHttpSource
import eu.kanade.tachiyomi.source.online.HttpSource
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
import eu.kanade.tachiyomi.util.lang.awaitSingle
import eu.kanade.tachiyomi.util.lang.withIOContext
@ -25,9 +25,11 @@ import exh.merged.sql.models.MergedMangaReference
import exh.util.executeOnIO
import okhttp3.Response
import rx.Observable
import tachiyomi.source.model.ChapterInfo
import tachiyomi.source.model.MangaInfo
import uy.kohesive.injekt.injectLazy
class MergedSource : SuspendHttpSource() {
class MergedSource : HttpSource() {
private val db: DatabaseHelper by injectLazy()
private val sourceManager: SourceManager by injectLazy()
private val downloadManager: DownloadManager by injectLazy()
@ -37,40 +39,42 @@ class MergedSource : SuspendHttpSource() {
override val baseUrl = ""
override suspend fun popularMangaRequestSuspended(page: Int) = throw UnsupportedOperationException()
override suspend fun popularMangaParseSuspended(response: Response) = throw UnsupportedOperationException()
override suspend fun searchMangaRequestSuspended(page: Int, query: String, filters: FilterList) = throw UnsupportedOperationException()
override suspend fun searchMangaParseSuspended(response: Response) = throw UnsupportedOperationException()
override suspend fun latestUpdatesRequestSuspended(page: Int) = throw UnsupportedOperationException()
override suspend fun latestUpdatesParseSuspended(response: Response) = throw UnsupportedOperationException()
override suspend fun mangaDetailsParseSuspended(response: Response) = throw UnsupportedOperationException()
override suspend fun chapterListParseSuspended(response: Response) = throw UnsupportedOperationException()
override suspend fun pageListParseSuspended(response: Response) = throw UnsupportedOperationException()
override suspend fun imageUrlParseSuspended(response: Response) = throw UnsupportedOperationException()
override suspend fun fetchChapterListSuspended(manga: SManga) = throw UnsupportedOperationException()
override suspend fun fetchImageSuspended(page: Page) = throw UnsupportedOperationException()
override suspend fun fetchImageUrlSuspended(page: Page) = throw UnsupportedOperationException()
override suspend fun fetchPageListSuspended(chapter: SChapter) = throw UnsupportedOperationException()
override suspend fun fetchLatestUpdatesSuspended(page: Int) = throw UnsupportedOperationException()
override suspend fun fetchPopularMangaSuspended(page: Int) = throw UnsupportedOperationException()
override fun popularMangaRequest(page: Int) = throw UnsupportedOperationException()
override fun popularMangaParse(response: Response) = throw UnsupportedOperationException()
override fun searchMangaRequest(page: Int, query: String, filters: FilterList) = throw UnsupportedOperationException()
override fun searchMangaParse(response: Response) = throw UnsupportedOperationException()
override fun latestUpdatesRequest(page: Int) = throw UnsupportedOperationException()
override fun latestUpdatesParse(response: Response) = throw UnsupportedOperationException()
override fun mangaDetailsParse(response: Response) = throw UnsupportedOperationException()
override fun chapterListParse(response: Response) = throw UnsupportedOperationException()
override fun pageListParse(response: Response) = throw UnsupportedOperationException()
override fun imageUrlParse(response: Response) = throw UnsupportedOperationException()
override fun fetchChapterList(manga: SManga) = throw UnsupportedOperationException()
override suspend fun getChapterList(manga: MangaInfo) = throw UnsupportedOperationException()
override fun fetchImage(page: Page) = throw UnsupportedOperationException()
override fun fetchImageUrl(page: Page) = throw UnsupportedOperationException()
override fun fetchPageList(chapter: SChapter) = throw UnsupportedOperationException()
override suspend fun getPageList(chapter: ChapterInfo) = throw UnsupportedOperationException()
override fun fetchLatestUpdates(page: Int) = throw UnsupportedOperationException()
override fun fetchPopularManga(page: Int) = throw UnsupportedOperationException()
override suspend fun fetchMangaDetailsSuspended(manga: SManga): SManga {
override suspend fun getMangaDetails(manga: MangaInfo): MangaInfo {
return withIOContext {
val mergedManga = db.getManga(manga.url, id).executeAsBlocking() ?: throw Exception("merged manga not in db")
val mangaReferences = mergedManga.id?.let { db.getMergedMangaReferences(it).executeOnIO() } ?: throw Exception("merged manga id is null")
val mergedManga = db.getManga(manga.key, id).executeAsBlocking() ?: throw Exception("merged manga not in db")
val mangaReferences = db.getMergedMangaReferences(mergedManga.id ?: throw Exception("merged manga id is null")).executeOnIO()
if (mangaReferences.isEmpty()) throw IllegalArgumentException("Manga references are empty, info unavailable, merge is likely corrupted")
if (mangaReferences.size == 1 || run {
val mangaReference = mangaReferences.firstOrNull()
mangaReference == null || (mangaReference.mangaSourceId == MERGED_SOURCE_ID)
}
if (mangaReferences.size == 1 &&
run {
val mangaReference = mangaReferences.firstOrNull()
mangaReference == null || mangaReference.mangaSourceId == MERGED_SOURCE_ID
}
) throw IllegalArgumentException("Manga references contain only the merged reference, merge is likely corrupted")
SManga.create().apply {
val mangaInfoReference = mangaReferences.firstOrNull { it.isInfoManga } ?: mangaReferences.firstOrNull { it.mangaId != it.mergeId }
val dbManga = mangaInfoReference?.let { db.getManga(it.mangaUrl, it.mangaSourceId).executeOnIO() }
this.copyFrom(dbManga ?: mergedManga)
url = manga.url
}
val mangaInfoReference = mangaReferences.firstOrNull { it.isInfoManga } ?: mangaReferences.firstOrNull { it.mangaId != it.mergeId }
val dbManga = mangaInfoReference?.let { db.getManga(it.mangaUrl, it.mangaSourceId).executeOnIO()?.toMangaInfo() }
(dbManga ?: mergedManga.toMangaInfo()).copy(
key = manga.key
)
}
}

View File

@ -8,7 +8,7 @@ import exh.util.DeferredField
import exh.util.executeOnIO
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.channels.ConflatedBroadcastChannel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlin.coroutines.CoroutineContext
class MigratingManga(
@ -20,7 +20,7 @@ class MigratingManga(
val searchResult = DeferredField<Long?>()
// <MAX, PROGRESS>
val progress = ConflatedBroadcastChannel(1 to 0)
val progress = MutableStateFlow(1 to 0)
val migrationJob = parentContext + SupervisorJob() + Dispatchers.Default

View File

@ -37,6 +37,7 @@ import eu.kanade.tachiyomi.ui.manga.MangaController
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
import eu.kanade.tachiyomi.util.lang.await
import eu.kanade.tachiyomi.util.lang.launchUI
import eu.kanade.tachiyomi.util.lang.withIOContext
import eu.kanade.tachiyomi.util.system.getResourceColor
import eu.kanade.tachiyomi.util.system.toast
import exh.eh.EHentaiThrottleManager
@ -51,7 +52,6 @@ import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Semaphore
import kotlinx.coroutines.sync.withPermit
import kotlinx.coroutines.withContext
import timber.log.Timber
import uy.kohesive.injekt.injectLazy
import java.util.concurrent.atomic.AtomicInteger
@ -187,7 +187,7 @@ class MigrationListController(bundle: Bundle? = null) :
} catch (e: Exception) {
return@async2 null
}
manga.progress.send(validSources.size to processedSources.incrementAndGet())
manga.progress.value = validSources.size to processedSources.incrementAndGet()
localManga to chapters.size
} else {
null
@ -222,7 +222,7 @@ class MigrationListController(bundle: Bundle? = null) :
Timber.e(e)
emptyList()
}
withContext(Dispatchers.IO) {
withIOContext {
syncChaptersWithSource(db, chapters, localManga, source)
}
localManga
@ -233,7 +233,7 @@ class MigrationListController(bundle: Bundle? = null) :
} catch (e: Exception) {
null
}
manga.progress.send(validSources.size to (index + 1))
manga.progress.value = validSources.size to (index + 1)
if (searchResult != null) return@async searchResult
}

View File

@ -8,9 +8,8 @@ import eu.kanade.tachiyomi.data.database.models.MangaCategory
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.ui.browse.migration.MigrationFlags
import eu.kanade.tachiyomi.util.lang.launchUI
import kotlinx.coroutines.Dispatchers
import eu.kanade.tachiyomi.util.lang.withIOContext
import kotlinx.coroutines.cancel
import kotlinx.coroutines.withContext
import uy.kohesive.injekt.injectLazy
class MigrationProcessAdapter(
@ -48,7 +47,7 @@ class MigrationProcessAdapter(
fun mangasSkipped() = items.count { it.manga.migrationStatus == MigrationStatus.MANGA_NOT_FOUND }
suspend fun performMigrations(copy: Boolean) {
withContext(Dispatchers.IO) {
withIOContext {
db.inTransaction {
currentItems.forEach { migratingManga ->
val manga = migratingManga.manga

View File

@ -18,14 +18,13 @@ import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
import eu.kanade.tachiyomi.ui.manga.MangaController
import eu.kanade.tachiyomi.util.lang.launchUI
import eu.kanade.tachiyomi.util.lang.withUIContext
import eu.kanade.tachiyomi.util.system.getResourceColor
import eu.kanade.tachiyomi.util.view.setVectorCompat
import exh.MERGED_SOURCE_ID
import exh.util.executeOnIO
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.withContext
import reactivecircus.flowbinding.android.view.clicks
import uy.kohesive.injekt.injectLazy
import java.text.DecimalFormat
@ -70,7 +69,7 @@ class MigrationProcessHolder(
binding.skipManga.isVisible = true
binding.migrationMangaCardTo.resetManga()
if (manga != null) {
withContext(Dispatchers.Main) {
withUIContext {
binding.migrationMangaCardFrom.attachManga(manga, source)
binding.migrationMangaCardFrom.root.clicks()
.onEach {
@ -85,7 +84,7 @@ class MigrationProcessHolder(
/*launchUI {
item.manga.progress.asFlow().collect { (max, progress) ->
withContext(Dispatchers.Main) {
withUIContext {
migration_manga_card_to.search_progress.let { progressBar ->
progressBar.max = max
progressBar.progress = progress
@ -100,11 +99,11 @@ class MigrationProcessHolder(
val resultSource = searchResult?.source?.let {
sourceManager.get(it)
}
withContext(Dispatchers.Main) {
withUIContext {
if (item.manga.mangaId != this@MigrationProcessHolder.item?.manga?.mangaId ||
item.manga.migrationStatus == MigrationStatus.RUNNING
) {
return@withContext
return@withUIContext
}
if (searchResult != null && resultSource != null) {
binding.migrationMangaCardTo.attachManga(searchResult, resultSource)

View File

@ -19,9 +19,8 @@ import eu.kanade.tachiyomi.ui.browse.migration.advanced.design.PreMigrationContr
import eu.kanade.tachiyomi.ui.browse.migration.manga.MigrationMangaController
import eu.kanade.tachiyomi.util.lang.await
import eu.kanade.tachiyomi.util.lang.launchUI
import eu.kanade.tachiyomi.util.lang.withUIContext
import eu.kanade.tachiyomi.util.system.openInBrowser
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import rx.schedulers.Schedulers
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
@ -100,7 +99,7 @@ class MigrationSourcesController :
launchUI {
val manga = Injekt.get<DatabaseHelper>().getFavoriteMangas().asRxSingle().await(Schedulers.io())
val sourceMangas = manga.asSequence().filter { it.source == item.source.id }.map { it.id!! }.toList()
withContext(Dispatchers.Main) {
withUIContext {
PreMigrationController.navigateToMigration(
Injekt.get<PreferencesHelper>().skipPreMigration().get(),
if (parentController is BrowseController) {

View File

@ -143,7 +143,7 @@ open class IndexController :
searchView.maxWidth = Int.MAX_VALUE
val query = presenter.query
if (!query.isBlank()) {
if (query.isNotBlank()) {
searchItem.expandActionView()
searchView.setQuery(query, true)
searchView.clearFocus()

View File

@ -15,12 +15,12 @@ import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourcePresenter.Companion.toItems
import eu.kanade.tachiyomi.util.lang.asFlow
import eu.kanade.tachiyomi.util.lang.runAsObservable
import eu.kanade.tachiyomi.util.lang.withUIContext
import exh.savedsearches.EXHSavedSearch
import exh.savedsearches.JsonSavedSearch
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.singleOrNull
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import rx.Observable
@ -99,7 +99,7 @@ open class IndexPresenter(
initializeFetchImageSubscription()
presenterScope.launch(Dispatchers.IO) {
withContext(Dispatchers.Main) {
withUIContext {
Observable.just(null).subscribeLatestCache({ view, results ->
view.setLatestManga(results)
})
@ -118,7 +118,7 @@ open class IndexPresenter(
}
fetchImage(results, true)
withContext(Dispatchers.Main) {
withUIContext {
Observable.just(results.map { IndexCardItem(it) }).subscribeLatestCache({ view, results ->
view.setLatestManga(results)
})
@ -127,7 +127,7 @@ open class IndexPresenter(
}
presenterScope.launch(Dispatchers.IO) {
withContext(Dispatchers.Main) {
withUIContext {
Observable.just(null).subscribeLatestCache({ view, results ->
view.setBrowseManga(results)
})
@ -146,7 +146,7 @@ open class IndexPresenter(
}
fetchImage(results, false)
withContext(Dispatchers.Main) {
withUIContext {
Observable.just(results.map { IndexCardItem(it) }).subscribeLatestCache({ view, results ->
view.setBrowseManga(results)
})

View File

@ -36,7 +36,6 @@ import reactivecircus.flowbinding.recyclerview.scrollStateChanges
import reactivecircus.flowbinding.swiperefreshlayout.refreshes
import rx.android.schedulers.AndroidSchedulers
import rx.subscriptions.CompositeSubscription
import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy
import java.util.concurrent.TimeUnit

View File

@ -30,6 +30,7 @@ import eu.kanade.tachiyomi.util.lang.awaitSingle
import eu.kanade.tachiyomi.util.lang.byteSize
import eu.kanade.tachiyomi.util.lang.launchIO
import eu.kanade.tachiyomi.util.lang.takeBytes
import eu.kanade.tachiyomi.util.lang.withIOContext
import eu.kanade.tachiyomi.util.storage.DiskUtil
import eu.kanade.tachiyomi.util.system.ImageUtil
import eu.kanade.tachiyomi.util.updateCoverLastModified
@ -44,11 +45,9 @@ import exh.metadata.metadata.base.getFlatMetadataForManga
import exh.source.getMainSource
import exh.util.defaultReaderType
import exh.util.shouldDeleteChapters
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import rx.Observable
import rx.Subscription
import rx.android.schedulers.AndroidSchedulers
@ -310,7 +309,7 @@ class ReaderPresenter(
// SY -->
suspend fun getChapters(context: Context): List<ReaderChapterItem> {
return withContext(Dispatchers.IO) {
return withIOContext {
val currentChapter = getCurrentChapter()
val decimalFormat = DecimalFormat(
"#.###",

View File

@ -18,12 +18,6 @@ import exh.metadata.metadata.base.insertFlatMetadata
import exh.util.await
import exh.util.floor
import exh.util.nullIfZero
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.intOrNull
import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive
import okhttp3.Response
import rx.Completable
import rx.Single

View File

@ -10,7 +10,7 @@ import exh.md.utils.MdUtil
import exh.md.utils.setMDUrlWithoutDomain
import okhttp3.CacheControl
import okhttp3.Headers
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
@ -75,7 +75,7 @@ class SearchHandler(val client: OkHttpClient, private val headers: Headers, val
val demographics = mutableListOf<String>()
// Do traditional search
val url = "${MdUtil.baseUrl}/?page=search".toHttpUrlOrNull()!!.newBuilder()
val url = "${MdUtil.baseUrl}/?page=search".toHttpUrl().newBuilder()
.addQueryParameter("p", page.toString())
.addQueryParameter("title", query.replace(WHITESPACE_REGEX, " "))

View File

@ -21,4 +21,4 @@ data class ChapterPageSerializer(
val pages: List<String>,
val server: String,
val mangaId: Int
)
)

View File

@ -49,13 +49,11 @@ object SourceTagsUtil {
}
fun parseTag(tag: String) = RaisedTag(
(
if (tag.startsWith("-")) {
tag.substringAfter("-")
} else {
tag
}
).substringBefore(':', missingDelimiterValue = "").trimOrNull(),
if (tag.startsWith("-")) {
tag.substringAfter("-")
} else {
tag
}.substringBefore(':', missingDelimiterValue = "").trimOrNull(),
tag.substringAfter(':', missingDelimiterValue = tag).trim(),
if (tag.startsWith("-")) TAG_TYPE_EXCLUDE else TAG_TYPE_DEFAULT
)
@ -94,6 +92,6 @@ object SourceTagsUtil {
private const val TAG_TYPE_DEFAULT = 1
}
fun Manga.getRaisedTags(genres: List<String>? = null): List<RaisedTag>? = (genres ?: this.getGenres())?.map {
fun Manga.getRaisedTags(genres: List<String>? = getGenres()): List<RaisedTag>? = genres?.map {
SourceTagsUtil.parseTag(it)
}