MangaEsp: Update domain and add alternative names (#1470)
* Update domain * Get comics from next data (api has old results) * Add alternative names * Change name creation logic Co-authored-by: AwkwardPeak7 <48650614+AwkwardPeak7@users.noreply.github.com> * Missing replace --------- Co-authored-by: AwkwardPeak7 <48650614+AwkwardPeak7@users.noreply.github.com>
This commit is contained in:
parent
942ca100d8
commit
d6f01fea0b
|
@ -1,7 +1,7 @@
|
||||||
ext {
|
ext {
|
||||||
extName = 'MangaEsp'
|
extName = 'MangaEsp'
|
||||||
extClass = '.MangaEsp'
|
extClass = '.MangaEsp'
|
||||||
extVersionCode = 1
|
extVersionCode = 2
|
||||||
isNsfw = false
|
isNsfw = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,9 +29,9 @@ class MangaEsp : HttpSource() {
|
||||||
|
|
||||||
override val name = "MangaEsp"
|
override val name = "MangaEsp"
|
||||||
|
|
||||||
override val baseUrl = "https://mangaesp.co"
|
override val baseUrl = "https://mangaesp.net"
|
||||||
|
|
||||||
private val apiBaseUrl = "https://apis.mangaesp.co"
|
private val apiBaseUrl = "https://apis.mangaesp.net"
|
||||||
|
|
||||||
override val lang = "es"
|
override val lang = "es"
|
||||||
|
|
||||||
|
@ -57,13 +57,7 @@ class MangaEsp : HttpSource() {
|
||||||
val topWeekly = responseData.response.topWeekly.flatten().map { it.data }
|
val topWeekly = responseData.response.topWeekly.flatten().map { it.data }
|
||||||
val topMonthly = responseData.response.topMonthly.flatten().map { it.data }
|
val topMonthly = responseData.response.topMonthly.flatten().map { it.data }
|
||||||
|
|
||||||
val mangas = (topDaily + topWeekly + topMonthly).distinctBy { it.slug }.map { series ->
|
val mangas = (topDaily + topWeekly + topMonthly).distinctBy { it.slug }.map { it.toSManga() }
|
||||||
SManga.create().apply {
|
|
||||||
title = series.name
|
|
||||||
thumbnail_url = series.thumbnail
|
|
||||||
url = "/ver/${series.slug}"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return MangasPage(mangas, false)
|
return MangasPage(mangas, false)
|
||||||
}
|
}
|
||||||
|
@ -73,13 +67,7 @@ class MangaEsp : HttpSource() {
|
||||||
override fun latestUpdatesParse(response: Response): MangasPage {
|
override fun latestUpdatesParse(response: Response): MangasPage {
|
||||||
val responseData = json.decodeFromString<LastUpdatesDto>(response.body.string())
|
val responseData = json.decodeFromString<LastUpdatesDto>(response.body.string())
|
||||||
|
|
||||||
val mangas = responseData.response.map { series ->
|
val mangas = responseData.response.map { it.toSManga() }
|
||||||
SManga.create().apply {
|
|
||||||
title = series.name
|
|
||||||
thumbnail_url = series.thumbnail
|
|
||||||
url = "/ver/${series.slug}"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return MangasPage(mangas, false)
|
return MangasPage(mangas, false)
|
||||||
}
|
}
|
||||||
|
@ -100,13 +88,17 @@ class MangaEsp : HttpSource() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request = GET("$baseUrl/api/comics", headers)
|
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request = GET("$baseUrl/comics", headers)
|
||||||
|
|
||||||
override fun searchMangaParse(response: Response): MangasPage = throw UnsupportedOperationException()
|
override fun searchMangaParse(response: Response): MangasPage = throw UnsupportedOperationException()
|
||||||
|
|
||||||
private fun searchMangaParse(response: Response, page: Int, query: String, filters: FilterList): MangasPage {
|
private fun searchMangaParse(response: Response, page: Int, query: String, filters: FilterList): MangasPage {
|
||||||
val responseData = json.decodeFromString<ComicsDto>(response.body.string())
|
val document = response.asJsoup()
|
||||||
comicsList = responseData.response.toMutableList()
|
val script = document.select("script:containsData(self.__next_f.push)").joinToString { it.data() }
|
||||||
|
val jsonString = MANGA_LIST_REGEX.find(script)?.groupValues?.get(1)
|
||||||
|
?: throw Exception("No se pudo encontrar la lista de comics")
|
||||||
|
val unescapedJson = jsonString.unescape()
|
||||||
|
comicsList = json.decodeFromString<List<SeriesDto>>(unescapedJson).toMutableList()
|
||||||
return parseComicsList(page, query, filters)
|
return parseComicsList(page, query, filters)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,7 +110,11 @@ class MangaEsp : HttpSource() {
|
||||||
|
|
||||||
if (query.isNotBlank()) {
|
if (query.isNotBlank()) {
|
||||||
if (query.length < 2) throw Exception("La búsqueda debe tener al menos 2 caracteres")
|
if (query.length < 2) throw Exception("La búsqueda debe tener al menos 2 caracteres")
|
||||||
filteredList.addAll(comicsList.filter { it.name.contains(query, ignoreCase = true) })
|
filteredList.addAll(
|
||||||
|
comicsList.filter {
|
||||||
|
it.name.contains(query, ignoreCase = true) || it.alternativeName?.contains(query, ignoreCase = true) == true
|
||||||
|
},
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
filteredList.addAll(comicsList)
|
filteredList.addAll(comicsList)
|
||||||
}
|
}
|
||||||
|
@ -154,7 +150,7 @@ class MangaEsp : HttpSource() {
|
||||||
|
|
||||||
return MangasPage(
|
return MangasPage(
|
||||||
filteredList.subList((page - 1) * MANGAS_PER_PAGE, min(page * MANGAS_PER_PAGE, filteredList.size))
|
filteredList.subList((page - 1) * MANGAS_PER_PAGE, min(page * MANGAS_PER_PAGE, filteredList.size))
|
||||||
.map { it.toSimpleSManga() },
|
.map { it.toSManga() },
|
||||||
hasNextPage,
|
hasNextPage,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -163,42 +159,24 @@ class MangaEsp : HttpSource() {
|
||||||
val responseBody = response.body.string()
|
val responseBody = response.body.string()
|
||||||
val mangaDetailsJson = MANGA_DETAILS_REGEX.find(responseBody)?.groupValues?.get(1)
|
val mangaDetailsJson = MANGA_DETAILS_REGEX.find(responseBody)?.groupValues?.get(1)
|
||||||
?: throw Exception("No se pudo encontrar los detalles del manga")
|
?: throw Exception("No se pudo encontrar los detalles del manga")
|
||||||
val unescapedJson = mangaDetailsJson.replace("\\", "")
|
val unescapedJson = mangaDetailsJson.unescape()
|
||||||
|
|
||||||
val series = json.decodeFromString<SeriesDto>(unescapedJson)
|
return json.decodeFromString<SeriesDto>(unescapedJson).toSMangaDetails()
|
||||||
return SManga.create().apply {
|
|
||||||
title = series.name
|
|
||||||
thumbnail_url = series.thumbnail
|
|
||||||
description = series.synopsis
|
|
||||||
genre = series.genders.joinToString { it.gender.name }
|
|
||||||
author = series.authors.joinToString { it.author.name }
|
|
||||||
artist = series.artists.joinToString { it.artist.name }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun chapterListParse(response: Response): List<SChapter> {
|
override fun chapterListParse(response: Response): List<SChapter> {
|
||||||
val responseBody = response.body.string()
|
val responseBody = response.body.string()
|
||||||
val mangaDetailsJson = MANGA_DETAILS_REGEX.find(responseBody)?.groupValues?.get(1)
|
val mangaDetailsJson = MANGA_DETAILS_REGEX.find(responseBody)?.groupValues?.get(1)
|
||||||
?: throw Exception("No se pudo encontrar la lista de capítulos")
|
?: throw Exception("No se pudo encontrar la lista de capítulos")
|
||||||
val unescapedJson = mangaDetailsJson.replace("\\", "")
|
val unescapedJson = mangaDetailsJson.unescape()
|
||||||
val series = json.decodeFromString<SeriesDto>(unescapedJson)
|
val series = json.decodeFromString<SeriesDto>(unescapedJson)
|
||||||
return series.chapters.map { chapter ->
|
return series.chapters.map { it.toSChapter(series.slug, dateFormat) }
|
||||||
SChapter.create().apply {
|
|
||||||
name = if (chapter.name.isNullOrBlank()) {
|
|
||||||
"Capítulo ${chapter.number.toString().removeSuffix(".0")}"
|
|
||||||
} else {
|
|
||||||
"Capítulo ${chapter.number.toString().removeSuffix(".0")} - ${chapter.name}"
|
|
||||||
}
|
|
||||||
date_upload = runCatching { dateFormat.parse(chapter.date)?.time }.getOrNull() ?: 0L
|
|
||||||
url = "/ver/${series.slug}/${chapter.slug}"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun pageListParse(response: Response): List<Page> {
|
override fun pageListParse(response: Response): List<Page> {
|
||||||
val document = response.asJsoup()
|
val document = response.asJsoup()
|
||||||
return document.select("main.contenedor.read img").mapIndexed { i, img ->
|
return document.select("main.contenedor.read img").mapIndexed { i, img ->
|
||||||
Page(i, "", img.imgAttr())
|
Page(i, imageUrl = img.imgAttr())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -254,8 +232,14 @@ class MangaEsp : HttpSource() {
|
||||||
else -> attr("abs:src")
|
else -> attr("abs:src")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun String.unescape(): String {
|
||||||
|
return UNESCAPE_REGEX.replace(this, "$1")
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val MANGA_DETAILS_REGEX = """self.__next_f.push\(.*data\\":(\{.*lastChapters.*\}).*numFollow""".toRegex()
|
private val UNESCAPE_REGEX = """\\(.)""".toRegex()
|
||||||
|
private val MANGA_LIST_REGEX = """self\.__next_f\.push\(.*data\\":(\[.*trending.*])\}""".toRegex()
|
||||||
|
private val MANGA_DETAILS_REGEX = """self\.__next_f\.push\(.*data\\":(\{.*lastChapters.*\}).*numFollow""".toRegex()
|
||||||
private const val MANGAS_PER_PAGE = 15
|
private const val MANGAS_PER_PAGE = 15
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,91 +1,118 @@
|
||||||
package eu.kanade.tachiyomi.extension.es.mangaesp
|
package eu.kanade.tachiyomi.extension.es.mangaesp
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.source.model.SChapter
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class TopSeriesDto(
|
class TopSeriesDto(
|
||||||
val response: TopSeriesResponseDto,
|
val response: TopSeriesResponseDto,
|
||||||
)
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class LastUpdatesDto(
|
class LastUpdatesDto(
|
||||||
val response: List<SeriesDto>,
|
val response: List<SeriesDto>,
|
||||||
)
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class ComicsDto(
|
class TopSeriesResponseDto(
|
||||||
val response: List<SeriesDto>,
|
|
||||||
)
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class TopSeriesResponseDto(
|
|
||||||
@SerialName("mensual") val topMonthly: List<List<PayloadSeriesDto>>,
|
@SerialName("mensual") val topMonthly: List<List<PayloadSeriesDto>>,
|
||||||
@SerialName("semanal") val topWeekly: List<List<PayloadSeriesDto>>,
|
@SerialName("semanal") val topWeekly: List<List<PayloadSeriesDto>>,
|
||||||
@SerialName("diario") val topDaily: List<List<PayloadSeriesDto>>,
|
@SerialName("diario") val topDaily: List<List<PayloadSeriesDto>>,
|
||||||
)
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class PayloadSeriesDto(
|
class PayloadSeriesDto(
|
||||||
@SerialName("project") val data: SeriesDto,
|
@SerialName("project") val data: SeriesDto,
|
||||||
)
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class SeriesDto(
|
class SeriesDto(
|
||||||
val name: String,
|
val name: String,
|
||||||
|
val alternativeName: String? = null,
|
||||||
val slug: String,
|
val slug: String,
|
||||||
@SerialName("sinopsis") val synopsis: String? = null,
|
@SerialName("sinopsis") private val synopsis: String? = null,
|
||||||
@SerialName("urlImg") val thumbnail: String? = null,
|
@SerialName("urlImg") private val thumbnail: String? = null,
|
||||||
val isVisible: Boolean,
|
|
||||||
@SerialName("actualizacionCap") val lastChapterDate: String? = null,
|
@SerialName("actualizacionCap") val lastChapterDate: String? = null,
|
||||||
@SerialName("created_at") val createdAt: String? = null,
|
@SerialName("created_at") val createdAt: String? = null,
|
||||||
@SerialName("state_id") val status: Int? = 0,
|
@SerialName("state_id") val status: Int? = 0,
|
||||||
val genders: List<SeriesGenderDto> = emptyList(),
|
private val genders: List<GenderDto> = emptyList(),
|
||||||
@SerialName("lastChapters") val chapters: List<SeriesChapterDto> = emptyList(),
|
@SerialName("lastChapters") val chapters: List<ChapterDto> = emptyList(),
|
||||||
val trending: SeriesTrendingDto? = null,
|
val trending: TrendingDto? = null,
|
||||||
@SerialName("autors") val authors: List<SeriesAuthorDto> = emptyList(),
|
@SerialName("autors") private val authors: List<AuthorDto> = emptyList(),
|
||||||
val artists: List<SeriesArtistDto> = emptyList(),
|
private val artists: List<ArtistDto> = emptyList(),
|
||||||
|
|
||||||
) {
|
) {
|
||||||
fun toSimpleSManga(): SManga {
|
fun toSManga(): SManga {
|
||||||
return SManga.create().apply {
|
return SManga.create().apply {
|
||||||
title = name
|
title = name
|
||||||
thumbnail_url = thumbnail
|
thumbnail_url = thumbnail
|
||||||
url = "/ver/$slug"
|
url = "/ver/$slug"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun toSMangaDetails(): SManga {
|
||||||
|
return SManga.create().apply {
|
||||||
|
title = name
|
||||||
|
thumbnail_url = thumbnail
|
||||||
|
description = synopsis
|
||||||
|
if (!alternativeName.isNullOrBlank()) {
|
||||||
|
if (!description.isNullOrBlank()) description += "\n\n"
|
||||||
|
description += "Nombres alternativos: $alternativeName"
|
||||||
|
}
|
||||||
|
genre = genders.joinToString { it.gender.name }
|
||||||
|
author = authors.joinToString { it.author.name }
|
||||||
|
artist = artists.joinToString { it.artist.name }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class SeriesTrendingDto(
|
class TrendingDto(
|
||||||
@SerialName("visitas") val views: Int? = 0,
|
@SerialName("visitas") val views: Int? = 0,
|
||||||
)
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class SeriesGenderDto(
|
class GenderDto(
|
||||||
val gender: SeriesDetailDataNameDto,
|
val gender: DetailDataNameDto,
|
||||||
)
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class SeriesAuthorDto(
|
class AuthorDto(
|
||||||
@SerialName("autor") val author: SeriesDetailDataNameDto,
|
@SerialName("autor") val author: DetailDataNameDto,
|
||||||
)
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class SeriesArtistDto(
|
class ArtistDto(
|
||||||
val artist: SeriesDetailDataNameDto,
|
val artist: DetailDataNameDto,
|
||||||
)
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class SeriesDetailDataNameDto(
|
class DetailDataNameDto(
|
||||||
val name: String,
|
val name: String,
|
||||||
)
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class SeriesChapterDto(
|
class ChapterDto(
|
||||||
@SerialName("num") val number: Float,
|
@SerialName("num") private val number: Float,
|
||||||
val name: String? = null,
|
private val name: String? = null,
|
||||||
val slug: String,
|
private val slug: String,
|
||||||
@SerialName("created_at") val date: String,
|
@SerialName("created_at") private val date: String,
|
||||||
)
|
) {
|
||||||
|
fun toSChapter(seriesSlug: String, dateFormat: SimpleDateFormat): SChapter {
|
||||||
|
return SChapter.create().apply {
|
||||||
|
name = "Capítulo ${number.toString().removeSuffix(".0")}"
|
||||||
|
if (!this@ChapterDto.name.isNullOrBlank()) {
|
||||||
|
name += " - ${this@ChapterDto.name}"
|
||||||
|
}
|
||||||
|
date_upload = try {
|
||||||
|
dateFormat.parse(date)?.time ?: 0L
|
||||||
|
} catch (e: Exception) {
|
||||||
|
0L
|
||||||
|
}
|
||||||
|
url = "/ver/$seriesSlug/$slug"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue