ColorlibAnime (#937)

* ColorlibAnime

* remove adaptive icons

* lint

* lint

* Optimize icons with `oxipng -omax --strip all`

---------

Co-authored-by: stevenyomi <95685115+stevenyomi@users.noreply.github.com>
This commit is contained in:
Mike 2024-02-02 17:26:40 -05:00 committed by Draff
parent cc9a0d2b41
commit dd60a193e7
26 changed files with 193 additions and 115 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

View File

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

View File

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -0,0 +1,7 @@
package eu.kanade.tachiyomi.extension.id.neumanga
import eu.kanade.tachiyomi.multisrc.colorlibanime.ColorlibAnime
class Neumanga : ColorlibAnime("Neumanga", "https://neumanga.xyz", "id") {
override val versionId = 2
}

View File

@ -1,12 +0,0 @@
package eu.kanade.tachiyomi.extension.id.neumanga
import eu.kanade.tachiyomi.multisrc.zmanga.ZManga
import okhttp3.Headers
import java.text.SimpleDateFormat
import java.util.Locale
class Neumanga : ZManga("Neumanga", "https://neumanga.net", "id", SimpleDateFormat("MMMM dd, yyyy", Locale("id"))) {
override fun headersBuilder(): Headers.Builder = Headers.Builder()
.add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9")
}

View File

@ -1,101 +0,0 @@
package eu.kanade.tachiyomi.extension.id.sektekomik
import eu.kanade.tachiyomi.multisrc.zmanga.ZManga
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.interceptor.rateLimit
import eu.kanade.tachiyomi.source.model.Filter
import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.source.model.SManga
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.OkHttpClient
import okhttp3.Request
import org.jsoup.nodes.Element
import java.util.concurrent.TimeUnit
class SekteKomik : ZManga("Sekte Komik", "https://sektekomik.com", "id") {
// Formerly "Sekte Komik (WP Manga Stream)"
override val id = 7866629035053218469
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.rateLimit(3)
.build()
// popular
override fun popularMangaRequest(page: Int): Request {
return GET("$baseUrl")
}
override fun popularMangaSelector() = "div.flexbox-item"
override fun popularMangaFromElement(element: Element): SManga {
return SManga.create().apply {
setUrlWithoutDomain(element.select("a").attr("href"))
title = element.select("a").attr("title")
thumbnail_url = element.select("img").attr("abs:src")
}
}
override fun popularMangaNextPageSelector() = "Not used"
// latest
override fun latestUpdatesRequest(page: Int): Request {
return GET("$baseUrl/page/$page")
}
override fun latestUpdatesSelector() = "div.flexbox4-item"
override fun latestUpdatesFromElement(element: Element): SManga {
return SManga.create().apply {
setUrlWithoutDomain(element.select("div.flexbox4-content a").attr("href"))
title = element.select("div.flexbox4-side .title").first()!!.text()
thumbnail_url = element.select("img").attr("abs:src")
}
}
override fun latestUpdatesNextPageSelector() = "div.pagination .next"
// search
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
var url = "$baseUrl/${pagePathSegment(page)}".toHttpUrl().newBuilder()
url.addQueryParameter("s", query)
(if (filters.isEmpty()) getFilterList() else filters).forEach { filter ->
when (filter) {
// if site has project page, default value "hasProjectPage" = false
is ProjectFilter -> {
if (filter.toUriPart() == "project-filter-on") {
url = "$baseUrl$projectPageString/${pagePathSegment(page)}".toHttpUrl().newBuilder()
}
}
else -> {}
}
}
return GET(url.build(), headers)
}
override fun searchMangaSelector() = "div.flexbox2-item"
override fun searchMangaFromElement(element: Element): SManga {
return SManga.create().apply {
setUrlWithoutDomain(element.select("div.flexbox2-content a").attr("href"))
title = element.select("div.flexbox2-title > span").first()!!.text()
thumbnail_url = element.select("img").attr("abs:src")
}
}
override fun searchMangaNextPageSelector() = latestUpdatesNextPageSelector()
// filter
override val hasProjectPage = true
override fun getFilterList(): FilterList {
val filters = mutableListOf<Filter<*>>(
Filter.Separator(),
Filter.Header("NOTE: cant be used with search!"),
Filter.Header("$name Project List page"),
ProjectFilter(),
)
return FilterList(filters)
}
}

View File

