Do quite a bit of code cleanup
This commit is contained in:
parent
8db57aef6c
commit
3b364c91f1
@ -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()
|
||||
}
|
||||
}
|
@ -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
|
||||
)
|
||||
}
|
||||
|
@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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) {
|
||||
|
@ -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()
|
||||
|
@ -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)
|
||||
})
|
||||
|
@ -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
|
||||
|
||||
|
@ -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(
|
||||
"#.###",
|
||||
|
@ -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
|
||||
|
@ -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, " "))
|
||||
|
||||
|
@ -21,4 +21,4 @@ data class ChapterPageSerializer(
|
||||
val pages: List<String>,
|
||||
val server: String,
|
||||
val mangaId: Int
|
||||
)
|
||||
)
|
||||
|
@ -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)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user