parent
f35e1e5ab3
commit
0ed49bce8b
|
@ -1,12 +0,0 @@
|
|||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
|
||||
ext {
|
||||
extName = 'Zahard'
|
||||
pkgNameSuffix = 'es.zahard'
|
||||
extClass = '.Zahard'
|
||||
extVersionCode = 4
|
||||
libVersion = '1.2'
|
||||
}
|
||||
|
||||
apply from: "$rootDir/common.gradle"
|
Binary file not shown.
Before Width: | Height: | Size: 3.1 KiB |
Binary file not shown.
Before Width: | Height: | Size: 1.7 KiB |
Binary file not shown.
Before Width: | Height: | Size: 4.2 KiB |
Binary file not shown.
Before Width: | Height: | Size: 8.7 KiB |
Binary file not shown.
Before Width: | Height: | Size: 12 KiB |
Binary file not shown.
Before Width: | Height: | Size: 61 KiB |
|
@ -1,292 +0,0 @@
|
|||
package eu.kanade.tachiyomi.extension.es.zahard
|
||||
|
||||
import android.net.Uri
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
||||
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.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.Request
|
||||
import okhttp3.Response
|
||||
import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
import rx.Observable
|
||||
|
||||
class Zahard : ParsedHttpSource() {
|
||||
|
||||
override val name = "Zahard"
|
||||
override val baseUrl = "https://zahard.top"
|
||||
override val lang = "es"
|
||||
override val supportsLatest = true
|
||||
|
||||
// common
|
||||
|
||||
private fun mangaFromElement(element: Element): SManga =
|
||||
SManga.create().apply {
|
||||
url = element.select("a").first().attr("href")
|
||||
title = element.select("h6").text().trim()
|
||||
thumbnail_url = element.select("img").attr("src")
|
||||
}
|
||||
|
||||
// poplular manga
|
||||
|
||||
override fun popularMangaRequest(page: Int) = GET("$baseUrl/biblioteca?page=$page", headers)
|
||||
|
||||
override fun popularMangaSelector() = "div.col-6.col-md-3.p-1"
|
||||
|
||||
override fun popularMangaNextPageSelector() = "a[rel=next]"
|
||||
|
||||
override fun popularMangaFromElement(element: Element) = mangaFromElement(element)
|
||||
|
||||
// latest manga
|
||||
// refer to: https://github.com/inorichi/tachiyomi-extensions/issues/4847
|
||||
|
||||
override fun fetchLatestUpdates(page: Int): Observable<MangasPage> {
|
||||
return client.newCall(latestUpdatesRequest(page))
|
||||
.asObservableSuccess()
|
||||
.map { response ->
|
||||
latestUpdatesParse(response, page)
|
||||
}
|
||||
}
|
||||
|
||||
val mangasLoaded = mutableListOf<SManga>()
|
||||
|
||||
override fun latestUpdatesParse(response: Response): MangasPage = throw Exception("Not Used")
|
||||
|
||||
fun latestUpdatesParse(response: Response, page: Int): MangasPage {
|
||||
val document = response.asJsoup()
|
||||
|
||||
val potentialMangas = document.select(latestUpdatesSelector()).map { element ->
|
||||
latestUpdatesFromElement(element)
|
||||
}.distinctBy { it.title }
|
||||
|
||||
// remve duplicates globaly
|
||||
if (page == 1)
|
||||
mangasLoaded.clear()
|
||||
var mangas = mutableListOf<SManga>()
|
||||
potentialMangas.forEach { manga ->
|
||||
var isDuplicate = false
|
||||
for (i in 0 until mangasLoaded.size) {
|
||||
if (manga.title == mangasLoaded.get(i).title) {
|
||||
isDuplicate = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (!isDuplicate) {
|
||||
mangasLoaded.add(manga)
|
||||
mangas.add(manga)
|
||||
}
|
||||
}
|
||||
|
||||
// extract manga urls from chapters
|
||||
mangas = mangas.map { manga ->
|
||||
manga.apply {
|
||||
url = client.newCall(GET(url, headers)).execute().asJsoup().select("body > div.container.mb-3.mibg.rounded.px-4.py-2 > div:nth-child(2) > div > a")[0].attr("href")
|
||||
}
|
||||
}.toMutableList()
|
||||
|
||||
// if is empty must pass something or we will get cut off
|
||||
// ref: tachiyomi/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/Pager.kt:27
|
||||
if (mangas.isEmpty()) {
|
||||
mangas.add(potentialMangas.get(0))
|
||||
}
|
||||
|
||||
val hasNextPage = latestUpdatesNextPageSelector().let { selector ->
|
||||
document.select(selector).first()
|
||||
} != null
|
||||
|
||||
return MangasPage(mangas, hasNextPage)
|
||||
}
|
||||
|
||||
override fun latestUpdatesRequest(page: Int) = GET("$baseUrl/fastpass?page=$page", headers)
|
||||
|
||||
override fun latestUpdatesSelector() = "div.col-6.col-md-3.p-1"
|
||||
|
||||
override fun latestUpdatesNextPageSelector() = "a[rel=next]"
|
||||
|
||||
override fun latestUpdatesFromElement(element: Element): SManga {
|
||||
val manga = SManga.create().apply {
|
||||
url = element.select("a").first().attr("href")
|
||||
title = element.select("h6").text().trim().substringBefore(" episodio")
|
||||
thumbnail_url = element.select("img").attr("src")
|
||||
}
|
||||
|
||||
return manga
|
||||
}
|
||||
|
||||
// search manga
|
||||
|
||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
||||
if (query.isNotBlank()) {
|
||||
throw Exception("Source does not support search")
|
||||
} else {
|
||||
val uri = Uri.parse("$baseUrl/").buildUpon()
|
||||
// Append uri filters
|
||||
filters.forEach {
|
||||
if (it is UriFilter)
|
||||
it.addToUri(uri)
|
||||
}
|
||||
uri.appendQueryParameter("page", "$page")
|
||||
return GET(uri.toString(), headers)
|
||||
}
|
||||
}
|
||||
|
||||
override fun searchMangaSelector() = popularMangaSelector()
|
||||
|
||||
override fun searchMangaNextPageSelector() = popularMangaNextPageSelector()
|
||||
|
||||
override fun searchMangaFromElement(element: Element) = mangaFromElement(element)
|
||||
|
||||
// chapter list
|
||||
|
||||
override fun chapterListRequest(manga: SManga) = mangaDetailsRequest(manga)
|
||||
|
||||
override fun chapterListSelector() = "a.list-group-item"
|
||||
|
||||
override fun chapterFromElement(element: Element): SChapter =
|
||||
SChapter.create().apply {
|
||||
url = element.attr("href")
|
||||
name = element.ownText().trim() + " [" + element.select("span").text().trim() + "]"
|
||||
|
||||
// general pattern: "Chapter <number in float> - <manga name>"
|
||||
chapter_number = element.ownText().split(" ")[1].toFloat()
|
||||
}
|
||||
|
||||
// manga details
|
||||
|
||||
override fun mangaDetailsRequest(manga: SManga) = GET(manga.url, headers)
|
||||
|
||||
override fun mangaDetailsParse(document: Document): SManga {
|
||||
val manga = SManga.create()
|
||||
manga.title = document.select("h2").text().trim()
|
||||
manga.description = document.select("p[style=margin: 5px]").text().trim()
|
||||
manga.thumbnail_url = document.select("div.text-center img").first().attr("src")
|
||||
val glist = document.select("div.container.mb-3.mibg.rounded.px-4.py-2 a[href*=genero]").map { it.text().trim() }
|
||||
manga.genre = glist.joinToString(", ")
|
||||
return manga
|
||||
}
|
||||
|
||||
// page list
|
||||
|
||||
override fun pageListRequest(chapter: SChapter) = GET(chapter.url, headers)
|
||||
|
||||
override fun pageListParse(document: Document): List<Page> {
|
||||
val pages = mutableListOf<Page>()
|
||||
|
||||
document.select("img.img-fluid")?.forEach {
|
||||
pages.add(Page(pages.size, "", it.attr("src")))
|
||||
}
|
||||
|
||||
return pages
|
||||
}
|
||||
|
||||
// image url
|
||||
|
||||
override fun imageUrlParse(document: Document) = throw Exception("Not Used")
|
||||
|
||||
// filters
|
||||
|
||||
/**
|
||||
* Represents a filter that is able to modify a URI.
|
||||
*/
|
||||
private interface UriFilter {
|
||||
fun addToUri(uri: Uri.Builder)
|
||||
}
|
||||
|
||||
private open class UriSelectFilter(
|
||||
displayName: String,
|
||||
val uriParam: String,
|
||||
val vals: Array<Pair<String, String>>,
|
||||
val firstIsUnspecified: Boolean = true,
|
||||
defaultValue: Int = 0
|
||||
) :
|
||||
Filter.Select<String>(displayName, vals.map { it.second }.toTypedArray(), defaultValue), UriFilter {
|
||||
override fun addToUri(uri: Uri.Builder) {
|
||||
if (state != 0 || !firstIsUnspecified)
|
||||
uri.appendPath(uriParam)
|
||||
.appendPath(vals[state].first)
|
||||
}
|
||||
}
|
||||
|
||||
private class TypeFilter : UriSelectFilter(
|
||||
"Type",
|
||||
"biblioteca",
|
||||
arrayOf(
|
||||
Pair("all", "All"),
|
||||
Pair("manga", "Manga"),
|
||||
Pair("manhwa", "Manhwa"),
|
||||
Pair("manhua", "Manhua")
|
||||
)
|
||||
)
|
||||
|
||||
private class GenreFilter : UriSelectFilter(
|
||||
"Genre",
|
||||
"genero",
|
||||
arrayOf(
|
||||
Pair("all", "ALL"),
|
||||
Pair("accion", "Acción"),
|
||||
Pair("aventura", "Aventura"),
|
||||
Pair("comedia", "Comedia"),
|
||||
Pair("drama", "Drama"),
|
||||
Pair("recuentos-de-la-vida", "Recuentos de la vida"),
|
||||
Pair("ecchi", "Ecchi"),
|
||||
Pair("fantasia", "Fantasia"),
|
||||
Pair("magia", "Magia"),
|
||||
Pair("sobrenatural", "Sobrenatural"),
|
||||
Pair("horror", "Horror"),
|
||||
Pair("misterio", "Misterio"),
|
||||
Pair("psicologico", "Psicológico"),
|
||||
Pair("romance", "Romance"),
|
||||
Pair("ciencia-ficcion", "Ciencia Ficción"),
|
||||
Pair("thriller", "Thriller"),
|
||||
Pair("deporte", "Deporte"),
|
||||
Pair("girls-love", "Girls Love"),
|
||||
Pair("boys-love", "Boys Love"),
|
||||
Pair("harem", "Harem"),
|
||||
Pair("mecha", "Mecha"),
|
||||
Pair("supervivencia", "Supervivencia"),
|
||||
Pair("reencarnacion", "Reencarnación"),
|
||||
Pair("gore", "Gore"),
|
||||
Pair("apocaliptico", "Apocalíptico"),
|
||||
Pair("tragedia", "Tragedia"),
|
||||
Pair("vida-escolar", "Vida Escolar"),
|
||||
Pair("historia", "Historia"),
|
||||
Pair("militar", "Militar"),
|
||||
Pair("policiaco", "Policiaco"),
|
||||
Pair("crimen", "Crimen"),
|
||||
Pair("superpoderes", "Superpoderes"),
|
||||
Pair("vampiros", "Vampiros"),
|
||||
Pair("artes-marciales", "Artes Marciales"),
|
||||
Pair("samurai", "Samurái"),
|
||||
Pair("genero-bender", "Género Bender"),
|
||||
Pair("realidad-virtual", "Realidad Virtual"),
|
||||
Pair("ciberpunk", "Ciberpunk"),
|
||||
Pair("musica", "Musica"),
|
||||
Pair("parodia", "Parodia"),
|
||||
Pair("animacion", "Animación"),
|
||||
Pair("demonios", "Demonios"),
|
||||
Pair("familia", "Familia"),
|
||||
Pair("extranjero", "Extranjero"),
|
||||
Pair("ni%C3%B1os", "Niños"),
|
||||
Pair("realidad", "Realidad"),
|
||||
Pair("telenovela", "Telenovela"),
|
||||
Pair("guerra", "Guerra"),
|
||||
Pair("oeste", "Oeste"),
|
||||
Pair("hentai", "hentai"),
|
||||
Pair("Comics", "Comics")
|
||||
)
|
||||
)
|
||||
|
||||
override fun getFilterList() = FilterList(
|
||||
Filter.Header("NOTE: Filters are ignored if using text search."),
|
||||
Filter.Header("Only one filter can be used at a time."),
|
||||
TypeFilter(),
|
||||
GenreFilter()
|
||||
)
|
||||
}
|
Loading…
Reference in New Issue