@ -0,0 +1,160 @@
package eu.kanade.tachiyomi.multisrc.colorlibanime
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.interceptor.rateLimit
import eu.kanade.tachiyomi.source.model.Filter
import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
abstract class ColorlibAnime(
override val name: String,
override val baseUrl: String,
override val lang: String,
) : ParsedHttpSource() {
override val supportsLatest = true
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
.rateLimit(3)
.build()
private fun Element.toThumbnail(): String {
return this.select(".set-bg").attr("abs:data-setbg").substringBeforeLast("?")
}
// Search
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
val url = baseUrl.toHttpUrl().newBuilder().apply {
addPathSegment("manga")
addQueryParameter("page", page.toString())
addQueryParameter("sort", filters.findInstance<OrderFilter>()!!.toUriPart())
addQueryParameter("search", query)
}
return GET(url.build(), headers)
}
override fun searchMangaSelector(): String = ".product__page__content > [style]:has(.col-6) .product__item"
override fun searchMangaFromElement(element: Element): SManga {
return SManga.create().apply {
setUrlWithoutDomain(element.select("a.img-link").attr("abs:href"))
title = element.select("h5").text()
thumbnail_url = element.toThumbnail()
}
}
override fun searchMangaNextPageSelector(): String? = ".fa-angle-right"
// Popular
override fun popularMangaRequest(page: Int): Request {
return searchMangaRequest(page, "", FilterList(OrderFilter(0)))
}
override fun popularMangaSelector(): String = searchMangaSelector()
override fun popularMangaFromElement(element: Element): SManga = searchMangaFromElement(element)
override fun popularMangaNextPageSelector(): String? = searchMangaNextPageSelector()
// Latest
override fun latestUpdatesRequest(page: Int): Request {
return searchMangaRequest(page, "", FilterList(OrderFilter(1)))
}
override fun latestUpdatesSelector(): String = searchMangaSelector()
override fun latestUpdatesFromElement(element: Element): SManga = searchMangaFromElement(element)
override fun latestUpdatesNextPageSelector(): String? = searchMangaNextPageSelector()
// Details
override fun mangaDetailsParse(document: Document): SManga {
document.select(".anime__details__content").let { element ->
return SManga.create().apply {
title = element.select("h3").text()
author = element.select("h3 + span").text()
description = element.select("p").text()
thumbnail_url = element.first()?.toThumbnail()
status = when (element.select("li:contains(status)").text().substringAfter(" ")) {
"Ongoing" -> SManga.ONGOING
"Complete" -> SManga.COMPLETED
else -> SManga.UNKNOWN
}
}
}
}
// Chapters
private val timeRegex = Regex("""Date\((\d+)\)""")
override fun chapterListParse(response: Response): List<SChapter> {
val doc = response.asJsoup()
val time = timeRegex.find(doc.select("script:containsData(lastUpdated)").html())
?.let { it.groupValues[1].toLong() } ?: 0
return doc.select(chapterListSelector())
.map { chapterFromElement(it) }
.apply { this.first().date_upload = time }
}
override fun chapterListSelector(): String = ".anime__details__episodes a"
override fun chapterFromElement(element: Element): SChapter {
return SChapter.create().apply {
setUrlWithoutDomain(element.attr("abs:href"))
name = element.text()
date_upload = 0L
}
}
// Pages
override fun pageListParse(document: Document): List<Page> {
return document.select(".container .read-img > img").mapIndexed { i, element ->
Page(i, "", element.attr("abs:src"))
}
}
override fun imageUrlParse(document: Document): String = throw UnsupportedOperationException()
// Filters
override fun getFilterList() = FilterList(
OrderFilter(),
)
class OrderFilter(state: Int = 0) : UriPartFilter(
"Order By",
arrayOf(
Pair("Views", "view"),
Pair("Updated", "updated"),
),
state,
)
open class UriPartFilter(
displayName: String,
private val vals: Array<Pair<String, String>>,
state: Int = 0,
) :
Filter.Select<String>(displayName, vals.map { it.first }.toTypedArray(), state) {
fun toUriPart() = vals[state].second
}
private inline fun <reified T> Iterable<*>.findInstance() = find { it is T } as? T
}

View File

@ -0,0 +1,26 @@
package eu.kanade.tachiyomi.multisrc.colorlibanime
import generator.ThemeSourceData.SingleLang
import generator.ThemeSourceGenerator
class ColorlibAnimeGenerator : ThemeSourceGenerator {
override val themePkg = "colorlibanime"
override val themeClass = "ColorlibAnime"
override val baseVersionCode: Int = 1
override val sources = listOf(
SingleLang("Sekte Komik", "https://sektekomik.xyz", "id", overrideVersionCode = 26),
SingleLang("Komikzoid", "https://komikzoid.id", "id"),
SingleLang("Neumanga", "https://neumanga.xyz", "id", overrideVersionCode = 1),
)
companion object {
@JvmStatic
fun main(args: Array<String>) {
ColorlibAnimeGenerator().createAll()
}
}
}

View File

@ -17,9 +17,7 @@ class ZMangaGenerator : ThemeSourceGenerator {
SingleLang("KomikIndo.info", "http://komikindo.info", "id", isNsfw = true, className = "KomikIndoInfo"),
SingleLang("KomikPlay", "https://komikplay.com", "id", overrideVersionCode = 1),
SingleLang("Maid - Manga", "https://www.maid.my.id", "id", overrideVersionCode = 10, className = "MaidManga"),
SingleLang("Neumanga", "https://neumanga.net", "id"),
SingleLang("ShiroDoujin", "https://shirodoujin.com", "id", isNsfw = true, overrideVersionCode = 1, className = "Shirodoujin"),
SingleLang("Sekte Komik", "https://sektekomik.com", "id", overrideVersionCode = 25),
)
companion object {