diff --git a/src/zh/baozimhorg/build.gradle b/src/zh/baozimhorg/build.gradle index fb1f29700..3f5ff1644 100644 --- a/src/zh/baozimhorg/build.gradle +++ b/src/zh/baozimhorg/build.gradle @@ -1,7 +1,7 @@ ext { - extName = 'Baozimh.org' - extClass = '.BaozimhOrg' - extVersionCode = 28 + extName = 'GoDa' + extClass = '.GoDaManhua' + extVersionCode = 29 } apply from: "$rootDir/common.gradle" diff --git a/src/zh/baozimhorg/res/mipmap-hdpi/ic_launcher.png b/src/zh/baozimhorg/res/mipmap-hdpi/ic_launcher.png index 8f388ea3d..e1a07b4d9 100644 Binary files a/src/zh/baozimhorg/res/mipmap-hdpi/ic_launcher.png and b/src/zh/baozimhorg/res/mipmap-hdpi/ic_launcher.png differ diff --git a/src/zh/baozimhorg/res/mipmap-mdpi/ic_launcher.png b/src/zh/baozimhorg/res/mipmap-mdpi/ic_launcher.png index 7337b1a10..acd45e588 100644 Binary files a/src/zh/baozimhorg/res/mipmap-mdpi/ic_launcher.png and b/src/zh/baozimhorg/res/mipmap-mdpi/ic_launcher.png differ diff --git a/src/zh/baozimhorg/res/mipmap-xhdpi/ic_launcher.png b/src/zh/baozimhorg/res/mipmap-xhdpi/ic_launcher.png index a22e9134d..ab2d8aea7 100644 Binary files a/src/zh/baozimhorg/res/mipmap-xhdpi/ic_launcher.png and b/src/zh/baozimhorg/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/src/zh/baozimhorg/res/mipmap-xxhdpi/ic_launcher.png b/src/zh/baozimhorg/res/mipmap-xxhdpi/ic_launcher.png index c19292033..d1aa6c897 100644 Binary files a/src/zh/baozimhorg/res/mipmap-xxhdpi/ic_launcher.png and b/src/zh/baozimhorg/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/src/zh/baozimhorg/res/mipmap-xxxhdpi/ic_launcher.png b/src/zh/baozimhorg/res/mipmap-xxxhdpi/ic_launcher.png index 5a468abf2..c4071e711 100644 Binary files a/src/zh/baozimhorg/res/mipmap-xxxhdpi/ic_launcher.png and b/src/zh/baozimhorg/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/src/zh/baozimhorg/src/eu/kanade/tachiyomi/extension/zh/baozimhorg/BaozimhOrg.kt b/src/zh/baozimhorg/src/eu/kanade/tachiyomi/extension/zh/baozimhorg/BaozimhOrg.kt index 11d42ec26..9109b2f56 100644 --- a/src/zh/baozimhorg/src/eu/kanade/tachiyomi/extension/zh/baozimhorg/BaozimhOrg.kt +++ b/src/zh/baozimhorg/src/eu/kanade/tachiyomi/extension/zh/baozimhorg/BaozimhOrg.kt @@ -1,10 +1,6 @@ package eu.kanade.tachiyomi.extension.zh.baozimhorg -import android.app.Application -import androidx.preference.ListPreference -import androidx.preference.PreferenceScreen import eu.kanade.tachiyomi.network.GET -import eu.kanade.tachiyomi.source.ConfigurableSource import eu.kanade.tachiyomi.source.model.Filter import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.MangasPage @@ -13,140 +9,133 @@ import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.online.HttpSource import eu.kanade.tachiyomi.util.asJsoup -import okhttp3.HttpUrl import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.Request import okhttp3.Response import org.jsoup.nodes.Document -import org.jsoup.nodes.Element -import org.jsoup.select.Evaluator -import uy.kohesive.injekt.Injekt -import uy.kohesive.injekt.api.get -import java.text.SimpleDateFormat -import java.util.Locale +import org.jsoup.nodes.Entities +import rx.Observable -// Uses WPManga + GeneratePress/Blocksy Child -class BaozimhOrg : HttpSource(), ConfigurableSource { +open class BaozimhOrg( + override val name: String, + override val baseUrl: String, + override val lang: String, +) : HttpSource() { - override val name get() = "包子漫画导航" - override val lang get() = "zh" override val supportsLatest get() = true - override val baseUrl: String - private val baseHttpUrl: HttpUrl - private val enableGenres: Boolean + private val enableGenres = true - init { - val mirrors = MIRRORS - val mirrorIndex = Injekt.get().getSharedPreferences("source_$id", 0x0000) - .getString(MIRROR_PREF, "0")!!.toInt().coerceAtMost(mirrors.size - 1) - baseUrl = "https://" + mirrors[mirrorIndex] - baseHttpUrl = baseUrl.toHttpUrl() - enableGenres = mirrorIndex == 0 - } + override fun headersBuilder() = super.headersBuilder().add("Referer", "$baseUrl/") - override val client = network.client.newBuilder() - .addInterceptor(UrlInterceptor) - .build() + override val client = network.cloudflareClient private fun getKey(link: String): String { - val pathSegments = baseHttpUrl.resolve(link)!!.pathSegments - val fromIndex = if (pathSegments[0] == "manga") 1 else 0 - val toIndex = if (pathSegments.last().isEmpty()) pathSegments.size - 1 else pathSegments.size - val list = pathSegments.subList(fromIndex, toIndex).toMutableList() - list[0] = list[0].split("-").take(2).joinToString("-") - return list.joinToString("/") + return link.substringAfter("/manga/").removeSuffix("/") } - override fun popularMangaRequest(page: Int) = GET("$baseUrl/hots/page/$page/", headers) + override fun popularMangaRequest(page: Int) = GET("$baseUrl/hots/page/$page", headers) override fun popularMangaParse(response: Response): MangasPage { val document = response.asJsoup().also(::parseGenres) - val mangas = document.select("article.wp-manga").map { element -> + val mangas = document.select(".cardlist .pb-2 a").map { element -> SManga.create().apply { - val link = element.selectFirst(Evaluator.Tag("h2"))!!.child(0) - url = getKey(link.attr("href")) - title = link.ownText() - thumbnail_url = element.selectFirst(Evaluator.Tag("img"))!!.imgSrc + val imgSrc = element.selectFirst("img")!!.attr("src") + url = getKey(element.attr("href")) + title = element.selectFirst("h3")!!.ownText() + thumbnail_url = if ("url=" in imgSrc) imgSrc.toHttpUrl().queryParameter("url")!! else imgSrc } } - val hasNextPage = document.selectFirst(Evaluator.Class("next"))?.tagName() == "a" || - document.selectFirst(".gb-button[aria-label=Next page]") != null + val nextPage = if (lang == "zh") "下一頁" else "NEXT" + val hasNextPage = document.selectFirst("a[aria-label=$nextPage] button") != null return MangasPage(mangas, hasNextPage) } - override fun latestUpdatesRequest(page: Int) = GET("$baseUrl/newss/page/$page/", headers) + override fun latestUpdatesRequest(page: Int) = GET("$baseUrl/newss/page/$page", headers) override fun latestUpdatesParse(response: Response) = popularMangaParse(response) override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { if (query.isNotEmpty()) { - val url = "$baseUrl/page/$page/".toHttpUrl().newBuilder() - .addQueryParameter("s", query) - return Request.Builder().url(url.build()).headers(headers).build() + val url = "$baseUrl/s".toHttpUrl().newBuilder() + .addPathSegment(query) + .addEncodedQueryParameter("page", "$page") + .build() + return GET(url, headers) } for (filter in filters) { - if (filter is UriPartFilter) return GET(baseUrl + filter.toUriPart() + "page/$page/", headers) + if (filter is UriPartFilter) return GET(baseUrl + filter.toUriPart() + "/page/$page", headers) } return popularMangaRequest(page) } override fun searchMangaParse(response: Response) = popularMangaParse(response) + override fun getMangaUrl(manga: SManga) = "$baseUrl/manga/${manga.url}" + override fun mangaDetailsRequest(manga: SManga): Request { - val url = manga.url - if (url[0] == '/') throw Exception(MIGRATE) - return GET("$baseUrl/manga/$url/", headers) + return GET(getMangaUrl(manga), headers) } + private fun Document.getMangaId() = selectFirst("#mangachapters")!!.attr("data-mid") + override fun mangaDetailsParse(response: Response) = SManga.create().apply { val document = response.asJsoup() - title = document.selectFirst(Evaluator.Tag("h1"))!!.ownText() - author = document.selectFirst(Evaluator.Class("author-content"))!!.children().joinToString { it.ownText() } - description = document.selectFirst(".descrip_manga_info, .wp-block-stackable-text")!!.text() - thumbnail_url = document.selectFirst("img.wp-post-image")!!.imgSrc + val titleElement = document.selectFirst("h1")!! + val elements = titleElement.parent()!!.parent()!!.children() + check(elements.size == 6) - val genreList = document.selectFirst(Evaluator.Class("genres-content"))!! - .children().eachText().toMutableSet() - if ("连载中" in genreList) { - genreList.remove("连载中") - status = SManga.ONGOING - } else if ("已完结" in genreList) { - genreList.remove("已完结") - status = SManga.COMPLETED - } - genre = genreList.joinToString() + title = titleElement.ownText() + status = SManga.UNKNOWN // Everything is marked as ongoing + author = Entities.unescape(elements[1].children().drop(1).joinToString { it.text().removeSuffix(" ,") }) + genre = buildList { + elements[2].children().drop(1).mapTo(this) { it.text().removeSuffix(" ,") } + elements[3].children().mapTo(this) { it.text().removePrefix("#") } + }.joinToString() + description = elements[4].text() + "\n\nID: ${document.getMangaId()}" + thumbnail_url = document.selectFirst("img.object-cover")!!.attr("src") } - override fun chapterListRequest(manga: SManga): Request { - val url = manga.url - if (url[0] == '/') throw Exception(MIGRATE) - return GET("$baseUrl/chapterlist/$url/", headers) + override fun fetchChapterList(manga: SManga): Observable> = Observable.fromCallable { + val mangaId = manga.description + ?.substringAfterLast("\nID: ", "") + ?.takeIf { it.isNotEmpty() && it.all(Character::isDigit) } + ?: client.newCall(mangaDetailsRequest(manga)).execute().asJsoup().getMangaId() + + fetchChapterList(mangaId) } override fun chapterListParse(response: Response): List { - val document = response.asJsoup() - return document.selectFirst(Evaluator.Class("version-chaps"))!!.children().map { + throw UnsupportedOperationException() + } + + open fun fetchChapterList(mangaId: String): List { + val response = client.newCall(GET("$baseUrl/manga/get?mid=$mangaId&mode=all", headers)).execute() + + return response.asJsoup().select(".chapteritem").asReversed().map { element -> + val anchor = element.selectFirst("a")!! SChapter.create().apply { - url = getKey(it.attr("href")) - name = it.ownText() - date_upload = parseChapterDate(it.child(0).text()) + url = getKey(anchor.attr("href")) + "#$mangaId/" + anchor.attr("data-cs") + name = anchor.attr("data-ct") } } } + override fun getChapterUrl(chapter: SChapter) = "$baseUrl/manga/" + chapter.url.substringBeforeLast('#') + override fun pageListRequest(chapter: SChapter): Request { - val url = chapter.url - if (url[0] == '/') throw Exception(MIGRATE) - return GET("$baseUrl/manga/$url/", headers) + val id = chapter.url.substringAfterLast('#', "") + val mangaId = id.substringBefore('/') + val chapterId = id.substringAfter('/') + return pageListRequest(mangaId, chapterId) } + open fun pageListRequest(mangaId: String, chapterId: String) = GET("$baseUrl/chapter/getcontent?m=$mangaId&c=$chapterId", headers) + override fun pageListParse(response: Response): List { val document = response.asJsoup() - // Jsoup won't ignore duplicates inside