From 28fca8c83960f58f8a6019bba431ce8a545a267b Mon Sep 17 00:00:00 2001 From: Jobobby04 Date: Sat, 2 Jan 2021 03:11:20 -0500 Subject: [PATCH] Make internal and delegated sources able to use getMangaDetails, getChapterList, and getPageList properly --- .../tachiyomi/source/online/MetadataSource.kt | 48 +++++++++++++++++++ .../tachiyomi/source/online/all/EHentai.kt | 36 ++++++++++++++ .../tachiyomi/source/online/all/Hitomi.kt | 8 ++++ .../tachiyomi/source/online/all/MangaDex.kt | 5 ++ .../tachiyomi/source/online/all/NHentai.kt | 8 ++++ .../tachiyomi/source/online/all/PervEden.kt | 8 ++++ .../source/online/english/EightMuses.kt | 8 ++++ .../source/online/english/HBrowse.kt | 8 ++++ .../source/online/english/HentaiCafe.kt | 38 ++++++++++++--- .../source/online/english/Pururin.kt | 8 ++++ .../source/online/english/Tsumino.kt | 8 ++++ .../java/exh/md/handlers/ApiMangaParser.kt | 20 ++++++++ .../main/java/exh/md/handlers/MangaHandler.kt | 9 ++++ .../metadata/EHentaiSearchMetadata.kt | 48 +++++++++++++++++++ .../metadata/EightMusesSearchMetadata.kt | 24 ++++++++++ .../metadata/HBrowseSearchMetadata.kt | 27 +++++++++++ .../metadata/HentaiCafeSearchMetadata.kt | 26 ++++++++++ .../metadata/metadata/HitomiSearchMetadata.kt | 25 ++++++++++ .../metadata/MangaDexSearchMetadata.kt | 38 +++++++++++++++ .../metadata/NHentaiSearchMetadata.kt | 48 +++++++++++++++++++ .../metadata/PervEdenSearchMetadata.kt | 31 ++++++++++++ .../metadata/PururinSearchMetadata.kt | 28 +++++++++++ .../metadata/TsuminoSearchMetadata.kt | 24 ++++++++++ .../metadata/base/RaisedSearchMetadata.kt | 9 ++++ .../java/exh/source/DelegatedHttpSource.kt | 26 ++++++++++ .../java/exh/source/EnhancedHttpSource.kt | 17 +++++++ 26 files changed, 576 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/MetadataSource.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/MetadataSource.kt index 767603132..b7c76a028 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/source/online/MetadataSource.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/online/MetadataSource.kt @@ -11,8 +11,10 @@ import eu.kanade.tachiyomi.ui.manga.MangaController import exh.metadata.metadata.base.RaisedSearchMetadata import exh.metadata.metadata.base.getFlatMetadataForManga import exh.metadata.metadata.base.insertFlatMetadata +import exh.util.await import rx.Completable import rx.Single +import tachiyomi.source.model.MangaInfo import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get import kotlin.reflect.KClass @@ -33,6 +35,8 @@ interface MetadataSource : CatalogueSource { */ fun parseIntoMetadata(metadata: M, input: I) + suspend fun parseInfoIntoMetadata(metadata: M, input: I) = parseIntoMetadata(metadata, input) + /** * Use reflection to create a new instance of metadata */ @@ -46,6 +50,7 @@ interface MetadataSource : CatalogueSource { * * Will also save the metadata to the DB if possible */ + @Deprecated("Use the MangaInfo variant") fun parseToManga(manga: SManga, input: I): Completable { val mangaId = manga.id val metaObservable = if (mangaId != null) { @@ -71,6 +76,22 @@ interface MetadataSource : CatalogueSource { } } + suspend fun parseToManga(manga: MangaInfo, input: I): MangaInfo { + val mangaId = manga.id() + val metadata = if (mangaId != null) { + val flatMetadata = db.getFlatMetadataForManga(mangaId).await() + flatMetadata?.raise(metaClass) ?: newMetaInstance() + } else newMetaInstance() + + parseInfoIntoMetadata(metadata, input) + if (mangaId != null) { + metadata.mangaId = mangaId + db.insertFlatMetadata(metadata.flatten()).await() + } + + return metadata.createMangaInfo(manga) + } + /** * Try to first get the metadata from the DB. If the metadata is not in the DB, calls the input * producer and parses the metadata from the input @@ -78,6 +99,7 @@ interface MetadataSource : CatalogueSource { * If the metadata needs to be parsed from the input producer, the resulting parsed metadata will * also be saved to the DB. */ + @Deprecated("use fetchOrLoadMetadata made for MangaInfo") fun getOrLoadMetadata(mangaId: Long?, inputProducer: () -> Single): Single { val metaObservable = if (mangaId != null) { // We have to use fromCallable because StorIO messes up the thread scheduling if we use their rx functions @@ -103,8 +125,34 @@ interface MetadataSource : CatalogueSource { } } + /** + * Try to first get the metadata from the DB. If the metadata is not in the DB, calls the input + * producer and parses the metadata from the input + * + * If the metadata needs to be parsed from the input producer, the resulting parsed metadata will + * also be saved to the DB. + */ + suspend fun fetchOrLoadMetadata(mangaId: Long?, inputProducer: suspend () -> I): M { + val meta = if (mangaId != null) { + val flatMetadata = db.getFlatMetadataForManga(mangaId).await() + flatMetadata?.raise(metaClass) + } else { + null + } + + return meta ?: inputProducer().let { input -> + val newMeta = newMetaInstance() + parseInfoIntoMetadata(newMeta, input) + if (mangaId != null) { + newMeta.mangaId = mangaId + db.insertFlatMetadata(newMeta.flatten()).let { newMeta } + } else newMeta + } + } + fun getDescriptionAdapter(controller: MangaController): RecyclerView.Adapter<*>? + suspend fun MangaInfo.id() = db.getManga(key, id).await()?.id val SManga.id get() = (this as? Manga)?.id val SChapter.mangaId get() = (this as? Chapter)?.manga_id } diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/all/EHentai.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/all/EHentai.kt index 0c72e28b1..63bd2c51c 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/source/online/all/EHentai.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/online/all/EHentai.kt @@ -9,6 +9,7 @@ import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.asObservableSuccess +import eu.kanade.tachiyomi.network.await import eu.kanade.tachiyomi.source.model.Filter import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.MangasPage @@ -16,6 +17,8 @@ import eu.kanade.tachiyomi.source.model.MetadataMangasPage 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.model.toChapterInfo +import eu.kanade.tachiyomi.source.model.toSManga import eu.kanade.tachiyomi.source.online.HttpSource import eu.kanade.tachiyomi.source.online.MetadataSource import eu.kanade.tachiyomi.source.online.NamespaceSource @@ -41,6 +44,7 @@ import exh.ui.metadata.adapters.EHentaiDescriptionAdapter import exh.util.UriFilter import exh.util.UriGroup import exh.util.asObservableWithAsyncStacktrace +import exh.util.awaitSingle import exh.util.dropBlank import exh.util.ignore import exh.util.nullIfBlank @@ -72,6 +76,8 @@ import org.jsoup.nodes.Element import org.jsoup.nodes.TextNode import rx.Observable import rx.Single +import tachiyomi.source.model.ChapterInfo +import tachiyomi.source.model.MangaInfo import uy.kohesive.injekt.injectLazy import java.net.URLEncoder import java.util.ArrayList @@ -276,8 +282,13 @@ class EHentai( MetadataMangasPage(mangaFromSource.first.map { it.manga }, mangaFromSource.second, mangaFromSource.first.map { it.metadata }) } + override suspend fun getChapterList(manga: MangaInfo): List = getChapterList(manga) {} + + suspend fun getChapterList(manga: MangaInfo, throttleFunc: () -> Unit) = fetchChapterList(manga.toSManga(), throttleFunc).awaitSingle().map { it.toChapterInfo() } + override fun fetchChapterList(manga: SManga) = fetchChapterList(manga) {} + @Deprecated("Use getChapterList instead") fun fetchChapterList(manga: SManga, throttleFunc: () -> Unit): Observable> { return Single.fromCallable { // Pull all the way to the root gallery @@ -516,6 +527,31 @@ class EHentai( } } + override suspend fun getMangaDetails(manga: MangaInfo): MangaInfo { + val exception = Exception("Async stacktrace") + val response = client.newCall(mangaDetailsRequest(manga.toSManga())).await() + if (response.isSuccessful) { + // Pull to most recent + val doc = response.asJsoup() + val newerGallery = doc.select("#gnd a").lastOrNull() + val pre = if (newerGallery != null && DebugToggles.PULL_TO_ROOT_WHEN_LOADING_EXH_MANGA_DETAILS.enabled) { + val sManga = manga.toSManga().apply { + url = EHentaiSearchMetadata.normalizeUrl(newerGallery.attr("href")) + } + client.newCall(mangaDetailsRequest(sManga)).await().asJsoup() + } else doc + return parseToManga(manga, pre) + } else { + response.close() + + if (response.code == 404) { + throw GalleryNotFoundException(exception) + } else { + throw Exception("HTTP error ${response.code}", exception) + } + } + } + /** * Parse gallery page to metadata model */ diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/all/Hitomi.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/all/Hitomi.kt index a46a3a8f8..c79a257bc 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/source/online/all/Hitomi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/online/all/Hitomi.kt @@ -4,9 +4,11 @@ import android.content.Context import android.net.Uri import android.os.Build import eu.kanade.tachiyomi.network.asObservableSuccess +import eu.kanade.tachiyomi.network.await import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.MangasPage import eu.kanade.tachiyomi.source.model.SManga +import eu.kanade.tachiyomi.source.model.toSManga import eu.kanade.tachiyomi.source.online.HttpSource import eu.kanade.tachiyomi.source.online.MetadataSource import eu.kanade.tachiyomi.source.online.NamespaceSource @@ -21,6 +23,7 @@ import exh.ui.metadata.adapters.HitomiDescriptionAdapter import exh.util.urlImportFetchSearchManga import org.jsoup.nodes.Document import rx.Observable +import tachiyomi.source.model.MangaInfo import java.text.SimpleDateFormat import java.util.Locale @@ -46,6 +49,11 @@ class Hitomi(delegate: HttpSource, val context: Context) : } } + override suspend fun getMangaDetails(manga: MangaInfo): MangaInfo { + val response = client.newCall(mangaDetailsRequest(manga.toSManga())).await() + return parseToManga(manga, response.asJsoup()) + } + override fun parseIntoMetadata(metadata: HitomiSearchMetadata, input: Document) { with(metadata) { url = input.location() diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/all/MangaDex.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/all/MangaDex.kt index 9dcaa838e..27465a5e8 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/source/online/all/MangaDex.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/online/all/MangaDex.kt @@ -57,6 +57,7 @@ import okhttp3.HttpUrl.Companion.toHttpUrlOrNull import okhttp3.Request import okhttp3.Response import rx.Observable +import tachiyomi.source.model.MangaInfo import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get import uy.kohesive.injekt.injectLazy @@ -126,6 +127,10 @@ class MangaDex(delegate: HttpSource, val context: Context) : return MangaHandler(client, headers, listOf(mdLang), preferences.mangaDexForceLatestCovers().get()).fetchMangaDetailsObservable(manga) } + override suspend fun getMangaDetails(manga: MangaInfo): MangaInfo { + return MangaHandler(client, headers, listOf(mdLang), preferences.mangaDexForceLatestCovers().get()).getMangaDetails(manga, id) + } + override fun fetchChapterList(manga: SManga): Observable> { return MangaHandler(client, headers, listOf(mdLang), preferences.mangaDexForceLatestCovers().get()).fetchChapterListObservable(manga) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/all/NHentai.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/all/NHentai.kt index 09a968b12..4fc61d02c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/source/online/all/NHentai.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/online/all/NHentai.kt @@ -4,9 +4,11 @@ import android.content.Context import android.content.SharedPreferences import android.net.Uri import eu.kanade.tachiyomi.network.asObservableSuccess +import eu.kanade.tachiyomi.network.await import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.MangasPage import eu.kanade.tachiyomi.source.model.SManga +import eu.kanade.tachiyomi.source.model.toSManga import eu.kanade.tachiyomi.source.online.HttpSource import eu.kanade.tachiyomi.source.online.MetadataSource import eu.kanade.tachiyomi.source.online.NamespaceSource @@ -24,6 +26,7 @@ import kotlinx.serialization.decodeFromString import kotlinx.serialization.json.Json import okhttp3.Response import rx.Observable +import tachiyomi.source.model.MangaInfo class NHentai(delegate: HttpSource, val context: Context) : DelegatedHttpSource(delegate), @@ -63,6 +66,11 @@ class NHentai(delegate: HttpSource, val context: Context) : } } + override suspend fun getMangaDetails(manga: MangaInfo): MangaInfo { + val response = client.newCall(mangaDetailsRequest(manga.toSManga())).await() + return parseToManga(manga, response) + } + override fun parseIntoMetadata(metadata: NHentaiSearchMetadata, input: Response) { val json = GALLERY_JSON_REGEX.find(input.body!!.string())!!.groupValues[1].replace( UNICODE_ESCAPE_REGEX diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/all/PervEden.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/all/PervEden.kt index 3031ecaaf..97991acea 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/source/online/all/PervEden.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/online/all/PervEden.kt @@ -4,9 +4,11 @@ import android.content.Context import android.net.Uri import androidx.core.net.toUri import eu.kanade.tachiyomi.network.asObservableSuccess +import eu.kanade.tachiyomi.network.await import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.MangasPage import eu.kanade.tachiyomi.source.model.SManga +import eu.kanade.tachiyomi.source.model.toSManga import eu.kanade.tachiyomi.source.online.HttpSource import eu.kanade.tachiyomi.source.online.MetadataSource import eu.kanade.tachiyomi.source.online.UrlImportableSource @@ -22,6 +24,7 @@ import org.jsoup.nodes.Document import org.jsoup.nodes.Element import org.jsoup.nodes.TextNode import rx.Observable +import tachiyomi.source.model.MangaInfo class PervEden(delegate: HttpSource, val context: Context) : DelegatedHttpSource(delegate), @@ -44,6 +47,11 @@ class PervEden(delegate: HttpSource, val context: Context) : } } + override suspend fun getMangaDetails(manga: MangaInfo): MangaInfo { + val response = client.newCall(mangaDetailsRequest(manga.toSManga())).await() + return parseToManga(manga, response.asJsoup()) + } + override fun parseIntoMetadata(metadata: PervEdenSearchMetadata, input: Document) { with(metadata) { url = input.location().toUri().path diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/english/EightMuses.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/english/EightMuses.kt index 11352148e..871db5a4d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/source/online/english/EightMuses.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/online/english/EightMuses.kt @@ -4,9 +4,11 @@ import android.content.Context import android.net.Uri import androidx.core.net.toUri import eu.kanade.tachiyomi.network.asObservableSuccess +import eu.kanade.tachiyomi.network.await import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.MangasPage import eu.kanade.tachiyomi.source.model.SManga +import eu.kanade.tachiyomi.source.model.toSManga import eu.kanade.tachiyomi.source.online.HttpSource import eu.kanade.tachiyomi.source.online.MetadataSource import eu.kanade.tachiyomi.source.online.NamespaceSource @@ -21,6 +23,7 @@ import exh.util.urlImportFetchSearchManga import org.jsoup.nodes.Document import org.jsoup.nodes.Element import rx.Observable +import tachiyomi.source.model.MangaInfo class EightMuses(delegate: HttpSource, val context: Context) : DelegatedHttpSource(delegate), @@ -44,6 +47,11 @@ class EightMuses(delegate: HttpSource, val context: Context) : } } + override suspend fun getMangaDetails(manga: MangaInfo): MangaInfo { + val response = client.newCall(mangaDetailsRequest(manga.toSManga())).await() + return parseToManga(manga, response.asJsoup()) + } + data class SelfContents(val albums: List, val images: List) private fun parseSelf(doc: Document): SelfContents { diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/english/HBrowse.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/english/HBrowse.kt index 44378868d..090bf7f66 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/source/online/english/HBrowse.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/online/english/HBrowse.kt @@ -3,9 +3,11 @@ package eu.kanade.tachiyomi.source.online.english import android.content.Context import android.net.Uri import eu.kanade.tachiyomi.network.asObservableSuccess +import eu.kanade.tachiyomi.network.await import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.MangasPage import eu.kanade.tachiyomi.source.model.SManga +import eu.kanade.tachiyomi.source.model.toSManga import eu.kanade.tachiyomi.source.online.HttpSource import eu.kanade.tachiyomi.source.online.MetadataSource import eu.kanade.tachiyomi.source.online.NamespaceSource @@ -20,6 +22,7 @@ import exh.util.urlImportFetchSearchManga import org.jsoup.nodes.Document import org.jsoup.nodes.Element import rx.Observable +import tachiyomi.source.model.MangaInfo class HBrowse(delegate: HttpSource, val context: Context) : DelegatedHttpSource(delegate), @@ -43,6 +46,11 @@ class HBrowse(delegate: HttpSource, val context: Context) : } } + override suspend fun getMangaDetails(manga: MangaInfo): MangaInfo { + val response = client.newCall(mangaDetailsRequest(manga.toSManga())).await() + return parseToManga(manga, response.asJsoup()) + } + override fun parseIntoMetadata(metadata: HBrowseSearchMetadata, input: Document) { val tables = parseIntoTables(input) with(metadata) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/english/HentaiCafe.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/english/HentaiCafe.kt index 6c7423714..059005ac3 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/source/online/english/HentaiCafe.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/online/english/HentaiCafe.kt @@ -3,14 +3,17 @@ package eu.kanade.tachiyomi.source.online.english import android.content.Context import android.net.Uri import eu.kanade.tachiyomi.network.asObservableSuccess +import eu.kanade.tachiyomi.network.await import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SManga +import eu.kanade.tachiyomi.source.model.toSManga import eu.kanade.tachiyomi.source.online.HttpSource import eu.kanade.tachiyomi.source.online.MetadataSource import eu.kanade.tachiyomi.source.online.UrlImportableSource import eu.kanade.tachiyomi.ui.manga.MangaController import eu.kanade.tachiyomi.util.asJsoup +import eu.kanade.tachiyomi.util.lang.runAsObservable import exh.metadata.metadata.HentaiCafeSearchMetadata import exh.metadata.metadata.HentaiCafeSearchMetadata.Companion.TAG_TYPE_DEFAULT import exh.metadata.metadata.base.RaisedSearchMetadata.Companion.TAG_TYPE_VIRTUAL @@ -21,6 +24,8 @@ import exh.util.urlImportFetchSearchManga import okhttp3.HttpUrl.Companion.toHttpUrlOrNull import org.jsoup.nodes.Document import rx.Observable +import tachiyomi.source.model.ChapterInfo +import tachiyomi.source.model.MangaInfo class HentaiCafe(delegate: HttpSource, val context: Context) : DelegatedHttpSource(delegate), @@ -56,6 +61,11 @@ class HentaiCafe(delegate: HttpSource, val context: Context) : } } + override suspend fun getMangaDetails(manga: MangaInfo): MangaInfo { + val response = client.newCall(mangaDetailsRequest(manga.toSManga())).await() + return parseToManga(manga, response.asJsoup()) + } + /** * Parse the supplied input into the supplied metadata object */ @@ -86,12 +96,12 @@ class HentaiCafe(delegate: HttpSource, val context: Context) : } } - override fun fetchChapterList(manga: SManga) = getOrLoadMetadata(manga.id) { - client.newCall(mangaDetailsRequest(manga)) - .asObservableSuccess() - .map { it.asJsoup() } - .toSingle() - }.map { + override fun fetchChapterList(manga: SManga) = runAsObservable({ + fetchOrLoadMetadata(manga.id) { + val response = client.newCall(mangaDetailsRequest(manga)).await() + response.asJsoup() + } + }).map { listOf( SChapter.create().apply { url = "/manga/read/${it.readerId}/en/0/1/" @@ -99,7 +109,21 @@ class HentaiCafe(delegate: HttpSource, val context: Context) : chapter_number = 0.0f } ) - }.toObservable() + } + + override suspend fun getChapterList(manga: MangaInfo): List { + val metadata = fetchOrLoadMetadata(manga.id()) { + val response = client.newCall(mangaDetailsRequest(manga.toSManga())).await() + response.asJsoup() + } + return listOf( + ChapterInfo( + key = "/manga/read/${metadata.readerId}/en/0/1/", + name = "Chapter", + number = 0F + ) + ) + } override val matchingHosts = listOf( "hentai.cafe" diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/english/Pururin.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/english/Pururin.kt index 3aba4c479..48d81aa57 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/source/online/english/Pururin.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/online/english/Pururin.kt @@ -4,9 +4,11 @@ import android.content.Context import android.net.Uri import androidx.core.net.toUri import eu.kanade.tachiyomi.network.asObservableSuccess +import eu.kanade.tachiyomi.network.await import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.MangasPage import eu.kanade.tachiyomi.source.model.SManga +import eu.kanade.tachiyomi.source.model.toSManga import eu.kanade.tachiyomi.source.online.HttpSource import eu.kanade.tachiyomi.source.online.MetadataSource import eu.kanade.tachiyomi.source.online.NamespaceSource @@ -23,6 +25,7 @@ import exh.util.trimAll import exh.util.urlImportFetchSearchManga import org.jsoup.nodes.Document import rx.Observable +import tachiyomi.source.model.MangaInfo class Pururin(delegate: HttpSource, val context: Context) : DelegatedHttpSource(delegate), @@ -60,6 +63,11 @@ class Pururin(delegate: HttpSource, val context: Context) : } } + override suspend fun getMangaDetails(manga: MangaInfo): MangaInfo { + val response = client.newCall(mangaDetailsRequest(manga.toSManga())).await() + return parseToManga(manga, response.asJsoup()) + } + override fun parseIntoMetadata(metadata: PururinSearchMetadata, input: Document) { val selfLink = input.select("[itemprop=name]").last().parent() val parsedSelfLink = selfLink.attr("href").toUri().pathSegments diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/english/Tsumino.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/english/Tsumino.kt index add4dc700..545be7a6c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/source/online/english/Tsumino.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/online/english/Tsumino.kt @@ -3,9 +3,11 @@ package eu.kanade.tachiyomi.source.online.english import android.content.Context import android.net.Uri import eu.kanade.tachiyomi.network.asObservableSuccess +import eu.kanade.tachiyomi.network.await import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.MangasPage import eu.kanade.tachiyomi.source.model.SManga +import eu.kanade.tachiyomi.source.model.toSManga import eu.kanade.tachiyomi.source.online.HttpSource import eu.kanade.tachiyomi.source.online.MetadataSource import eu.kanade.tachiyomi.source.online.NamespaceSource @@ -23,6 +25,7 @@ import exh.util.trimAll import exh.util.urlImportFetchSearchManga import org.jsoup.nodes.Document import rx.Observable +import tachiyomi.source.model.MangaInfo import java.text.SimpleDateFormat import java.util.Locale @@ -56,6 +59,11 @@ class Tsumino(delegate: HttpSource, val context: Context) : } } + override suspend fun getMangaDetails(manga: MangaInfo): MangaInfo { + val response = client.newCall(mangaDetailsRequest(manga.toSManga())).await() + return parseToManga(manga, response.asJsoup()) + } + override fun parseIntoMetadata(metadata: TsuminoSearchMetadata, input: Document) { with(metadata) { tmId = TsuminoSearchMetadata.tmIdFromUrl(input.location())!!.toInt() diff --git a/app/src/main/java/exh/md/handlers/ApiMangaParser.kt b/app/src/main/java/exh/md/handlers/ApiMangaParser.kt index ab27f69ad..42753ac45 100644 --- a/app/src/main/java/exh/md/handlers/ApiMangaParser.kt +++ b/app/src/main/java/exh/md/handlers/ApiMangaParser.kt @@ -14,6 +14,7 @@ import exh.metadata.metadata.MangaDexSearchMetadata import exh.metadata.metadata.base.RaisedTag import exh.metadata.metadata.base.getFlatMetadataForManga import exh.metadata.metadata.base.insertFlatMetadata +import exh.util.await import exh.util.floor import exh.util.nullIfZero import kotlinx.serialization.decodeFromString @@ -24,6 +25,7 @@ import kotlinx.serialization.json.jsonPrimitive import okhttp3.Response import rx.Completable import rx.Single +import tachiyomi.source.model.MangaInfo import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get @@ -70,6 +72,24 @@ class ApiMangaParser(private val langs: List) { } } + suspend fun parseToManga(manga: MangaInfo, input: Response, forceLatestCover: Boolean, sourceId: Long): MangaInfo { + val mangaId = db.getManga(manga.key, sourceId).await()?.id + val metadata = if (mangaId != null) { + val flatMetadata = db.getFlatMetadataForManga(mangaId).await() + flatMetadata?.raise(metaClass) ?: newMetaInstance() + } else newMetaInstance() + + parseInfoIntoMetadata(metadata, input, forceLatestCover) + if (mangaId != null) { + metadata.mangaId = mangaId + db.insertFlatMetadata(metadata.flatten()).await() + } + + return metadata.createMangaInfo(manga) + } + + fun parseInfoIntoMetadata(metadata: MangaDexSearchMetadata, input: Response, forceLatestCover: Boolean) = parseIntoMetadata(metadata, input, forceLatestCover) + fun parseIntoMetadata(metadata: MangaDexSearchMetadata, input: Response, forceLatestCover: Boolean) { with(metadata) { try { diff --git a/app/src/main/java/exh/md/handlers/MangaHandler.kt b/app/src/main/java/exh/md/handlers/MangaHandler.kt index f3fd5386f..3a1789f5a 100644 --- a/app/src/main/java/exh/md/handlers/MangaHandler.kt +++ b/app/src/main/java/exh/md/handlers/MangaHandler.kt @@ -6,6 +6,7 @@ import eu.kanade.tachiyomi.network.asObservableSuccess import eu.kanade.tachiyomi.network.await import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SManga +import eu.kanade.tachiyomi.source.model.toSManga import exh.md.utils.MdUtil import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext @@ -14,6 +15,7 @@ import okhttp3.Headers import okhttp3.OkHttpClient import okhttp3.Request import rx.Observable +import tachiyomi.source.model.MangaInfo class MangaHandler(val client: OkHttpClient, val headers: Headers, val langs: List, val forceLatestCovers: Boolean = false) { @@ -56,6 +58,13 @@ class MangaHandler(val client: OkHttpClient, val headers: Headers, val langs: Li } } + suspend fun getMangaDetails(manga: MangaInfo, sourceId: Long): MangaInfo { + return withContext(Dispatchers.IO) { + val response = client.newCall(apiRequest(manga.toSManga())).await() + ApiMangaParser(langs).parseToManga(manga, response, forceLatestCovers, sourceId) + } + } + fun fetchMangaDetailsObservable(manga: SManga): Observable { return client.newCall(apiRequest(manga)) .asObservableSuccess() diff --git a/app/src/main/java/exh/metadata/metadata/EHentaiSearchMetadata.kt b/app/src/main/java/exh/metadata/metadata/EHentaiSearchMetadata.kt index 8a141a271..9a3b785b9 100644 --- a/app/src/main/java/exh/metadata/metadata/EHentaiSearchMetadata.kt +++ b/app/src/main/java/exh/metadata/metadata/EHentaiSearchMetadata.kt @@ -8,6 +8,7 @@ import eu.kanade.tachiyomi.source.model.SManga import exh.metadata.MetadataUtil import exh.metadata.metadata.base.RaisedSearchMetadata import kotlinx.serialization.Serializable +import tachiyomi.source.model.MangaInfo import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get import java.util.Date @@ -42,6 +43,53 @@ class EHentaiSearchMetadata : RaisedSearchMetadata() { var aged: Boolean = false var lastUpdateCheck: Long = 0 + override fun createMangaInfo(manga: MangaInfo): MangaInfo { + val key = gId?.let { gId -> + gToken?.let { gToken -> + idAndTokenToUrl(gId, gToken) + } + } + val cover = thumbnailUrl + + // No title bug? + val title = if (Injekt.get().useJapaneseTitle().get()) { + altTitle ?: title + } else { + title + } + + // Set artist (if we can find one) + val artist = tags.filter { it.namespace == EH_ARTIST_NAMESPACE }.let { tags -> + if (tags.isNotEmpty()) tags.joinToString(transform = { it.name }) else null + } + + // Copy tags -> genres + val genres = tagsToGenreList() + + // Try to automatically identify if it is ongoing, we try not to be too lenient here to avoid making mistakes + // We default to completed + var status = MangaInfo.COMPLETED + title?.let { t -> + MetadataUtil.ONGOING_SUFFIX.find { + t.endsWith(it, ignoreCase = true) + }?.let { + status = MangaInfo.ONGOING + } + } + + val description = "meta" + + return manga.copy( + key = key ?: manga.key, + title = title ?: manga.title, + artist = artist ?: manga.artist, + description = description, + genres = genres, + status = status, + cover = cover ?: manga.cover + ) + } + override fun copyTo(manga: SManga) { gId?.let { gId -> gToken?.let { gToken -> diff --git a/app/src/main/java/exh/metadata/metadata/EightMusesSearchMetadata.kt b/app/src/main/java/exh/metadata/metadata/EightMusesSearchMetadata.kt index 446efe4e9..d0990f135 100644 --- a/app/src/main/java/exh/metadata/metadata/EightMusesSearchMetadata.kt +++ b/app/src/main/java/exh/metadata/metadata/EightMusesSearchMetadata.kt @@ -5,6 +5,7 @@ import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.source.model.SManga import exh.metadata.metadata.base.RaisedSearchMetadata import kotlinx.serialization.Serializable +import tachiyomi.source.model.MangaInfo @Serializable class EightMusesSearchMetadata : RaisedSearchMetadata() { @@ -14,6 +15,29 @@ class EightMusesSearchMetadata : RaisedSearchMetadata() { var thumbnailUrl: String? = null + override fun createMangaInfo(manga: MangaInfo): MangaInfo { + val key = path.joinToString("/", prefix = "/") + + val title = title + + val cover = thumbnailUrl + + val artist = tags.ofNamespace(ARTIST_NAMESPACE).joinToString { it.name } + + val genres = tagsToGenreList() + + val description = "meta" + + return manga.copy( + key = key, + title = title ?: manga.title, + cover = cover ?: manga.cover, + artist = artist, + genres = genres, + description = description + ) + } + override fun copyTo(manga: SManga) { manga.url = path.joinToString("/", prefix = "/") diff --git a/app/src/main/java/exh/metadata/metadata/HBrowseSearchMetadata.kt b/app/src/main/java/exh/metadata/metadata/HBrowseSearchMetadata.kt index 3d6788af5..b06a2acfd 100644 --- a/app/src/main/java/exh/metadata/metadata/HBrowseSearchMetadata.kt +++ b/app/src/main/java/exh/metadata/metadata/HBrowseSearchMetadata.kt @@ -5,6 +5,7 @@ import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.source.model.SManga import exh.metadata.metadata.base.RaisedSearchMetadata import kotlinx.serialization.Serializable +import tachiyomi.source.model.MangaInfo @Serializable class HBrowseSearchMetadata : RaisedSearchMetadata() { @@ -19,6 +20,32 @@ class HBrowseSearchMetadata : RaisedSearchMetadata() { // Length in pages var length: Int? = null + override fun createMangaInfo(manga: MangaInfo): MangaInfo { + val key = hbUrl + + val title = title + + // Guess thumbnail URL if manga does not have thumbnail URL + val cover = if (manga.cover.isBlank()) { + guessThumbnailUrl(hbId.toString()) + } else null + + val artist = tags.ofNamespace(ARTIST_NAMESPACE).joinToString { it.name } + + val genres = tagsToGenreList() + + val description = "meta" + + return manga.copy( + key = key ?: manga.key, + title = title ?: manga.title, + cover = cover ?: manga.cover, + artist = artist, + genres = genres, + description = description + ) + } + override fun copyTo(manga: SManga) { hbUrl?.let { manga.url = it diff --git a/app/src/main/java/exh/metadata/metadata/HentaiCafeSearchMetadata.kt b/app/src/main/java/exh/metadata/metadata/HentaiCafeSearchMetadata.kt index b8568207e..758fc0cc7 100644 --- a/app/src/main/java/exh/metadata/metadata/HentaiCafeSearchMetadata.kt +++ b/app/src/main/java/exh/metadata/metadata/HentaiCafeSearchMetadata.kt @@ -5,6 +5,7 @@ import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.source.model.SManga import exh.metadata.metadata.base.RaisedSearchMetadata import kotlinx.serialization.Serializable +import tachiyomi.source.model.MangaInfo @Serializable class HentaiCafeSearchMetadata : RaisedSearchMetadata() { @@ -24,6 +25,31 @@ class HentaiCafeSearchMetadata : RaisedSearchMetadata() { var artist: String? = null + override fun createMangaInfo(manga: MangaInfo): MangaInfo { + val cover = thumbnailUrl + + val title = title + val artist = artist + val author = artist + + // Not available + val status = MangaInfo.UNKNOWN + + val genres = tagsToGenreList() + + val description = "meta" + + return manga.copy( + cover = cover ?: manga.cover, + title = title ?: manga.title, + artist = artist ?: manga.artist, + author = author ?: manga.author, + status = status, + genres = genres, + description = description + ) + } + override fun copyTo(manga: SManga) { thumbnailUrl?.let { manga.thumbnail_url = it } diff --git a/app/src/main/java/exh/metadata/metadata/HitomiSearchMetadata.kt b/app/src/main/java/exh/metadata/metadata/HitomiSearchMetadata.kt index c35fa888b..1f9fd6063 100644 --- a/app/src/main/java/exh/metadata/metadata/HitomiSearchMetadata.kt +++ b/app/src/main/java/exh/metadata/metadata/HitomiSearchMetadata.kt @@ -6,6 +6,7 @@ import eu.kanade.tachiyomi.source.model.SManga import exh.metadata.MetadataUtil import exh.metadata.metadata.base.RaisedSearchMetadata import kotlinx.serialization.Serializable +import tachiyomi.source.model.MangaInfo import java.util.Date @Serializable @@ -37,6 +38,30 @@ class HitomiSearchMetadata : RaisedSearchMetadata() { var uploadDate: Long? = null + override fun createMangaInfo(manga: MangaInfo): MangaInfo { + val cover = thumbnailUrl + + val title = title + + // Copy tags -> genres + val genres = tagsToGenreList() + + val artist = artists.joinToString() + + val status = MangaInfo.UNKNOWN + + val description = "meta" + + return manga.copy( + cover = cover ?: manga.cover, + title = title ?: manga.title, + genres = genres, + artist = artist, + status = status, + description = description + ) + } + override fun copyTo(manga: SManga) { thumbnailUrl?.let { manga.thumbnail_url = it } diff --git a/app/src/main/java/exh/metadata/metadata/MangaDexSearchMetadata.kt b/app/src/main/java/exh/metadata/metadata/MangaDexSearchMetadata.kt index c1d2b9236..4966cf33d 100644 --- a/app/src/main/java/exh/metadata/metadata/MangaDexSearchMetadata.kt +++ b/app/src/main/java/exh/metadata/metadata/MangaDexSearchMetadata.kt @@ -6,6 +6,7 @@ import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.source.model.SManga import exh.metadata.metadata.base.RaisedSearchMetadata import kotlinx.serialization.Serializable +import tachiyomi.source.model.MangaInfo @Serializable class MangaDexSearchMetadata : RaisedSearchMetadata() { @@ -40,6 +41,43 @@ class MangaDexSearchMetadata : RaisedSearchMetadata() { var follow_status: Int? = null + override fun createMangaInfo(manga: MangaInfo): MangaInfo { + val key = mdUrl?.let { + try { + val uri = it.toUri() + val out = uri.path!!.removePrefix("/api") + out + if (out.endsWith("/")) "" else "/" + } catch (e: Exception) { + it + } + } + + val title = title + + val cover = thumbnail_url + + val author = author + + val artist = artist + + val status = status + + val genres = tagsToGenreList() + + val description = description + + return manga.copy( + key = key ?: manga.key, + title = title ?: manga.title, + cover = cover ?: manga.cover, + author = author ?: manga.author, + artist = artist ?: manga.artist, + status = status ?: manga.status, + genres = genres, + description = description ?: manga.description + ) + } + override fun copyTo(manga: SManga) { mdUrl?.let { manga.url = try { diff --git a/app/src/main/java/exh/metadata/metadata/NHentaiSearchMetadata.kt b/app/src/main/java/exh/metadata/metadata/NHentaiSearchMetadata.kt index 37e2562a5..99c52edb2 100644 --- a/app/src/main/java/exh/metadata/metadata/NHentaiSearchMetadata.kt +++ b/app/src/main/java/exh/metadata/metadata/NHentaiSearchMetadata.kt @@ -6,6 +6,7 @@ import eu.kanade.tachiyomi.source.model.SManga import exh.metadata.MetadataUtil import exh.metadata.metadata.base.RaisedSearchMetadata import kotlinx.serialization.Serializable +import tachiyomi.source.model.MangaInfo import java.util.Date @Serializable @@ -37,6 +38,53 @@ class NHentaiSearchMetadata : RaisedSearchMetadata() { var preferredTitle: Int? = null + override fun createMangaInfo(manga: MangaInfo): MangaInfo { + val key = nhId?.let { nhIdToPath(it) } + + val cover = if (mediaId != null) { + typeToExtension(coverImageType)?.let { + "https://t.nhentai.net/galleries/$mediaId/cover.$it" + } + } else null + + val title = when (preferredTitle) { + TITLE_TYPE_SHORT -> shortTitle ?: englishTitle ?: japaneseTitle ?: manga.title + 0, TITLE_TYPE_ENGLISH -> englishTitle ?: japaneseTitle ?: shortTitle ?: manga.title + else -> englishTitle ?: japaneseTitle ?: shortTitle ?: manga.title + } + + // Set artist (if we can find one) + val artist = tags.filter { it.namespace == NHENTAI_ARTIST_NAMESPACE }.let { tags -> + if (tags.isNotEmpty()) tags.joinToString(transform = { it.name }) else null + } + + // Copy tags -> genres + val genres = tagsToGenreList() + + // Try to automatically identify if it is ongoing, we try not to be too lenient here to avoid making mistakes + // We default to completed + var status = SManga.COMPLETED + englishTitle?.let { t -> + MetadataUtil.ONGOING_SUFFIX.find { + t.endsWith(it, ignoreCase = true) + }?.let { + status = SManga.ONGOING + } + } + + val description = "meta" + + return manga.copy( + key = key ?: manga.key, + cover = cover ?: manga.cover, + title = title, + artist = artist ?: manga.artist, + genres = genres, + status = status, + description = description + ) + } + override fun copyTo(manga: SManga) { nhId?.let { manga.url = nhIdToPath(it) } diff --git a/app/src/main/java/exh/metadata/metadata/PervEdenSearchMetadata.kt b/app/src/main/java/exh/metadata/metadata/PervEdenSearchMetadata.kt index fb8c769f4..5db018688 100644 --- a/app/src/main/java/exh/metadata/metadata/PervEdenSearchMetadata.kt +++ b/app/src/main/java/exh/metadata/metadata/PervEdenSearchMetadata.kt @@ -7,6 +7,7 @@ import eu.kanade.tachiyomi.source.model.SManga import exh.metadata.metadata.base.RaisedSearchMetadata import exh.metadata.metadata.base.RaisedTitle import kotlinx.serialization.Serializable +import tachiyomi.source.model.MangaInfo @Serializable class PervEdenSearchMetadata : RaisedSearchMetadata() { @@ -33,6 +34,36 @@ class PervEdenSearchMetadata : RaisedSearchMetadata() { var lang: String? = null + override fun createMangaInfo(manga: MangaInfo): MangaInfo { + val key = url + val cover = thumbnailUrl + + val title = title + + val artist = artist + + val status = when (status) { + "Ongoing" -> MangaInfo.ONGOING + "Completed", "Suspended" -> MangaInfo.COMPLETED + else -> MangaInfo.UNKNOWN + } + + // Copy tags -> genres + val genres = tagsToGenreList() + + val description = "meta" + + return manga.copy( + key = key ?: manga.key, + cover = cover ?: manga.cover, + title = title ?: manga.title, + artist = artist ?: manga.artist, + status = status, + genres = genres, + description = description + ) + } + override fun copyTo(manga: SManga) { url?.let { manga.url = it } thumbnailUrl?.let { manga.thumbnail_url = it } diff --git a/app/src/main/java/exh/metadata/metadata/PururinSearchMetadata.kt b/app/src/main/java/exh/metadata/metadata/PururinSearchMetadata.kt index 3e848879c..b26538af9 100644 --- a/app/src/main/java/exh/metadata/metadata/PururinSearchMetadata.kt +++ b/app/src/main/java/exh/metadata/metadata/PururinSearchMetadata.kt @@ -5,6 +5,7 @@ import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.source.model.SManga import exh.metadata.metadata.base.RaisedSearchMetadata import kotlinx.serialization.Serializable +import tachiyomi.source.model.MangaInfo @Serializable class PururinSearchMetadata : RaisedSearchMetadata() { @@ -26,6 +27,33 @@ class PururinSearchMetadata : RaisedSearchMetadata() { var ratingCount: Int? = null var averageRating: Double? = null + override fun createMangaInfo(manga: MangaInfo): MangaInfo { + val key = prId?.let { prId -> + prShortLink?.let { prShortLink -> + "/gallery/$prId/$prShortLink" + } + } + + val title = title ?: altTitle + + val cover = thumbnailUrl + + val artist = tags.ofNamespace(TAG_NAMESPACE_ARTIST).joinToString { it.name } + + val genres = tagsToGenreList() + + val description = "meta" + + return manga.copy( + key = key ?: manga.key, + title = title ?: manga.title, + cover = cover ?: manga.cover, + artist = artist, + genres = genres, + description = description + ) + } + override fun copyTo(manga: SManga) { prId?.let { prId -> prShortLink?.let { prShortLink -> diff --git a/app/src/main/java/exh/metadata/metadata/TsuminoSearchMetadata.kt b/app/src/main/java/exh/metadata/metadata/TsuminoSearchMetadata.kt index 7cbff0176..ffbf86721 100644 --- a/app/src/main/java/exh/metadata/metadata/TsuminoSearchMetadata.kt +++ b/app/src/main/java/exh/metadata/metadata/TsuminoSearchMetadata.kt @@ -7,6 +7,7 @@ import eu.kanade.tachiyomi.source.model.SManga import exh.metadata.MetadataUtil import exh.metadata.metadata.base.RaisedSearchMetadata import kotlinx.serialization.Serializable +import tachiyomi.source.model.MangaInfo import java.text.SimpleDateFormat import java.util.Date import java.util.Locale @@ -41,6 +42,29 @@ class TsuminoSearchMetadata : RaisedSearchMetadata() { var character: List = emptyList() + override fun createMangaInfo(manga: MangaInfo): MangaInfo { + val title = title + val cover = tmId?.let { BASE_URL.replace("www", "content") + thumbUrlFromId(it.toString()) } + + val artist = artist + + val status = SManga.UNKNOWN + + // Copy tags -> genres + val genres = tagsToGenreList() + + val description = "meta" + + return manga.copy( + title = title ?: manga.title, + cover = cover ?: manga.cover, + artist = artist ?: manga.artist, + status = status, + genres = genres, + description = description + ) + } + override fun copyTo(manga: SManga) { title?.let { manga.title = it } manga.thumbnail_url = BASE_URL.replace("www", "content") + thumbUrlFromId(tmId.toString()) diff --git a/app/src/main/java/exh/metadata/metadata/base/RaisedSearchMetadata.kt b/app/src/main/java/exh/metadata/metadata/base/RaisedSearchMetadata.kt index 57515abcb..7245d9104 100644 --- a/app/src/main/java/exh/metadata/metadata/base/RaisedSearchMetadata.kt +++ b/app/src/main/java/exh/metadata/metadata/base/RaisedSearchMetadata.kt @@ -25,6 +25,7 @@ import kotlinx.serialization.json.Json import kotlinx.serialization.modules.SerializersModule import kotlinx.serialization.modules.polymorphic import kotlinx.serialization.modules.subclass +import tachiyomi.source.model.MangaInfo import kotlin.properties.ReadWriteProperty import kotlin.reflect.KProperty @@ -57,8 +58,12 @@ abstract class RaisedSearchMetadata { abstract fun copyTo(manga: SManga) + abstract fun createMangaInfo(manga: MangaInfo): MangaInfo + fun tagsToGenreString() = tags.toGenreString() + fun tagsToGenreList() = tags.toGenreList() + fun tagsToDescription() = StringBuilder("Tags:\n").apply { // BiConsumer only available in Java 8, don't bother calling forEach directly on 'tags' @@ -142,6 +147,10 @@ abstract class RaisedSearchMetadata { (this).filter { it.type != TAG_TYPE_VIRTUAL } .joinToString { (if (it.namespace != null) "${it.namespace}: " else "") + it.name } + fun MutableList.toGenreList() = + (this).filter { it.type != TAG_TYPE_VIRTUAL } + .map { (if (it.namespace != null) "${it.namespace}: " else "") + it.name } + private val module = SerializersModule { polymorphic(RaisedSearchMetadata::class) { subclass(EHentaiSearchMetadata::class) diff --git a/app/src/main/java/exh/source/DelegatedHttpSource.kt b/app/src/main/java/exh/source/DelegatedHttpSource.kt index 3cefcffc1..2001d302a 100644 --- a/app/src/main/java/exh/source/DelegatedHttpSource.kt +++ b/app/src/main/java/exh/source/DelegatedHttpSource.kt @@ -10,6 +10,8 @@ import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.Response import rx.Observable +import tachiyomi.source.model.ChapterInfo +import tachiyomi.source.model.MangaInfo abstract class DelegatedHttpSource(val delegate: HttpSource) : HttpSource() { /** @@ -185,6 +187,14 @@ abstract class DelegatedHttpSource(val delegate: HttpSource) : HttpSource() { return delegate.fetchMangaDetails(manga) } + /** + * [1.x API] Get the updated details for a manga. + */ + override suspend fun getMangaDetails(manga: MangaInfo): MangaInfo { + ensureDelegateCompatible() + return delegate.getMangaDetails(manga) + } + /** * 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. @@ -207,6 +217,14 @@ abstract class DelegatedHttpSource(val delegate: HttpSource) : HttpSource() { return delegate.fetchChapterList(manga) } + /** + * [1.x API] Get all the available chapters for a manga. + */ + override suspend fun getChapterList(manga: MangaInfo): List { + ensureDelegateCompatible() + return delegate.getChapterList(manga) + } + /** * Returns an observable with the page list for a chapter. * @@ -217,6 +235,14 @@ abstract class DelegatedHttpSource(val delegate: HttpSource) : HttpSource() { return delegate.fetchPageList(chapter) } + /** + * [1.x API] Get the list of pages a chapter has. + */ + override suspend fun getPageList(chapter: ChapterInfo): List { + ensureDelegateCompatible() + return delegate.getPageList(chapter) + } + /** * 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. diff --git a/app/src/main/java/exh/source/EnhancedHttpSource.kt b/app/src/main/java/exh/source/EnhancedHttpSource.kt index 7b566c594..bc82190bf 100644 --- a/app/src/main/java/exh/source/EnhancedHttpSource.kt +++ b/app/src/main/java/exh/source/EnhancedHttpSource.kt @@ -9,6 +9,8 @@ import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.online.HttpSource import okhttp3.Response +import tachiyomi.source.model.ChapterInfo +import tachiyomi.source.model.MangaInfo import uy.kohesive.injekt.injectLazy class EnhancedHttpSource( @@ -177,6 +179,11 @@ class EnhancedHttpSource( */ override fun fetchMangaDetails(manga: SManga) = source().fetchMangaDetails(manga) + /** + * [1.x API] Get the updated details for a manga. + */ + override suspend fun getMangaDetails(manga: MangaInfo): MangaInfo = source().getMangaDetails(manga) + /** * 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. @@ -193,6 +200,11 @@ class EnhancedHttpSource( */ override fun fetchChapterList(manga: SManga) = source().fetchChapterList(manga) + /** + * [1.x API] Get all the available chapters for a manga. + */ + override suspend fun getChapterList(manga: MangaInfo): List = source().getChapterList(manga) + /** * Returns an observable with the page list for a chapter. * @@ -200,6 +212,11 @@ class EnhancedHttpSource( */ override fun fetchPageList(chapter: SChapter) = source().fetchPageList(chapter) + /** + * [1.x API] Get the list of pages a chapter has. + */ + override suspend fun getPageList(chapter: ChapterInfo): List = source().getPageList(chapter) + /** * 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.