Update to extensions-lib 1.4 (#15298)

* Update to extensions-lib 1.4.

* Fix a syntax error in NM.

* Add UpdateStrategy to Nana as well.
This commit is contained in:
Alessandro Jean 2023-02-11 10:44:48 -03:00 committed by GitHub
parent 7ee6d834d8
commit 5093e6a5fa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 86 additions and 151 deletions

View File

@ -236,10 +236,10 @@ apply from: "$rootDir/common.gradle"
| `pkgNameSuffix` | A unique suffix added to `eu.kanade.tachiyomi.extension`. The language and the site name should be enough. Remember your extension code implementation must be placed in this package. | | `pkgNameSuffix` | A unique suffix added to `eu.kanade.tachiyomi.extension`. The language and the site name should be enough. Remember your extension code implementation must be placed in this package. |
| `extClass` | Points to the class that implements `Source`. You can use a relative path starting with a dot (the package name is the base path). This is used to find and instantiate the source(s). | | `extClass` | Points to the class that implements `Source`. You can use a relative path starting with a dot (the package name is the base path). This is used to find and instantiate the source(s). |
| `extVersionCode` | The extension version code. This must be a positive integer and incremented with any change to the code. | | `extVersionCode` | The extension version code. This must be a positive integer and incremented with any change to the code. |
| `libVersion` | (Optional, defaults to `1.3`) The version of the [extensions library](https://github.com/tachiyomiorg/extensions-lib) used. | | `libVersion` | (Optional, defaults to `1.4`) The version of the [extensions library](https://github.com/tachiyomiorg/extensions-lib) used. |
| `isNsfw` | (Optional, defaults to `false`) Flag to indicate that a source contains NSFW content. | | `isNsfw` | (Optional, defaults to `false`) Flag to indicate that a source contains NSFW content. |
The extension's version name is generated automatically by concatenating `libVersion` and `extVersionCode`. With the example used above, the version would be `1.3.1`. The extension's version name is generated automatically by concatenating `libVersion` and `extVersionCode`. With the example used above, the version would be `1.4.1`.
### Core dependencies ### Core dependencies

View File

@ -22,7 +22,7 @@ android {
targetSdkVersion AndroidConfig.targetSdk targetSdkVersion AndroidConfig.targetSdk
applicationIdSuffix pkgNameSuffix applicationIdSuffix pkgNameSuffix
versionCode extVersionCode versionCode extVersionCode
versionName project.ext.properties.getOrDefault("libVersion", "1.3") + ".$extVersionCode" versionName project.ext.properties.getOrDefault("libVersion", "1.4") + ".$extVersionCode"
setProperty("archivesBaseName", "tachiyomi-$pkgNameSuffix-v$versionName") setProperty("archivesBaseName", "tachiyomi-$pkgNameSuffix-v$versionName")
def readmes = project.projectDir.listFiles({ File file -> def readmes = project.projectDir.listFiles({ File file ->
file.name == "README.md" || file.name == "CHANGELOG.md" file.name == "README.md" || file.name == "CHANGELOG.md"

View File

@ -9,7 +9,7 @@ gradle-kotlin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.
gradle-serialization = { module = "org.jetbrains.kotlin:kotlin-serialization", version.ref = "kotlin_version" } gradle-serialization = { module = "org.jetbrains.kotlin:kotlin-serialization", version.ref = "kotlin_version" }
gradle-kotlinter = { module = "org.jmailen.gradle:kotlinter-gradle", version = "3.6.0" } gradle-kotlinter = { module = "org.jmailen.gradle:kotlinter-gradle", version = "3.6.0" }
tachiyomi-lib = { module = "com.github.tachiyomiorg:extensions-lib", version = "1.3.2" } tachiyomi-lib = { module = "com.github.tachiyomiorg:extensions-lib", version = "1.4.0" }
kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib-jdk8", version.ref = "kotlin_version" } kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib-jdk8", version.ref = "kotlin_version" }
kotlin-protobuf = { module = "org.jetbrains.kotlinx:kotlinx-serialization-protobuf", version.ref = "serialization_version" } kotlin-protobuf = { module = "org.jetbrains.kotlinx:kotlinx-serialization-protobuf", version.ref = "serialization_version" }

View File

@ -5,7 +5,6 @@ import android.content.SharedPreferences
import androidx.preference.ListPreference import androidx.preference.ListPreference
import androidx.preference.PreferenceScreen import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.network.POST import eu.kanade.tachiyomi.network.POST
import eu.kanade.tachiyomi.network.asObservableSuccess
import eu.kanade.tachiyomi.network.interceptor.rateLimitHost import eu.kanade.tachiyomi.network.interceptor.rateLimitHost
import eu.kanade.tachiyomi.source.ConfigurableSource import eu.kanade.tachiyomi.source.ConfigurableSource
import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.FilterList
@ -29,7 +28,6 @@ import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.Response import okhttp3.Response
import org.jsoup.Jsoup import org.jsoup.Jsoup
import rx.Observable
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
@ -98,7 +96,8 @@ abstract class Bilibili(
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
ID_SEARCH_PATTERN.matchEntire(query)?.let { ID_SEARCH_PATTERN.matchEntire(query)?.let {
val (id) = it.destructured val (id) = it.destructured
return mangaDetailsApiRequest("/detail/mc$id") val temporaryManga = SManga.create().apply { url = "/detail/mc$id" }
return mangaDetailsRequest(temporaryManga)
} }
val price = filters.firstInstanceOrNull<PriceFilter>()?.state ?: 0 val price = filters.firstInstanceOrNull<PriceFilter>()?.state ?: 0
@ -177,23 +176,16 @@ abstract class Bilibili(
url = "/detail/mc$comicId" url = "/detail/mc$comicId"
} }
// Workaround to allow "Open in browser" use the real URL. override fun getMangaUrl(manga: SManga): String = baseUrl + manga.url
override fun fetchMangaDetails(manga: SManga): Observable<SManga> {
return client.newCall(mangaDetailsApiRequest(manga.url))
.asObservableSuccess()
.map { response ->
mangaDetailsParse(response).apply { initialized = true }
}
}
private fun mangaDetailsApiRequest(mangaUrl: String): Request { override fun mangaDetailsRequest(manga: SManga): Request {
val comicId = mangaUrl.substringAfterLast("/mc").toInt() val comicId = manga.url.substringAfterLast("/mc").toInt()
val jsonPayload = buildJsonObject { put("comic_id", comicId) } val jsonPayload = buildJsonObject { put("comic_id", comicId) }
val requestBody = jsonPayload.toString().toRequestBody(JSON_MEDIA_TYPE) val requestBody = jsonPayload.toString().toRequestBody(JSON_MEDIA_TYPE)
val newHeaders = headersBuilder() val newHeaders = headersBuilder()
.set("Referer", baseUrl + mangaUrl) .set("Referer", baseUrl + manga.url)
.build() .build()
val apiUrl = "$baseUrl/$API_COMIC_V1_COMIC_ENDPOINT/ComicDetail".toHttpUrl() val apiUrl = "$baseUrl/$API_COMIC_V1_COMIC_ENDPOINT/ComicDetail".toHttpUrl()
@ -233,7 +225,7 @@ abstract class Bilibili(
} }
// Chapters are available in the same url of the manga details. // Chapters are available in the same url of the manga details.
override fun chapterListRequest(manga: SManga): Request = mangaDetailsApiRequest(manga.url) override fun chapterListRequest(manga: SManga): Request = mangaDetailsRequest(manga)
override fun chapterListParse(response: Response): List<SChapter> { override fun chapterListParse(response: Response): List<SChapter> {
val result = response.parseAs<BilibiliComicDto>() val result = response.parseAs<BilibiliComicDto>()
@ -253,6 +245,8 @@ abstract class Bilibili(
url = "/mc$comicId/${episode.id}" url = "/mc$comicId/${episode.id}"
} }
override fun getChapterUrl(chapter: SChapter): String = baseUrl + chapter.url
override fun pageListRequest(chapter: SChapter): Request = imageIndexRequest(chapter.url, "") override fun pageListRequest(chapter: SChapter): Request = imageIndexRequest(chapter.url, "")
override fun pageListParse(response: Response): List<Page> = imageIndexParse(response) override fun pageListParse(response: Response): List<Page> = imageIndexParse(response)

View File

@ -2,7 +2,6 @@ package eu.kanade.tachiyomi.multisrc.heancms
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.POST import eu.kanade.tachiyomi.network.POST
import eu.kanade.tachiyomi.network.asObservableSuccess
import eu.kanade.tachiyomi.source.model.Filter import eu.kanade.tachiyomi.source.model.Filter
import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.source.model.MangasPage import eu.kanade.tachiyomi.source.model.MangasPage
@ -184,26 +183,17 @@ abstract class HeanCms(
return MangasPage(mangaList, hasNextPage = false) return MangasPage(mangaList, hasNextPage = false)
} }
// Workaround to allow "Open in browser" use the real URL. override fun getMangaUrl(manga: SManga): String {
override fun fetchMangaDetails(manga: SManga): Observable<SManga> {
return client.newCall(seriesDetailsRequest(manga))
.asObservableSuccess()
.map { response ->
mangaDetailsParse(response).apply { initialized = true }
}
}
override fun mangaDetailsRequest(manga: SManga): Request {
val seriesSlug = manga.url val seriesSlug = manga.url
.substringAfterLast("/") .substringAfterLast("/")
.replace(TIMESTAMP_REGEX, "") .replace(TIMESTAMP_REGEX, "")
val currentSlug = seriesSlugMap?.get(seriesSlug)?.slug ?: seriesSlug val currentSlug = seriesSlugMap?.get(seriesSlug)?.slug ?: seriesSlug
return GET("$baseUrl/series/$currentSlug", headers) return "$baseUrl/series/$currentSlug"
} }
private fun seriesDetailsRequest(manga: SManga): Request { override fun mangaDetailsRequest(manga: SManga): Request {
val seriesSlug = manga.url val seriesSlug = manga.url
.substringAfterLast("/") .substringAfterLast("/")
.replace(TIMESTAMP_REGEX, "") .replace(TIMESTAMP_REGEX, "")
@ -231,7 +221,7 @@ abstract class HeanCms(
} }
} }
override fun chapterListRequest(manga: SManga): Request = seriesDetailsRequest(manga) override fun chapterListRequest(manga: SManga): Request = mangaDetailsRequest(manga)
override fun chapterListParse(response: Response): List<SChapter> { override fun chapterListParse(response: Response): List<SChapter> {
val result = response.parseAs<HeanCmsSeriesDto>() val result = response.parseAs<HeanCmsSeriesDto>()
@ -244,6 +234,8 @@ abstract class HeanCms(
.reversed() .reversed()
} }
override fun getChapterUrl(chapter: SChapter): String = baseUrl + chapter.url
override fun pageListRequest(chapter: SChapter): Request { override fun pageListRequest(chapter: SChapter): Request {
val chapterId = chapter.url.substringAfterLast("#") val chapterId = chapter.url.substringAfterLast("#")

View File

@ -20,6 +20,7 @@ import eu.kanade.tachiyomi.source.model.MangasPage
import eu.kanade.tachiyomi.source.model.Page import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.model.UpdateStrategy
import eu.kanade.tachiyomi.source.online.HttpSource import eu.kanade.tachiyomi.source.online.HttpSource
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.CacheControl import okhttp3.CacheControl
@ -302,6 +303,7 @@ abstract class EHentai(
// Copy metadata to manga // Copy metadata to manga
SManga.create().apply { SManga.create().apply {
copyTo(this) copyTo(this)
update_strategy = UpdateStrategy.ONLY_FETCH_ONCE
} }
} }
} }

View File

@ -367,22 +367,12 @@ abstract class MangaDex(final override val lang: String, private val dexLang: St
// Manga Details section // Manga Details section
// Workaround to allow "Open in WebView" to show a webpage instead of JSON. override fun getMangaUrl(manga: SManga): String {
// TODO: Replace with getMangaUrl when the repository is using extensions-lib 1.4
override fun fetchMangaDetails(manga: SManga): Observable<SManga> {
return client.newCall(apiMangaDetailsRequest(manga))
.asObservableSuccess()
.map { response ->
mangaDetailsParse(response).apply { initialized = true }
}
}
override fun mangaDetailsRequest(manga: SManga): Request {
// TODO: Remove once redirect for /manga is fixed. // TODO: Remove once redirect for /manga is fixed.
val title = manga.title val title = manga.title
val url = "${baseUrl}${manga.url.replace("manga", "title")}" val url = "${baseUrl}${manga.url.replace("manga", "title")}"
val shareUrl = "$url/" + helper.titleToSlug(title)
return GET(shareUrl, headers) return "$url/" + helper.titleToSlug(title)
} }
/** /**
@ -390,7 +380,7 @@ abstract class MangaDex(final override val lang: String, private val dexLang: St
* *
* @throws Exception if the url is the old format so people migrate * @throws Exception if the url is the old format so people migrate
*/ */
private fun apiMangaDetailsRequest(manga: SManga): Request { override fun mangaDetailsRequest(manga: SManga): Request {
if (!helper.containsUuid(manga.url.trim())) { if (!helper.containsUuid(manga.url.trim())) {
throw Exception(helper.intl.migrateWarning) throw Exception(helper.intl.migrateWarning)
} }
@ -547,6 +537,8 @@ abstract class MangaDex(final override val lang: String, private val dexLang: St
.map(helper::createChapter) .map(helper::createChapter)
} }
override fun getChapterUrl(chapter: SChapter): String = baseUrl + chapter.url
override fun pageListRequest(chapter: SChapter): Request { override fun pageListRequest(chapter: SChapter): Request {
if (!helper.containsUuid(chapter.url)) { if (!helper.containsUuid(chapter.url)) {
throw Exception(helper.intl.migrateWarning) throw Exception(helper.intl.migrateWarning)

View File

@ -269,9 +269,9 @@ class MangaDexHelper(lang: String) {
val titleMap = mangaDataDto.attributes!!.title val titleMap = mangaDataDto.attributes!!.title
val dirtyTitle = val dirtyTitle =
titleMap.values.firstOrNull() // use literally anything from title as first resort titleMap.values.firstOrNull() // use literally anything from title as first resort
?: mangaDataDto.attributes.altTitles ?: mangaDataDto.attributes.altTitles
.find { (it[lang] ?: it["en"]) !== null } .find { (it[lang] ?: it["en"]) !== null }
?.values?.singleOrNull() // find something else from alt titles ?.values?.singleOrNull() // find something else from alt titles
title = (dirtyTitle ?: "").removeEntitiesAndMarkdown() title = (dirtyTitle ?: "").removeEntitiesAndMarkdown()
coverFileName?.let { coverFileName?.let {

View File

@ -6,7 +6,6 @@ import androidx.preference.ListPreference
import androidx.preference.PreferenceScreen import androidx.preference.PreferenceScreen
import androidx.preference.SwitchPreferenceCompat import androidx.preference.SwitchPreferenceCompat
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.asObservableSuccess
import eu.kanade.tachiyomi.network.interceptor.rateLimitHost import eu.kanade.tachiyomi.network.interceptor.rateLimitHost
import eu.kanade.tachiyomi.source.ConfigurableSource import eu.kanade.tachiyomi.source.ConfigurableSource
import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.FilterList
@ -132,9 +131,9 @@ class MangaPlus(
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
if (query.matches(ID_SEARCH_PATTERN)) { if (query.matches(ID_SEARCH_PATTERN)) {
return titleDetailsRequest(query.removePrefix(PREFIX_ID_SEARCH)) return mangaDetailsRequest(query.removePrefix(PREFIX_ID_SEARCH))
} else if (query.matches(CHAPTER_ID_SEARCH_PATTERN)) { } else if (query.matches(CHAPTER_ID_SEARCH_PATTERN)) {
return mangaViewerRequest(query.removePrefix(PREFIX_CHAPTER_ID_SEARCH)) return pageListRequest(query.removePrefix(PREFIX_CHAPTER_ID_SEARCH))
} }
val newHeaders = headersBuilder() val newHeaders = headersBuilder()
@ -170,7 +169,7 @@ class MangaPlus(
val cachedTitle = titleCache?.get(titleId) val cachedTitle = titleCache?.get(titleId)
val title = cachedTitle?.toSManga() ?: run { val title = cachedTitle?.toSManga() ?: run {
val titleRequest = titleDetailsRequest(titleId.toString()) val titleRequest = mangaDetailsRequest(titleId.toString())
val titleResult = client.newCall(titleRequest).execute().asMangaPlusResponse() val titleResult = client.newCall(titleRequest).execute().asMangaPlusResponse()
checkNotNull(titleResult.success) { checkNotNull(titleResult.success) {
@ -201,7 +200,12 @@ class MangaPlus(
return MangasPage(searchResults.map(Title::toSManga), hasNextPage = false) return MangasPage(searchResults.map(Title::toSManga), hasNextPage = false)
} }
private fun titleDetailsRequest(mangaUrl: String): Request { // Remove the '#' and map to the new url format used in website.
override fun getMangaUrl(manga: SManga): String = baseUrl + manga.url.substring(1)
override fun mangaDetailsRequest(manga: SManga): Request = mangaDetailsRequest(manga.url)
private fun mangaDetailsRequest(mangaUrl: String): Request {
val titleId = mangaUrl.substringAfterLast("/") val titleId = mangaUrl.substringAfterLast("/")
val newHeaders = headersBuilder() val newHeaders = headersBuilder()
@ -211,20 +215,6 @@ class MangaPlus(
return GET("$API_URL/title_detail?title_id=$titleId&format=json", newHeaders) return GET("$API_URL/title_detail?title_id=$titleId&format=json", newHeaders)
} }
// Workaround to allow "Open in browser" use the real URL.
override fun fetchMangaDetails(manga: SManga): Observable<SManga> {
return client.newCall(titleDetailsRequest(manga.url))
.asObservableSuccess()
.map { response ->
mangaDetailsParse(response).apply { initialized = true }
}
}
override fun mangaDetailsRequest(manga: SManga): Request {
// Remove the '#' and map to the new url format used in website.
return GET(baseUrl + manga.url.substring(1), headers)
}
override fun mangaDetailsParse(response: Response): SManga { override fun mangaDetailsParse(response: Response): SManga {
val result = response.asMangaPlusResponse() val result = response.asMangaPlusResponse()
@ -245,7 +235,7 @@ class MangaPlus(
return titleDetails.toSManga() return titleDetails.toSManga()
} }
override fun chapterListRequest(manga: SManga): Request = titleDetailsRequest(manga.url) override fun chapterListRequest(manga: SManga): Request = mangaDetailsRequest(manga.url)
override fun chapterListParse(response: Response): List<SChapter> { override fun chapterListParse(response: Response): List<SChapter> {
val result = response.asMangaPlusResponse() val result = response.asMangaPlusResponse()
@ -269,13 +259,16 @@ class MangaPlus(
.map(Chapter::toSChapter) .map(Chapter::toSChapter)
} }
// Remove the '#' and map to the new url format used in website.
override fun getChapterUrl(chapter: SChapter): String = baseUrl + chapter.url.substring(1)
override fun pageListRequest(chapter: SChapter): Request { override fun pageListRequest(chapter: SChapter): Request {
val chapterId = chapter.url.substringAfterLast("/") val chapterId = chapter.url.substringAfterLast("/")
return mangaViewerRequest(chapterId) return pageListRequest(chapterId)
} }
private fun mangaViewerRequest(chapterId: String): Request { private fun pageListRequest(chapterId: String): Request {
val newHeaders = headersBuilder() val newHeaders = headersBuilder()
.set("Referer", "$baseUrl/viewer/$chapterId") .set("Referer", "$baseUrl/viewer/$chapterId")
.build() .build()

View File

@ -1,7 +1,6 @@
package eu.kanade.tachiyomi.extension.all.mangaup package eu.kanade.tachiyomi.extension.all.mangaup
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.asObservableSuccess
import eu.kanade.tachiyomi.network.interceptor.rateLimitHost import eu.kanade.tachiyomi.network.interceptor.rateLimitHost
import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.source.model.MangasPage import eu.kanade.tachiyomi.source.model.MangasPage
@ -63,7 +62,7 @@ class MangaUp(override val lang: String) : HttpSource() {
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
if (query.startsWith(PREFIX_ID_SEARCH) && query.matches(ID_SEARCH_PATTERN)) { if (query.startsWith(PREFIX_ID_SEARCH) && query.matches(ID_SEARCH_PATTERN)) {
return titleDetailsRequest(query.removePrefix(PREFIX_ID_SEARCH)) return mangaDetailsRequest(query.removePrefix(PREFIX_ID_SEARCH))
} }
val apiUrl = "$API_URL/manga/search".toHttpUrl().newBuilder() val apiUrl = "$API_URL/manga/search".toHttpUrl().newBuilder()
@ -98,7 +97,11 @@ class MangaUp(override val lang: String) : HttpSource() {
return MangasPage(titles.map(MangaUpTitle::toSManga), hasNextPage = false) return MangasPage(titles.map(MangaUpTitle::toSManga), hasNextPage = false)
} }
private fun titleDetailsRequest(mangaUrl: String): Request { override fun getMangaUrl(manga: SManga): String = baseUrl + manga.url
override fun mangaDetailsRequest(manga: SManga): Request = mangaDetailsRequest(manga.url)
private fun mangaDetailsRequest(mangaUrl: String): Request {
val titleId = mangaUrl.substringAfterLast("/") val titleId = mangaUrl.substringAfterLast("/")
val apiUrl = "$API_URL/manga/detail".toHttpUrl().newBuilder() val apiUrl = "$API_URL/manga/detail".toHttpUrl().newBuilder()
@ -110,20 +113,11 @@ class MangaUp(override val lang: String) : HttpSource() {
return GET(apiUrl, headers) return GET(apiUrl, headers)
} }
// Workaround to allow "Open in browser" use the real URL.
override fun fetchMangaDetails(manga: SManga): Observable<SManga> {
return client.newCall(titleDetailsRequest(manga.url))
.asObservableSuccess()
.map { response ->
mangaDetailsParse(response).apply { initialized = true }
}
}
override fun mangaDetailsParse(response: Response): SManga { override fun mangaDetailsParse(response: Response): SManga {
return response.parseAs<MangaUpTitle>().toSManga() return response.parseAs<MangaUpTitle>().toSManga()
} }
override fun chapterListRequest(manga: SManga): Request = titleDetailsRequest(manga.url) override fun chapterListRequest(manga: SManga): Request = mangaDetailsRequest(manga.url)
override fun chapterListParse(response: Response): List<SChapter> { override fun chapterListParse(response: Response): List<SChapter> {
val titleId = response.request.url.queryParameter("title_id")!!.toInt() val titleId = response.request.url.queryParameter("title_id")!!.toInt()
@ -132,6 +126,8 @@ class MangaUp(override val lang: String) : HttpSource() {
.map { it.toSChapter(titleId) } .map { it.toSChapter(titleId) }
} }
override fun getChapterUrl(chapter: SChapter): String = baseUrl + chapter.url
override fun pageListRequest(chapter: SChapter): Request { override fun pageListRequest(chapter: SChapter): Request {
val chapterId = chapter.url.substringAfterLast("/") val chapterId = chapter.url.substringAfterLast("/")

View File

@ -18,6 +18,7 @@ import eu.kanade.tachiyomi.source.model.MangasPage
import eu.kanade.tachiyomi.source.model.Page import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.model.UpdateStrategy
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.Headers import okhttp3.Headers
@ -222,6 +223,7 @@ open class NHentai(
.plus("Favorited by: ${document.select("div#info i.fa-heart + span span").text().removeSurrounding("(", ")")}\n") .plus("Favorited by: ${document.select("div#info i.fa-heart + span span").text().removeSurrounding("(", ")")}\n")
.plus(getTagDescription(document)) .plus(getTagDescription(document))
genre = getTags(document) genre = getTags(document)
update_strategy = UpdateStrategy.ONLY_FETCH_ONCE
} }
} }

View File

@ -9,6 +9,7 @@ import eu.kanade.tachiyomi.source.model.MangasPage
import eu.kanade.tachiyomi.source.model.Page import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.model.UpdateStrategy
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import okhttp3.Call import okhttp3.Call
import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.HttpUrl.Companion.toHttpUrl
@ -86,6 +87,7 @@ class Nana : ParsedHttpSource() {
.joinToString { it.text() } .joinToString { it.text() }
status = SManga.COMPLETED status = SManga.COMPLETED
update_strategy = UpdateStrategy.ONLY_FETCH_ONCE
initialized = true initialized = true
} }

View File

@ -7,7 +7,6 @@ import androidx.preference.EditTextPreference
import androidx.preference.PreferenceScreen import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.POST import eu.kanade.tachiyomi.network.POST
import eu.kanade.tachiyomi.network.asObservableSuccess
import eu.kanade.tachiyomi.network.interceptor.rateLimit import eu.kanade.tachiyomi.network.interceptor.rateLimit
import eu.kanade.tachiyomi.source.ConfigurableSource import eu.kanade.tachiyomi.source.ConfigurableSource
import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.FilterList
@ -127,16 +126,9 @@ class ArgosScan : HttpSource(), ConfigurableSource {
override fun searchMangaParse(response: Response): MangasPage = popularMangaParse(response) override fun searchMangaParse(response: Response): MangasPage = popularMangaParse(response)
// Workaround to allow "Open in browser" use the real URL. override fun getMangaUrl(manga: SManga): String = baseUrl + manga.url
override fun fetchMangaDetails(manga: SManga): Observable<SManga> {
return client.newCall(mangaDetailsApiRequest(manga))
.asObservableSuccess()
.map { response ->
mangaDetailsParse(response).apply { initialized = true }
}
}
private fun mangaDetailsApiRequest(manga: SManga): Request { override fun mangaDetailsRequest(manga: SManga): Request {
val mangaId = manga.url.substringAfter("obras/").toInt() val mangaId = manga.url.substringAfter("obras/").toInt()
val payload = buildMangaDetailsQueryPayload(mangaId) val payload = buildMangaDetailsQueryPayload(mangaId)
@ -172,7 +164,7 @@ class ArgosScan : HttpSource(), ConfigurableSource {
genre = project.tags.orEmpty().sortedBy(ArgosTagDto::name).joinToString { it.name } genre = project.tags.orEmpty().sortedBy(ArgosTagDto::name).joinToString { it.name }
} }
override fun chapterListRequest(manga: SManga): Request = mangaDetailsApiRequest(manga) override fun chapterListRequest(manga: SManga): Request = mangaDetailsRequest(manga)
override fun chapterListParse(response: Response): List<SChapter> { override fun chapterListParse(response: Response): List<SChapter> {
val result = response.parseAs<ArgosResponseDto<ArgosProjectDto>>() val result = response.parseAs<ArgosResponseDto<ArgosProjectDto>>()
@ -192,6 +184,8 @@ class ArgosScan : HttpSource(), ConfigurableSource {
url = "/leitor/${chapter.id}" url = "/leitor/${chapter.id}"
} }
override fun getChapterUrl(chapter: SChapter): String = baseUrl + chapter.url
override fun pageListRequest(chapter: SChapter): Request { override fun pageListRequest(chapter: SChapter): Request {
if (chapter.url.removePrefix("/leitor/").toIntOrNull() != null) { if (chapter.url.removePrefix("/leitor/").toIntOrNull() != null) {
throw Exception(REFRESH_WARNING) throw Exception(REFRESH_WARNING)

View File

@ -2,7 +2,6 @@ package eu.kanade.tachiyomi.extension.pt.hqnow
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.POST import eu.kanade.tachiyomi.network.POST
import eu.kanade.tachiyomi.network.asObservableSuccess
import eu.kanade.tachiyomi.network.interceptor.rateLimit import eu.kanade.tachiyomi.network.interceptor.rateLimit
import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.source.model.MangasPage import eu.kanade.tachiyomi.source.model.MangasPage
@ -164,16 +163,9 @@ class HQNow : HttpSource() {
return MangasPage(comicList, hasNextPage = false) return MangasPage(comicList, hasNextPage = false)
} }
// Workaround to allow "Open in browser" use the real URL. override fun getMangaUrl(manga: SManga): String = baseUrl + manga.url
override fun fetchMangaDetails(manga: SManga): Observable<SManga> {
return client.newCall(mangaDetailsApiRequest(manga))
.asObservableSuccess()
.map { response ->
mangaDetailsParse(response).apply { initialized = true }
}
}
private fun mangaDetailsApiRequest(manga: SManga): Request { override fun mangaDetailsRequest(manga: SManga): Request {
val comicBookId = manga.url.substringAfter("/hq/").substringBefore("/") val comicBookId = manga.url.substringAfter("/hq/").substringBefore("/")
val query = buildQuery { val query = buildQuery {
@ -219,7 +211,7 @@ class HQNow : HttpSource() {
status = comicBook.status.orEmpty().toStatus() status = comicBook.status.orEmpty().toStatus()
} }
override fun chapterListRequest(manga: SManga): Request = mangaDetailsApiRequest(manga) override fun chapterListRequest(manga: SManga): Request = mangaDetailsRequest(manga)
override fun chapterListParse(response: Response): List<SChapter> { override fun chapterListParse(response: Response): List<SChapter> {
val result = json.parseToJsonElement(response.body!!.string()).jsonObject val result = json.parseToJsonElement(response.body!!.string()).jsonObject
@ -239,7 +231,7 @@ class HQNow : HttpSource() {
"/chapter/${chapter.id}/page/1" "/chapter/${chapter.id}/page/1"
} }
// Pages override fun getChapterUrl(chapter: SChapter): String = baseUrl + chapter.url
override fun pageListRequest(chapter: SChapter): Request { override fun pageListRequest(chapter: SChapter): Request {
val chapterId = chapter.url.substringAfter("/chapter/").substringBefore("/") val chapterId = chapter.url.substringAfter("/chapter/").substringBefore("/")

View File

@ -1,7 +1,6 @@
package eu.kanade.tachiyomi.extension.pt.mangavibe package eu.kanade.tachiyomi.extension.pt.mangavibe
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.asObservableSuccess
import eu.kanade.tachiyomi.network.interceptor.rateLimit import eu.kanade.tachiyomi.network.interceptor.rateLimit
import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.source.model.MangasPage import eu.kanade.tachiyomi.source.model.MangasPage
@ -160,16 +159,9 @@ class MangaVibe : HttpSource() {
private fun searchMangaFromObject(comic: MangaVibeComicDto): SManga = popularMangaFromObject(comic) private fun searchMangaFromObject(comic: MangaVibeComicDto): SManga = popularMangaFromObject(comic)
// Workaround to allow "Open in browser" use the real URL. override fun getMangaUrl(manga: SManga): String = baseUrl + manga.url
override fun fetchMangaDetails(manga: SManga): Observable<SManga> {
return client.newCall(mangaDetailsApiRequest(manga))
.asObservableSuccess()
.map { response ->
mangaDetailsParse(response).apply { initialized = true }
}
}
private fun mangaDetailsApiRequest(manga: SManga): Request { override fun mangaDetailsRequest(manga: SManga): Request {
val comicId = manga.url.substringAfter("/manga/") val comicId = manga.url.substringAfter("/manga/")
.substringBefore("/") .substringBefore("/")

View File

@ -1,7 +1,6 @@
package eu.kanade.tachiyomi.extension.pt.nixmangas package eu.kanade.tachiyomi.extension.pt.nixmangas
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.asObservableSuccess
import eu.kanade.tachiyomi.network.interceptor.rateLimitHost import eu.kanade.tachiyomi.network.interceptor.rateLimitHost
import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.source.model.MangasPage import eu.kanade.tachiyomi.source.model.MangasPage
@ -84,19 +83,12 @@ class NixMangas : HttpSource() {
return MangasPage(workList, result.mangas.hasNextPage) return MangasPage(workList, result.mangas.hasNextPage)
} }
// Workaround to allow "Open in browser" use the real URL. override fun getMangaUrl(manga: SManga): String = baseUrl + manga.url
override fun fetchMangaDetails(manga: SManga): Observable<SManga> {
return client.newCall(mangaDetailsApiRequest(manga.url))
.asObservableSuccess()
.map { response ->
mangaDetailsParse(response).apply { initialized = true }
}
}
private fun mangaDetailsApiRequest(mangaUrl: String): Request { override fun mangaDetailsRequest(manga: SManga): Request {
// Their API doesn't have an endpoint for the manga details, so we // Their API doesn't have an endpoint for the manga details, so we
// use their site wrapped API instead for now. // use their site wrapped API instead for now.
val apiUrl = (baseUrl + mangaUrl).toHttpUrl().newBuilder() val apiUrl = (baseUrl + manga.url).toHttpUrl().newBuilder()
.addQueryParameter("_data", "routes/__app/obras/\$slug") .addQueryParameter("_data", "routes/__app/obras/\$slug")
.toString() .toString()
@ -109,7 +101,7 @@ class NixMangas : HttpSource() {
return result.manga.toSManga() return result.manga.toSManga()
} }
override fun chapterListRequest(manga: SManga): Request = mangaDetailsApiRequest(manga.url) override fun chapterListRequest(manga: SManga): Request = mangaDetailsRequest(manga)
override fun chapterListParse(response: Response): List<SChapter> { override fun chapterListParse(response: Response): List<SChapter> {
val result = response.parseAs<NixMangasDetailsDto>() val result = response.parseAs<NixMangasDetailsDto>()
@ -122,6 +114,8 @@ class NixMangas : HttpSource() {
.sortedByDescending(SChapter::chapter_number) .sortedByDescending(SChapter::chapter_number)
} }
override fun getChapterUrl(chapter: SChapter): String = baseUrl + chapter.url
override fun pageListRequest(chapter: SChapter): Request { override fun pageListRequest(chapter: SChapter): Request {
val apiUrl = (baseUrl + chapter.url).toHttpUrl().newBuilder() val apiUrl = (baseUrl + chapter.url).toHttpUrl().newBuilder()
.addQueryParameter("_data", "routes/__leitor/ler.\$manga.\$chapter") .addQueryParameter("_data", "routes/__leitor/ler.\$manga.\$chapter")

View File

@ -1,7 +1,6 @@
package eu.kanade.tachiyomi.extension.pt.saikaiscan package eu.kanade.tachiyomi.extension.pt.saikaiscan
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.asObservableSuccess
import eu.kanade.tachiyomi.network.interceptor.rateLimitHost import eu.kanade.tachiyomi.network.interceptor.rateLimitHost
import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.source.model.MangasPage import eu.kanade.tachiyomi.source.model.MangasPage
@ -105,16 +104,9 @@ class SaikaiScan : HttpSource() {
override fun searchMangaParse(response: Response): MangasPage = popularMangaParse(response) override fun searchMangaParse(response: Response): MangasPage = popularMangaParse(response)
// Workaround to allow "Open in browser" use the real URL. override fun getMangaUrl(manga: SManga): String = baseUrl + manga.url
override fun fetchMangaDetails(manga: SManga): Observable<SManga> {
return client.newCall(storyDetailsRequest(manga))
.asObservableSuccess()
.map { response ->
mangaDetailsParse(response).apply { initialized = true }
}
}
private fun storyDetailsRequest(manga: SManga): Request { override fun mangaDetailsRequest(manga: SManga): Request {
val storySlug = manga.url.substringAfterLast("/") val storySlug = manga.url.substringAfterLast("/")
val apiHeaders = headersBuilder() val apiHeaders = headersBuilder()
@ -164,6 +156,8 @@ class SaikaiScan : HttpSource() {
.sortedByDescending(SChapter::chapter_number) .sortedByDescending(SChapter::chapter_number)
} }
override fun getChapterUrl(chapter: SChapter): String = baseUrl + chapter.url
override fun pageListRequest(chapter: SChapter): Request { override fun pageListRequest(chapter: SChapter): Request {
val releaseId = chapter.url val releaseId = chapter.url
.substringBeforeLast("/") .substringBeforeLast("/")

View File

@ -2,7 +2,6 @@ package eu.kanade.tachiyomi.extension.pt.taosect
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.POST import eu.kanade.tachiyomi.network.POST
import eu.kanade.tachiyomi.network.asObservableSuccess
import eu.kanade.tachiyomi.network.interceptor.rateLimit import eu.kanade.tachiyomi.network.interceptor.rateLimit
import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.source.model.MangasPage import eu.kanade.tachiyomi.source.model.MangasPage
@ -140,7 +139,7 @@ class TaoSect : HttpSource() {
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
if (query.startsWith(SLUG_PREFIX_SEARCH) && query.removePrefix(SLUG_PREFIX_SEARCH).isNotBlank()) { if (query.startsWith(SLUG_PREFIX_SEARCH) && query.removePrefix(SLUG_PREFIX_SEARCH).isNotBlank()) {
return mangaDetailsApiRequest(query.removePrefix(SLUG_PREFIX_SEARCH)) return mangaDetailsRequest(query.removePrefix(SLUG_PREFIX_SEARCH))
} }
val apiUrl = "$baseUrl/$API_BASE_PATH/projetos".toHttpUrl().newBuilder() val apiUrl = "$baseUrl/$API_BASE_PATH/projetos".toHttpUrl().newBuilder()
@ -160,16 +159,11 @@ class TaoSect : HttpSource() {
override fun searchMangaParse(response: Response): MangasPage = popularMangaParse(response) override fun searchMangaParse(response: Response): MangasPage = popularMangaParse(response)
// Workaround to allow "Open in browser" use the real URL. override fun getMangaUrl(manga: SManga): String = baseUrl + manga.url
override fun fetchMangaDetails(manga: SManga): Observable<SManga> {
return client.newCall(mangaDetailsApiRequest(manga.url))
.asObservableSuccess()
.map { response ->
mangaDetailsParse(response).apply { initialized = true }
}
}
private fun mangaDetailsApiRequest(mangaUrl: String): Request { override fun mangaDetailsRequest(manga: SManga): Request = mangaDetailsRequest(manga.url)
private fun mangaDetailsRequest(mangaUrl: String): Request {
val projectSlug = mangaUrl val projectSlug = mangaUrl
.substringAfterLast("projeto/") .substringAfterLast("projeto/")
.substringBefore("/") .substringBefore("/")
@ -244,6 +238,8 @@ class TaoSect : HttpSource() {
url = "/leitor-online/projeto/$projectSlug/${obj.slug}/" url = "/leitor-online/projeto/$projectSlug/${obj.slug}/"
} }
override fun getChapterUrl(chapter: SChapter): String = baseUrl + chapter.url
override fun pageListRequest(chapter: SChapter): Request { override fun pageListRequest(chapter: SChapter): Request {
val projectSlug = chapter.url val projectSlug = chapter.url
.substringAfter("projeto/") .substringAfter("projeto/")