diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/all/MergedSource.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/all/MergedSource.kt index c80224221..6e77e18ac 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/source/online/all/MergedSource.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/online/all/MergedSource.kt @@ -1,22 +1,31 @@ package eu.kanade.tachiyomi.source.online.all +import android.util.Log +import com.elvishew.xlog.XLog import com.github.salomonbrys.kotson.fromJson import com.google.gson.Gson import com.google.gson.annotations.SerializedName -import com.lvla.rxjava.interopkt.toV1Observable -import com.lvla.rxjava.interopkt.toV1Single import eu.kanade.tachiyomi.data.database.DatabaseHelper import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.source.SourceManager -import eu.kanade.tachiyomi.source.model.* +import eu.kanade.tachiyomi.source.model.FilterList +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.source.online.HttpSource import exh.MERGED_SOURCE_ID import exh.util.await +import hu.akarnokd.rxjava.interop.RxJavaInterop import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.async -import kotlinx.coroutines.flow.* +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.asFlow +import kotlinx.coroutines.flow.buffer +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.take +import kotlinx.coroutines.flow.toList import kotlinx.coroutines.rx2.asFlowable import kotlinx.coroutines.rx2.asSingle import okhttp3.Response @@ -43,63 +52,74 @@ class MergedSource : HttpSource() { override fun latestUpdatesParse(response: Response) = throw UnsupportedOperationException() override fun fetchMangaDetails(manga: SManga): Observable { - return readMangaConfig(manga).load(db, sourceManager).take(1).map { loaded -> - SManga.create().apply { - this.copyFrom(loaded.manga) - url = manga.url - } - }.asFlowable().toV1Observable() - } - override fun fetchChapterList(manga: SManga): Observable> { - return GlobalScope.async(Dispatchers.IO) { - val loadedMangas = readMangaConfig(manga).load(db, sourceManager).buffer() - loadedMangas.map { loadedManga -> - async(Dispatchers.IO) { - loadedManga.source.fetchChapterList(loadedManga.manga).map { chapterList -> - chapterList.map { chapter -> - chapter.apply { - url = writeUrlConfig(UrlConfig(loadedManga.source.id, url, loadedManga.manga.url)) - } - } - }.toSingle().await(Schedulers.io()) + return RxJavaInterop.toV1Observable( + readMangaConfig(manga).load(db, sourceManager).take(1).map { loaded -> + SManga.create().apply { + this.copyFrom(loaded.manga) + url = manga.url } - }.buffer().map { it.await() }.toList().flatten() - }.asSingle(Dispatchers.IO).toV1Single().toObservable() + }.asFlowable() + ) } + + override fun fetchChapterList(manga: SManga): Observable> { + return RxJavaInterop.toV1Single( + GlobalScope.async(Dispatchers.IO) { + val loadedMangas = readMangaConfig(manga).load(db, sourceManager).buffer() + loadedMangas.map { loadedManga -> + async(Dispatchers.IO) { + loadedManga.source.fetchChapterList(loadedManga.manga).map { chapterList -> + chapterList.map { chapter -> + chapter.apply { + url = writeUrlConfig(UrlConfig(loadedManga.source.id, url, loadedManga.manga.url)) + } + } + }.toSingle().await(Schedulers.io()) + } + }.buffer().map { it.await() }.toList().flatten() + }.asSingle(Dispatchers.IO) + ).toObservable() + } + override fun mangaDetailsParse(response: Response) = throw UnsupportedOperationException() override fun chapterListParse(response: Response) = throw UnsupportedOperationException() override fun fetchPageList(chapter: SChapter): Observable> { val config = readUrlConfig(chapter.url) val source = sourceManager.getOrStub(config.source) - return source.fetchPageList(SChapter.create().apply { - copyFrom(chapter) - url = config.url - }).map { pages -> + return source.fetchPageList( + SChapter.create().apply { + copyFrom(chapter) + url = config.url + } + ).map { pages -> pages.map { page -> page.copyWithUrl(writeUrlConfig(UrlConfig(config.source, page.url, config.mangaUrl))) } } } + override fun fetchImageUrl(page: Page): Observable { val config = readUrlConfig(page.url) val source = sourceManager.getOrStub(config.source) as? HttpSource - ?: throw UnsupportedOperationException("This source does not support this operation!") + ?: throw UnsupportedOperationException("This source does not support this operation!") return source.fetchImageUrl(page.copyWithUrl(config.url)) } + override fun pageListParse(response: Response) = throw UnsupportedOperationException() override fun imageUrlParse(response: Response) = throw UnsupportedOperationException() override fun fetchImage(page: Page): Observable { val config = readUrlConfig(page.url) val source = sourceManager.getOrStub(config.source) as? HttpSource - ?: throw UnsupportedOperationException("This source does not support this operation!") + ?: throw UnsupportedOperationException("This source does not support this operation!") return source.fetchImage(page.copyWithUrl(config.url)) } + override fun prepareNewChapter(chapter: SChapter, manga: SManga) { val chapterConfig = readUrlConfig(chapter.url) val source = sourceManager.getOrStub(chapterConfig.source) as? HttpSource - ?: throw UnsupportedOperationException("This source does not support this operation!") + ?: throw UnsupportedOperationException("This source does not support this operation!") val copiedManga = SManga.create().apply { this.copyFrom(manga) url = chapterConfig.mangaUrl @@ -107,40 +127,48 @@ class MergedSource : HttpSource() { chapter.url = chapterConfig.url source.prepareNewChapter(chapter, copiedManga) chapter.url = writeUrlConfig(UrlConfig(source.id, chapter.url, chapterConfig.mangaUrl)) - chapter.scanlator = if(chapter.scanlator.isNullOrBlank()) source.name + chapter.scanlator = if (chapter.scanlator.isNullOrBlank()) source.name else "$source: ${chapter.scanlator}" } fun readMangaConfig(manga: SManga): MangaConfig { return MangaConfig.readFromUrl(gson, manga.url) } + fun readUrlConfig(url: String): UrlConfig { return gson.fromJson(url) } + fun writeUrlConfig(urlConfig: UrlConfig): String { return gson.toJson(urlConfig) } + data class LoadedMangaSource(val source: Source, val manga: Manga) data class MangaSource( - @SerializedName("s") - val source: Long, - @SerializedName("u") - val url: String + @SerializedName("s") + val source: Long, + @SerializedName("u") + val url: String ) { suspend fun load(db: DatabaseHelper, sourceManager: SourceManager): LoadedMangaSource? { - val manga = db.getManga(url, source).await() ?: return null + val manga = db.getManga(url, source).executeAsBlocking() ?: return null val source = sourceManager.getOrStub(source) return LoadedMangaSource(source, manga) } } + data class MangaConfig( - @SerializedName("c") - val children: List + @SerializedName("c") + val children: List ) { fun load(db: DatabaseHelper, sourceManager: SourceManager): Flow { return children.asFlow().map { mangaSource -> mangaSource.load(db, sourceManager) - ?: throw IllegalStateException("Missing source manga: $mangaSource") + ?: run { + XLog.w("> Missing source manga: $mangaSource") + Log.d("MERGED", "> Missing source manga: $mangaSource") + throw IllegalStateException("Missing source manga: $mangaSource") + } } } @@ -154,23 +182,24 @@ class MergedSource : HttpSource() { } } } + data class UrlConfig( - @SerializedName("s") - val source: Long, - @SerializedName("u") - val url: String, - @SerializedName("m") - val mangaUrl: String + @SerializedName("s") + val source: Long, + @SerializedName("u") + val url: String, + @SerializedName("m") + val mangaUrl: String ) fun Page.copyWithUrl(newUrl: String) = Page( - index, - newUrl, - imageUrl, - uri + index, + newUrl, + imageUrl, + uri ) override val lang = "all" override val supportsLatest = false override val name = "MergedSource" -} \ No newline at end of file +}