Add HeavenManga[ES] extension (#1375)
* initial commit for heavenmanga * updated of icons * TODO: Only viewing of chapters and see filter * Can now view pages * Complete work. Finito! * removed un-needed dependencies in build.gradle * fixed all parts suggested in the PR review
This commit is contained in:
parent
9fae259e03
commit
2abd854084
|
@ -0,0 +1,12 @@
|
||||||
|
apply plugin: 'com.android.application'
|
||||||
|
apply plugin: 'kotlin-android'
|
||||||
|
|
||||||
|
ext {
|
||||||
|
appName = 'Tachiyomi: HeavenManga'
|
||||||
|
pkgNameSuffix = 'es.heavenmanga'
|
||||||
|
extClass = '.HeavenManga'
|
||||||
|
extVersionCode = 1
|
||||||
|
libVersion = '1.2'
|
||||||
|
}
|
||||||
|
|
||||||
|
apply from: "$rootDir/common.gradle"
|
Binary file not shown.
After Width: | Height: | Size: 6.0 KiB |
Binary file not shown.
After Width: | Height: | Size: 3.2 KiB |
Binary file not shown.
After Width: | Height: | Size: 8.5 KiB |
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
Binary file not shown.
After Width: | Height: | Size: 27 KiB |
|
@ -0,0 +1,335 @@
|
||||||
|
package eu.kanade.tachiyomi.extension.es.heavenmanga
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
|
import eu.kanade.tachiyomi.network.GET
|
||||||
|
import eu.kanade.tachiyomi.source.model.*
|
||||||
|
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
|
||||||
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
|
import okhttp3.*
|
||||||
|
import okhttp3.Response
|
||||||
|
import org.jsoup.nodes.Document
|
||||||
|
import org.jsoup.select.Elements
|
||||||
|
import org.jsoup.nodes.Element
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class HeavenManga : ParsedHttpSource() {
|
||||||
|
|
||||||
|
override val name = "HeavenManga"
|
||||||
|
|
||||||
|
override val baseUrl = "http://heavenmanga.com"
|
||||||
|
|
||||||
|
override val lang = "es"
|
||||||
|
|
||||||
|
override val supportsLatest = true
|
||||||
|
|
||||||
|
override val client: OkHttpClient = network.cloudflareClient
|
||||||
|
|
||||||
|
override fun headersBuilder(): Headers.Builder {
|
||||||
|
return Headers.Builder()
|
||||||
|
.add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) Gecko/20100101 Firefox/60")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override fun popularMangaSelector() = ".top.clearfix .ranking"
|
||||||
|
|
||||||
|
override fun latestUpdatesSelector() = "#container .ultimos_epis .not"
|
||||||
|
|
||||||
|
override fun searchMangaSelector() = ".top.clearfix .cont_manga"
|
||||||
|
|
||||||
|
override fun chapterListSelector() = "#mamain ul li"
|
||||||
|
|
||||||
|
private fun chapterPageSelector() = "a#l"
|
||||||
|
|
||||||
|
override fun popularMangaNextPageSelector() = null
|
||||||
|
|
||||||
|
override fun latestUpdatesNextPageSelector() = popularMangaNextPageSelector()
|
||||||
|
|
||||||
|
override fun searchMangaNextPageSelector() = popularMangaNextPageSelector()
|
||||||
|
|
||||||
|
|
||||||
|
override fun popularMangaRequest(page: Int) = GET("$baseUrl/top/", headers)
|
||||||
|
|
||||||
|
override fun latestUpdatesRequest(page: Int) = GET("$baseUrl/", headers)
|
||||||
|
|
||||||
|
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
||||||
|
val search_url = "$baseUrl/buscar/$query"
|
||||||
|
|
||||||
|
// Filter
|
||||||
|
if(query.isBlank()) {
|
||||||
|
val ext = ".html"
|
||||||
|
var name = ""
|
||||||
|
filters.forEach { filter ->
|
||||||
|
when(filter) {
|
||||||
|
is GenreFilter -> {
|
||||||
|
if(filter.toUriPart().isNotBlank() && filter.state != 0) {
|
||||||
|
name = filter.toUriPart()
|
||||||
|
return GET("$baseUrl/genero/$name$ext", headers)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is AlphabeticoFilter -> {
|
||||||
|
if(filter.toUriPart().isNotBlank() && filter.state != 0) {
|
||||||
|
name = filter.toUriPart()
|
||||||
|
return GET("$baseUrl/letra/$name$ext", headers)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is ListaCompletasFilter -> {
|
||||||
|
if(filter.toUriPart().isNotBlank() && filter.state != 0) {
|
||||||
|
name = filter.toUriPart()
|
||||||
|
return GET("$baseUrl/$name/", headers)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return GET(search_url, headers)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun imageUrlRequest(page: Page) = GET(page.url, headers)
|
||||||
|
|
||||||
|
// get contents of a url
|
||||||
|
private fun getUrlContents(url: String): Document = client.newCall(GET(url, headers)).execute().asJsoup()
|
||||||
|
|
||||||
|
|
||||||
|
override fun popularMangaFromElement(element: Element) = SManga.create().apply {
|
||||||
|
element.select("a").let {
|
||||||
|
setUrlWithoutDomain(it.attr("href"))
|
||||||
|
val allElements: Elements = it.select(".box .tit")
|
||||||
|
//get all elements under .box .tit
|
||||||
|
for (e: Element in allElements) {
|
||||||
|
title = e.childNode(0).toString() //the title
|
||||||
|
}
|
||||||
|
thumbnail_url = it.select(".box img").attr("src")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun latestUpdatesFromElement(element: Element) = SManga.create().apply {
|
||||||
|
element.select("a").let {
|
||||||
|
val latestChapter = getUrlContents(it.attr("href"))
|
||||||
|
val url = latestChapter.select(".rpwe-clearfix:last-child a")
|
||||||
|
setUrlWithoutDomain(url.attr("href"))
|
||||||
|
title = it.select("span span").text()
|
||||||
|
thumbnail_url = it.select("img").attr("src")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun searchMangaFromElement(element: Element) = SManga.create().apply {
|
||||||
|
element.select("a").let {
|
||||||
|
setUrlWithoutDomain(it.attr("href"))
|
||||||
|
title = it.select("header").text()
|
||||||
|
thumbnail_url = it.select("img").attr("src")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun chapterFromElement(element: Element): SChapter {
|
||||||
|
val urlElement = element.select("a").first()
|
||||||
|
val timeElement = element.select("span").first()
|
||||||
|
val time = timeElement.text()
|
||||||
|
val date = time.replace("--", "-")
|
||||||
|
val url = urlElement.attr("href")
|
||||||
|
|
||||||
|
val chapter = SChapter.create()
|
||||||
|
chapter.setUrlWithoutDomain(url)
|
||||||
|
chapter.name = urlElement.text()
|
||||||
|
chapter.date_upload = parseChapterDate(date.toString())
|
||||||
|
return chapter
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override fun mangaDetailsParse(document: Document) = SManga.create().apply {
|
||||||
|
document.select(".left.home").let {
|
||||||
|
val genres = it.select(".sinopsis a")?.map {
|
||||||
|
it.text()
|
||||||
|
}
|
||||||
|
|
||||||
|
genre = genres?.joinToString(", ")
|
||||||
|
val allElements: Elements = document.select(".sinopsis")
|
||||||
|
//get all elements under .sinopsis
|
||||||
|
for (e: Element in allElements) {
|
||||||
|
description = e.childNode(0).toString() //the description
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
thumbnail_url = document.select(".cover.clearfix img[style='width:142px;height:212px;']").attr("src")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun parseChapterDate(date: String): Long = SimpleDateFormat("dd-MM-yyyy", Locale.getDefault()).parse(date).time
|
||||||
|
|
||||||
|
override fun chapterListParse(response: Response): List<SChapter> {
|
||||||
|
val chapters = mutableListOf<SChapter>()
|
||||||
|
val document = response.asJsoup()
|
||||||
|
document.select(chapterListSelector()).forEach {
|
||||||
|
chapters.add(chapterFromElement(it))
|
||||||
|
}
|
||||||
|
return chapters
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override fun imageUrlParse(document: Document) = document.select("#p").attr("src").toString()
|
||||||
|
|
||||||
|
override fun pageListParse(document: Document): List<Page> {
|
||||||
|
val pages = mutableListOf<Page>()
|
||||||
|
val leerUrl = document.select(chapterPageSelector()).attr("href")
|
||||||
|
val urlElement = getUrlContents(leerUrl)
|
||||||
|
urlElement.body().select("option").forEach {
|
||||||
|
pages.add(Page(pages.size, it.attr("value")))
|
||||||
|
}
|
||||||
|
pages.getOrNull(0)?.imageUrl = imageUrlParse(urlElement)
|
||||||
|
|
||||||
|
return pages
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Array.from(document.querySelectorAll('.categorias a')).map(a => `Pair("${a.textContent}", "${a.getAttribute('href')}")`).join(',\n')
|
||||||
|
* on http://heavenmanga.com/top/
|
||||||
|
* */
|
||||||
|
private class GenreFilter : UriPartFilter("Géneros", arrayOf(
|
||||||
|
Pair("Todo", ""),
|
||||||
|
Pair("Accion", "accion"),
|
||||||
|
Pair("Adulto", "adulto"),
|
||||||
|
Pair("Aventura", "aventura"),
|
||||||
|
Pair("Artes Marciales", "artes+marciales"),
|
||||||
|
Pair("Acontesimientos de la Vida", "acontesimientos+de+la+vida"),
|
||||||
|
Pair("Bakunyuu", "bakunyuu"),
|
||||||
|
Pair("Sci-fi", "sci-fi"),
|
||||||
|
Pair("Comic", "comic"),
|
||||||
|
Pair("Combate", "combate"),
|
||||||
|
Pair("Comedia", "comedia"),
|
||||||
|
Pair("Cooking", "cooking"),
|
||||||
|
Pair("Cotidiano", "cotidiano"),
|
||||||
|
Pair("Colegialas", "colegialas"),
|
||||||
|
Pair("Critica social", "critica+social"),
|
||||||
|
Pair("Ciencia ficcion", "ciencia+ficcion"),
|
||||||
|
Pair("Cambio de genero", "cambio+de+genero"),
|
||||||
|
Pair("Cosas de la Vida", "cosas+de+la+vida"),
|
||||||
|
Pair("Drama", "drama"),
|
||||||
|
Pair("Deporte", "deporte"),
|
||||||
|
Pair("Doujinshi", "doujinshi"),
|
||||||
|
Pair("Delincuentes", "delincuentes"),
|
||||||
|
Pair("Ecchi", "ecchi"),
|
||||||
|
Pair("Escolar", "escolar"),
|
||||||
|
Pair("Erotico", "erotico"),
|
||||||
|
Pair("Escuela", "escuela"),
|
||||||
|
Pair("Estilo de Vida", "estilo+de+vida"),
|
||||||
|
Pair("Fantasia", "fantasia"),
|
||||||
|
Pair("Fragmentos de la Vida", "fragmentos+de+la+vida"),
|
||||||
|
Pair("Gore", "gore"),
|
||||||
|
Pair("Gender Bender", "gender+bender"),
|
||||||
|
Pair("Humor", "humor"),
|
||||||
|
Pair("Harem", "harem"),
|
||||||
|
Pair("Haren", "haren"),
|
||||||
|
Pair("Hentai", "hentai"),
|
||||||
|
Pair("Horror", "horror"),
|
||||||
|
Pair("Historico", "historico"),
|
||||||
|
Pair("Josei", "josei"),
|
||||||
|
Pair("Loli", "loli"),
|
||||||
|
Pair("Light", "light"),
|
||||||
|
Pair("Lucha Libre", "lucha+libre"),
|
||||||
|
Pair("Manga", "manga"),
|
||||||
|
Pair("Mecha", "mecha"),
|
||||||
|
Pair("Magia", "magia"),
|
||||||
|
Pair("Maduro", "maduro"),
|
||||||
|
Pair("Manhwa", "manhwa"),
|
||||||
|
Pair("Manwha", "manwha"),
|
||||||
|
Pair("Mature", "mature"),
|
||||||
|
Pair("Misterio", "misterio"),
|
||||||
|
Pair("Mutantes", "mutantes"),
|
||||||
|
Pair("Novela", "novela"),
|
||||||
|
Pair("Orgia", "orgia"),
|
||||||
|
Pair("OneShot", "oneshot"),
|
||||||
|
Pair("OneShots", "oneshots"),
|
||||||
|
Pair("Psicologico", "psicologico"),
|
||||||
|
Pair("Romance", "romance"),
|
||||||
|
Pair("Recuentos de la vida", "recuentos+de+la+vida"),
|
||||||
|
Pair("Smut", "smut"),
|
||||||
|
Pair("Shojo", "shojo"),
|
||||||
|
Pair("Shonen", "shonen"),
|
||||||
|
Pair("Seinen", "seinen"),
|
||||||
|
Pair("Shoujo", "shoujo"),
|
||||||
|
Pair("Shounen", "shounen"),
|
||||||
|
Pair("Suspenso", "suspenso"),
|
||||||
|
Pair("School Life", "school+life"),
|
||||||
|
Pair("Sobrenatural", "sobrenatural"),
|
||||||
|
Pair("SuperHeroes", "superheroes"),
|
||||||
|
Pair("Supernatural", "supernatural"),
|
||||||
|
Pair("Slice of Life", "slice+of+life"),
|
||||||
|
Pair("Super Poderes", "ssuper+poderes"),
|
||||||
|
Pair("Terror", "terror"),
|
||||||
|
Pair("Torneo", "torneo"),
|
||||||
|
Pair("Tragedia", "tragedia"),
|
||||||
|
Pair("Transexual", "transexual"),
|
||||||
|
Pair("Vida", "vida"),
|
||||||
|
Pair("Vampiros", "vampiros"),
|
||||||
|
Pair("Violencia", "violencia"),
|
||||||
|
Pair("Vida Pasada", "vida+pasada"),
|
||||||
|
Pair("Vida Cotidiana", "vida+cotidiana"),
|
||||||
|
Pair("Vida de Escuela", "vida+de+escuela"),
|
||||||
|
Pair("Webtoon", "webtoon"),
|
||||||
|
Pair("Webtoons", "webtoons"),
|
||||||
|
Pair("Yaoi", "yaoi"),
|
||||||
|
Pair("Yuri", "yuri")
|
||||||
|
))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Array.from(document.querySelectorAll('.letras a')).map(a => `Pair("${a.textContent}", "${a.getAttribute('href')}")`).join(',\n')
|
||||||
|
* on http://heavenmanga.com/top/
|
||||||
|
* */
|
||||||
|
private class AlphabeticoFilter : UriPartFilter("Alfabético", arrayOf(
|
||||||
|
Pair("Todo", ""),
|
||||||
|
Pair("A", "a"),
|
||||||
|
Pair("B", "b"),
|
||||||
|
Pair("C", "c"),
|
||||||
|
Pair("D", "d"),
|
||||||
|
Pair("E", "e"),
|
||||||
|
Pair("F", "f"),
|
||||||
|
Pair("G", "g"),
|
||||||
|
Pair("H", "h"),
|
||||||
|
Pair("I", "i"),
|
||||||
|
Pair("J", "j"),
|
||||||
|
Pair("K", "k"),
|
||||||
|
Pair("L", "l"),
|
||||||
|
Pair("M", "m"),
|
||||||
|
Pair("N", "n"),
|
||||||
|
Pair("O", "o"),
|
||||||
|
Pair("P", "p"),
|
||||||
|
Pair("Q", "q"),
|
||||||
|
Pair("R", "r"),
|
||||||
|
Pair("S", "s"),
|
||||||
|
Pair("T", "t"),
|
||||||
|
Pair("U", "u"),
|
||||||
|
Pair("V", "v"),
|
||||||
|
Pair("W", "w"),
|
||||||
|
Pair("X", "x"),
|
||||||
|
Pair("Y", "y"),
|
||||||
|
Pair("Z", "z"),
|
||||||
|
Pair("0-9", "0-9")
|
||||||
|
))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Array.from(document.querySelectorAll('#t li a')).map(a => `Pair("${a.textContent}", "${a.getAttribute('href')}")`).join(',\n')
|
||||||
|
* on http://heavenmanga.com/top/
|
||||||
|
* */
|
||||||
|
private class ListaCompletasFilter: UriPartFilter("Lista Completa", arrayOf(
|
||||||
|
Pair("Todo", ""),
|
||||||
|
Pair("Lista Comis", "comic"),
|
||||||
|
Pair("Lista Novelas", "novela"),
|
||||||
|
Pair("Lista Adulto", "adulto")
|
||||||
|
))
|
||||||
|
|
||||||
|
override fun getFilterList() = FilterList(
|
||||||
|
// Search and filter don't work at the same time
|
||||||
|
Filter.Header("NOTE: Ignored if using text search!"),
|
||||||
|
GenreFilter(),
|
||||||
|
AlphabeticoFilter(),
|
||||||
|
ListaCompletasFilter()
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
private open class UriPartFilter(displayName: String, val vals: Array<Pair<String, String>>) :
|
||||||
|
Filter.Select<String>(displayName, vals.map { it.first }.toTypedArray()) {
|
||||||
|
fun toUriPart() = vals[state].second
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Binary file not shown.
After Width: | Height: | Size: 131 KiB |
Loading…
Reference in New Issue