diff --git a/src/es/leercapitulo/AndroidManifest.xml b/src/es/leercapitulo/AndroidManifest.xml new file mode 100644 index 000000000..b4571bfa8 --- /dev/null +++ b/src/es/leercapitulo/AndroidManifest.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/src/es/leercapitulo/build.gradle b/src/es/leercapitulo/build.gradle new file mode 100644 index 000000000..281245bb2 --- /dev/null +++ b/src/es/leercapitulo/build.gradle @@ -0,0 +1,12 @@ +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply plugin: 'kotlinx-serialization' + +ext { + extName = 'LeerCapitulo' + pkgNameSuffix = 'es.leercapitulo' + extClass = '.LeerCapitulo' + extVersionCode = 1 +} + +apply from: "$rootDir/common.gradle" \ No newline at end of file diff --git a/src/es/leercapitulo/res/mipmap-hdpi/ic_launcher.png b/src/es/leercapitulo/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 000000000..6649ec5fe Binary files /dev/null and b/src/es/leercapitulo/res/mipmap-hdpi/ic_launcher.png differ diff --git a/src/es/leercapitulo/res/mipmap-mdpi/ic_launcher.png b/src/es/leercapitulo/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 000000000..f2df43ab5 Binary files /dev/null and b/src/es/leercapitulo/res/mipmap-mdpi/ic_launcher.png differ diff --git a/src/es/leercapitulo/res/mipmap-xhdpi/ic_launcher.png b/src/es/leercapitulo/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 000000000..bdd03a256 Binary files /dev/null and b/src/es/leercapitulo/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/src/es/leercapitulo/res/mipmap-xxhdpi/ic_launcher.png b/src/es/leercapitulo/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..47d60c4c0 Binary files /dev/null and b/src/es/leercapitulo/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/src/es/leercapitulo/res/mipmap-xxxhdpi/ic_launcher.png b/src/es/leercapitulo/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 000000000..b732e8ecf Binary files /dev/null and b/src/es/leercapitulo/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/src/es/leercapitulo/res/web_hi_res_512.png b/src/es/leercapitulo/res/web_hi_res_512.png new file mode 100644 index 000000000..44da81cf5 Binary files /dev/null and b/src/es/leercapitulo/res/web_hi_res_512.png differ diff --git a/src/es/leercapitulo/src/eu/kanade/tachiyomi/extension/es/leercapitulo/LeerCapitulo.kt b/src/es/leercapitulo/src/eu/kanade/tachiyomi/extension/es/leercapitulo/LeerCapitulo.kt new file mode 100644 index 000000000..2ac3ccab6 --- /dev/null +++ b/src/es/leercapitulo/src/eu/kanade/tachiyomi/extension/es/leercapitulo/LeerCapitulo.kt @@ -0,0 +1,142 @@ +package eu.kanade.tachiyomi.extension.es.leercapitulo + +import eu.kanade.tachiyomi.extension.es.leercapitulo.dto.MangaDto +import eu.kanade.tachiyomi.network.GET +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 kotlinx.serialization.decodeFromString +import kotlinx.serialization.json.Json +import okhttp3.HttpUrl.Companion.toHttpUrl +import okhttp3.Request +import okhttp3.Response +import org.jsoup.nodes.Document +import org.jsoup.nodes.Element +import uy.kohesive.injekt.injectLazy + +open class LeerCapitulo : ParsedHttpSource() { + override val name = "LeerCapitulo" + + override val baseUrl = "https://www.leercapitulo.com" + + override val lang = "es" + + override val supportsLatest = true + + private val json: Json by injectLazy() + + // Popular + override fun popularMangaRequest(page: Int): Request = + GET(baseUrl, headers) + + override fun popularMangaSelector(): String = + ".hot-manga > .thumbnails > a" + + override fun popularMangaFromElement(element: Element): SManga = SManga.create().apply { + setUrlWithoutDomain(element.attr("abs:href")) + title = element.attr("title") + + thumbnail_url = element.selectFirst("img")!!.attr("abs:src") + } + + override fun popularMangaNextPageSelector(): String? = + null + + // Search + override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { + val url = "$baseUrl/search-autocomplete".toHttpUrl().newBuilder() + .addQueryParameter("term", query) + + return GET(url.toString(), headers) + } + + override fun searchMangaParse(response: Response): MangasPage { + val mangas = json.decodeFromString>(response.body!!.string()).map { + SManga.create().apply { + setUrlWithoutDomain(it.link) + title = it.label + thumbnail_url = baseUrl + it.thumbnail + } + } + + return MangasPage(mangas, hasNextPage = false) + } + + override fun searchMangaSelector(): String = + throw UnsupportedOperationException("Not used.") + + override fun searchMangaFromElement(element: Element): SManga = + throw UnsupportedOperationException("Not used.") + + override fun searchMangaNextPageSelector(): String? = + null + + // Latest + override fun latestUpdatesRequest(page: Int): Request = + popularMangaRequest(page) + + override fun latestUpdatesSelector(): String = + ".mainpage-manga" + + override fun latestUpdatesFromElement(element: Element): SManga = SManga.create().apply { + setUrlWithoutDomain(element.selectFirst(".media-body > a").attr("abs:href")) + title = element.selectFirst("h4").text() + thumbnail_url = element.selectFirst("img").attr("abs:src") + } + + override fun latestUpdatesNextPageSelector(): String? = + null + + // Details + override fun mangaDetailsParse(document: Document): SManga = SManga.create().apply { + title = document.selectFirst("h1").text() + + val altNames = document.selectFirst(".description-update > span:contains(Títulos Alternativos:) + :matchText")?.text() + val desc = document.selectFirst("#example2").text() + description = when (altNames) { + null -> desc + else -> "$desc\n\nAlt name(s): $altNames" + } + + genre = document.select(".description-update a[href^='/genre/']").joinToString { it.text() } + status = document.selectFirst(".description-update > span:contains(Estado:) + :matchText").text().toStatus() + thumbnail_url = document.selectFirst(".cover-detail > img").attr("abs:src") + } + + // Chapters + override fun chapterListSelector(): String = + ".chapter-list > ul > li" + + override fun chapterFromElement(element: Element): SChapter = SChapter.create().apply { + val a = element.selectFirst("a.xanh") + setUrlWithoutDomain(a.attr("abs:href")) + name = a.text() + chapter_number = name + .substringAfter("Capitulo ") + .substringBefore(":") + .toFloatOrNull() + ?: -1f + } + + // Pages + override fun pageListParse(document: Document): List { + val urls = document.selectFirst("#arraydata").text().split(',') + + return urls.mapIndexed { i, image_url -> + Page(i, "", image_url) + } + } + + override fun imageUrlParse(document: Document): String = + throw UnsupportedOperationException("Not used.") + + // Other + private fun String.toStatus() = when (this) { + "Publicándose" -> SManga.ONGOING + "Pausado", "FINALIZADO", "CANCELADO" -> SManga.COMPLETED + else -> SManga.UNKNOWN + } +} diff --git a/src/es/leercapitulo/src/eu/kanade/tachiyomi/extension/es/leercapitulo/dto/MangaDto.kt b/src/es/leercapitulo/src/eu/kanade/tachiyomi/extension/es/leercapitulo/dto/MangaDto.kt new file mode 100644 index 000000000..8d969aae3 --- /dev/null +++ b/src/es/leercapitulo/src/eu/kanade/tachiyomi/extension/es/leercapitulo/dto/MangaDto.kt @@ -0,0 +1,11 @@ +package eu.kanade.tachiyomi.extension.es.leercapitulo.dto + +import kotlinx.serialization.Serializable + +@Serializable +data class MangaDto( + val label: String, + val link: String, + val thumbnail: String, + val value: String, +)