diff --git a/multisrc/overrides/madara/baozimhorg/res/mipmap-hdpi/ic_launcher.png b/multisrc/overrides/madara/baozimhorg/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 000000000..8f388ea3d Binary files /dev/null and b/multisrc/overrides/madara/baozimhorg/res/mipmap-hdpi/ic_launcher.png differ diff --git a/multisrc/overrides/madara/baozimhorg/res/mipmap-mdpi/ic_launcher.png b/multisrc/overrides/madara/baozimhorg/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 000000000..7337b1a10 Binary files /dev/null and b/multisrc/overrides/madara/baozimhorg/res/mipmap-mdpi/ic_launcher.png differ diff --git a/multisrc/overrides/madara/baozimhorg/res/mipmap-xhdpi/ic_launcher.png b/multisrc/overrides/madara/baozimhorg/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 000000000..a22e9134d Binary files /dev/null and b/multisrc/overrides/madara/baozimhorg/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/multisrc/overrides/madara/baozimhorg/res/mipmap-xxhdpi/ic_launcher.png b/multisrc/overrides/madara/baozimhorg/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..c19292033 Binary files /dev/null and b/multisrc/overrides/madara/baozimhorg/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/multisrc/overrides/madara/baozimhorg/res/mipmap-xxxhdpi/ic_launcher.png b/multisrc/overrides/madara/baozimhorg/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 000000000..5a468abf2 Binary files /dev/null and b/multisrc/overrides/madara/baozimhorg/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/multisrc/overrides/madara/baozimhorg/res/web_hi_res_512.png b/multisrc/overrides/madara/baozimhorg/res/web_hi_res_512.png new file mode 100644 index 000000000..8e1a2719c Binary files /dev/null and b/multisrc/overrides/madara/baozimhorg/res/web_hi_res_512.png differ diff --git a/multisrc/overrides/madara/baozimhorg/src/BaozimhOrg.kt b/multisrc/overrides/madara/baozimhorg/src/BaozimhOrg.kt new file mode 100644 index 000000000..13d116b82 --- /dev/null +++ b/multisrc/overrides/madara/baozimhorg/src/BaozimhOrg.kt @@ -0,0 +1,149 @@ +package eu.kanade.tachiyomi.extension.zh.baozimhorg + +import android.app.Application +import androidx.preference.ListPreference +import androidx.preference.PreferenceScreen +import eu.kanade.tachiyomi.multisrc.madara.Madara +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 +import eu.kanade.tachiyomi.source.model.SChapter +import eu.kanade.tachiyomi.source.model.SManga +import eu.kanade.tachiyomi.util.asJsoup +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 + +// Uses Elementor + Madara theme. +class BaozimhOrg : ConfigurableSource, Madara( + "包子漫画导航", + "", + "zh", + SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH) +) { + + override val baseUrl: String + + 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] + } + + override val client = network.client + + override val useLoadMoreSearch = false + + override fun popularMangaRequest(page: Int) = GET("$baseUrl/hots/$page/", headers) + override fun latestUpdatesRequest(page: Int) = GET("$baseUrl/dayup/$page/", headers) + 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() + } + for (filter in filters) { + if (filter is UriPartFilter) return GET(baseUrl + filter.toUriPart() + "page/$page/", headers) + } + return popularMangaRequest(page) + } + + override val popularMangaUrlSelector = "h3 > a" + + override fun latestUpdatesParse(response: Response) = popularMangaParse(response) + override fun searchMangaParse(response: Response) = popularMangaParse(response) + override fun popularMangaParse(response: Response): MangasPage { + val document = response.asJsoup().also(::parseGenresInternal) + val mangas = document.select(Evaluator.Tag("article")).map(::popularMangaFromElement) + val hasNextPage = document.selectFirst(Evaluator.Class("next"))?.tagName() == "a" + return MangasPage(mangas, hasNextPage) + } + + override val mangaDetailsSelectorStatus = "none" + override val mangaDetailsSelectorDescription = "div.summary_content > div.post-content_item:last-child" + override val seriesTypeSelector = "none" + override val altNameSelector = "none" + + override fun mangaDetailsParse(document: Document): SManga { + val manga = super.mangaDetailsParse(document) + val genre = manga.genre ?: return manga + val genreList = genre.split(", ") as ArrayList + for ((index, tag) in genreList.withIndex()) { + val status = when (tag) { + "连载中" -> SManga.ONGOING + "已完结" -> SManga.COMPLETED + else -> SManga.UNKNOWN + } + if (status != SManga.UNKNOWN) { + manga.status = status + genreList.removeAt(index) + manga.genre = genreList.joinToString() + return manga + } + } + return manga + } + + override fun chapterFromElement(element: Element) = SChapter.create().apply { + val link = element.selectFirst(Evaluator.Tag("a")) + url = link.attr("href").removePrefix(baseUrl) + name = link.ownText() + date_upload = parseChapterDate(link.child(0).text()) + } + + override fun parseRelativeDate(date: String) = + super.parseRelativeDate(date.replace("小时", "hour")) + + var genres: Array> = emptyArray() + + private fun parseGenresInternal(document: Document) { + if (genres.isNotEmpty()) return + val box = document.selectFirst("[data-elementor-type=header] + div nav > ul") ?: return + val items = box.select(Evaluator.Class("menu-item-type-custom")) + genres = buildList(items.size + 1) { + add(Pair("全部", "/allmanga/")) + items.mapTo(this) { + val link = it.child(0) + Pair(link.ownText(), link.attr("href")) + } + }.toTypedArray() + } + + override fun getFilterList(): FilterList = + if (genres.isEmpty()) { + FilterList(listOf(Filter.Header("点击“重置”刷新分类"))) + } else { + val list = listOf( + Filter.Header("分类(搜索文本时无效)"), + UriPartFilter("分类", genres), + ) + FilterList(list) + } + + override fun setupPreferenceScreen(screen: PreferenceScreen) { + ListPreference(screen.context).apply { + val mirrors = MIRRORS + key = MIRROR_PREF + title = "镜像网址" + summary = "%s\n重启生效" + entries = mirrors + entryValues = Array(mirrors.size) { it.toString() } + setDefaultValue("0") + }.let(screen::addPreference) + } + + companion object { + private const val MIRROR_PREF = "MIRROR" + private val MIRRORS get() = arrayOf("baozimh.org", "cn.godamanga.com") + } +} diff --git a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/madara/MadaraGenerator.kt b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/madara/MadaraGenerator.kt index c084ac439..b66c0161e 100644 --- a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/madara/MadaraGenerator.kt +++ b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/madara/MadaraGenerator.kt @@ -56,6 +56,7 @@ class MadaraGenerator : ThemeSourceGenerator { SingleLang("Azora", "https://azoraworld.com", "ar", overrideVersionCode = 3), SingleLang("Bakaman", "https://bakaman.net", "th", overrideVersionCode = 1), SingleLang("Banana Cítrica", "https://dinastiacilly.com", "pt-BR", isNsfw = true, pkgName = "bananamecanica", className = "BananaCitrica", overrideVersionCode = 4), + SingleLang("Baozimh.org", "https://baozimh.org", "zh", className = "BaozimhOrg", sourceName = "包子漫画导航"), SingleLang("BestManga", "https://bestmanga.club", "ru", overrideVersionCode = 1), SingleLang("BestManhua", "https://bestmanhua.com", "en", overrideVersionCode = 2), SingleLang("Bichen Traduções", "https://bichentraducoes.com", "pt-BR", isNsfw = true, className = "BichenTraducoes"),