Manhwa latino (#9692)
* First commit Mahnwa-Latino Extension. * manhwa-latino: Implementing find function TODO: only works with text, filter not implemented yet * manhwa-latino Add Parser to finde the information of Manhwa-Latino The parser 'ManhwaLatinoSiteParser.kt' make the whole magic to find the information of the Website. Mudularize The code and adding documentation * manhwa-latino: Adding Logos der Extension TODO: I am not to happy, i will check it later. * manhwa-latino: Adding Tags to Genre Combobox * manhwa-latino: Adding Headers to prevent error 404 The headers are necesary to prevent error 403 by downloading images. * manhwa-latino: Tags addded into Manga Description Page Status from Manga readed from Tags * manhwa-latino: Modularize Code * manhwa-latino: Adding Uploaddate for Chapters * manhwa-latino: Bug to get Chapter Number fixed * manhwa-latino: Logo 0.2 * manhwa-latino: Versionb 1.2.10 Adding Comments to ManhwaLatinoSiteParser * manhwa-latino: Remove logo_model directory * manhwa-latino: Show Seconds after Release a new Chapter Co-authored-by: Luis Beroiza <luisalberto.beroizaosses@intern.osp-dd.de>
This commit is contained in:
parent
c5262ebb59
commit
5695e7e470
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="eu.kanade.tachiyomi.extension" />
|
|
@ -0,0 +1,12 @@
|
|||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
|
||||
ext {
|
||||
extName = 'Manhwa-Latino'
|
||||
pkgNameSuffix = 'es.manhwalatino'
|
||||
extClass = '.ManhwaLatino'
|
||||
extVersionCode = 11
|
||||
containsNsfw = true
|
||||
}
|
||||
|
||||
apply from: "$rootDir/common.gradle"
|
Binary file not shown.
After Width: | Height: | Size: 20 KiB |
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
Binary file not shown.
After Width: | Height: | Size: 30 KiB |
Binary file not shown.
After Width: | Height: | Size: 40 KiB |
Binary file not shown.
After Width: | Height: | Size: 160 KiB |
|
@ -0,0 +1,279 @@
|
|||
package eu.kanade.tachiyomi.extension.es.manhwalatino
|
||||
|
||||
import eu.kanade.tachiyomi.extension.es.manhwalatino.filters.GenreTagFilter
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
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.Headers
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
|
||||
class ManhwaLatino : ParsedHttpSource() {
|
||||
|
||||
/**
|
||||
* Name of the source.
|
||||
*/
|
||||
override val name = "Manhwa-Latino"
|
||||
|
||||
/**
|
||||
* Base url of the website without the trailing slash, like: http://mysite.com
|
||||
*/
|
||||
override val baseUrl = "https://manhwa-latino.com"
|
||||
|
||||
/**
|
||||
* Parser for Mainsite or Genre Site
|
||||
*/
|
||||
val manhwaLatinoSiteParser = ManhwaLatinoSiteParser(baseUrl)
|
||||
|
||||
/**
|
||||
* An ISO 639-1 compliant language code (two letters in lower case).
|
||||
*/
|
||||
override val lang = "es"
|
||||
|
||||
/**
|
||||
* Whether the source has support for latest updates.
|
||||
*/
|
||||
override val supportsLatest = true
|
||||
|
||||
/**
|
||||
* User Agent for this wWebsite
|
||||
*/
|
||||
private val userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 " +
|
||||
"(KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36"
|
||||
|
||||
override fun headersBuilder(): Headers.Builder {
|
||||
return Headers.Builder()
|
||||
.add("User-Agent", userAgent)
|
||||
.add("Referer", "$baseUrl/")
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Jsoup selector that returns a list of [Element] corresponding to each manga.
|
||||
*/
|
||||
override fun popularMangaSelector(): String {
|
||||
return manhwaLatinoSiteParser.popularMangaSelector
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Jsoup selector that returns a list of [Element] corresponding to each manga.
|
||||
*/
|
||||
override fun latestUpdatesSelector(): String {
|
||||
return manhwaLatinoSiteParser.latestUpdatesSelector
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Jsoup selector that returns a list of [Element] corresponding to each manga.
|
||||
*/
|
||||
override fun searchMangaSelector(): String {
|
||||
return manhwaLatinoSiteParser.searchMangaSelector
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Jsoup selector that returns a list of [Element] corresponding to each chapter.
|
||||
*/
|
||||
override fun chapterListSelector() =
|
||||
throw Exception("Not Used")
|
||||
|
||||
/**
|
||||
* Returns the Jsoup selector that returns the <a> tag linking to the next page, or null if
|
||||
* there's no next page.
|
||||
*/
|
||||
override fun popularMangaNextPageSelector(): String {
|
||||
return manhwaLatinoSiteParser.popularMangaNextPageSelector
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Jsoup selector that returns the <a> tag linking to the next page, or null if
|
||||
* there's no next page.
|
||||
*/
|
||||
override fun latestUpdatesNextPageSelector(): String {
|
||||
return manhwaLatinoSiteParser.latestUpdatesNextPageSelector
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Jsoup selector that returns the <a> tag linking to the next page, or null if
|
||||
* there's no next page.
|
||||
*/
|
||||
override fun searchMangaNextPageSelector(): String {
|
||||
return manhwaLatinoSiteParser.searchMangaNextPageSelector
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the request for the popular manga given the page.
|
||||
*
|
||||
* @param page the page number to retrieve.
|
||||
*/
|
||||
override fun popularMangaRequest(page: Int): Request {
|
||||
return GET("$baseUrl/page/$page/", headers)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the request for latest manga given the page.
|
||||
*
|
||||
* @param page the page number to retrieve.
|
||||
*/
|
||||
override fun latestUpdatesRequest(page: Int): Request {
|
||||
return GET("$baseUrl/page/$page/", headers)
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the response from the site and returns a [MangasPage] object.
|
||||
*
|
||||
* @param response the response from the site.
|
||||
*/
|
||||
override fun latestUpdatesParse(response: Response): MangasPage {
|
||||
val document = response.asJsoup()
|
||||
val mangas = document.select(latestUpdatesSelector()).map { latestUpdatesFromElement(it) }
|
||||
return MangasPage(mangas, manhwaLatinoSiteParser.latestUpdatesHasNextPages())
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a manga from the given [element]. Most sites only show the title and the url, it's
|
||||
* totally fine to fill only those two values.
|
||||
*
|
||||
* @param element an element obtained from [latestUpdatesSelector].
|
||||
*/
|
||||
override fun latestUpdatesFromElement(element: Element): SManga {
|
||||
return manhwaLatinoSiteParser.getMangaFromLastTranslatedSlide(element)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the request for the search manga given the page.
|
||||
*
|
||||
* @param page the page number to retrieve.
|
||||
* @param query the search query.
|
||||
* @param filters the list of filters to apply.
|
||||
*/
|
||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
||||
val uri = manhwaLatinoSiteParser.searchMangaRequest(page, query, filters)
|
||||
return GET(uri.toString(), headers)
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the response from the site and returns a [MangasPage] object.
|
||||
*
|
||||
* @param response the response from the site.
|
||||
*/
|
||||
override fun searchMangaParse(response: Response): MangasPage {
|
||||
return manhwaLatinoSiteParser.searchMangaParse(response)
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Returns the request for the details of a manga. Override only if it's needed to change the
|
||||
// * url, send different headers or request method like POST.
|
||||
// *
|
||||
// * @param manga the manga to be updated.
|
||||
// */
|
||||
// override fun mangaDetailsRequest(manga: SManga) = GET(baseUrl + manga.url, headers)
|
||||
|
||||
/**
|
||||
* Returns the request for updating the chapter list. Override only if it's needed to override
|
||||
* the url, send different headers or request method like POST.
|
||||
*
|
||||
* @param manga the manga to look for chapters.
|
||||
*/
|
||||
override fun chapterListRequest(manga: SManga): Request {
|
||||
return GET(baseUrl + manga.url, headers)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a manga from the given [element]. Most sites only show the title and the url, it's
|
||||
* totally fine to fill only those two values.
|
||||
*
|
||||
* @param element an element obtained from [popularMangaSelector].
|
||||
*/
|
||||
override fun popularMangaFromElement(element: Element) = mangaFromElement(element)
|
||||
|
||||
/**
|
||||
* Returns a manga from the given [element]. Most sites only show the title and the url, it's
|
||||
* totally fine to fill only those two values.
|
||||
*
|
||||
* @param element an element obtained from [searchMangaSelector].
|
||||
*/
|
||||
override fun searchMangaFromElement(element: Element) = mangaFromElement(element)
|
||||
|
||||
/**
|
||||
* Returns a manga from the given [element]. Most sites only show the title and the url, it's
|
||||
* totally fine to fill only those two values.
|
||||
*
|
||||
* @param element an element obtained from [searchMangaSelector].
|
||||
*/
|
||||
private fun mangaFromElement(element: Element): SManga {
|
||||
return manhwaLatinoSiteParser.getMangaFromList(element)
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the response from the site and returns a list of chapters.
|
||||
*
|
||||
* @param response the response from the site.
|
||||
*/
|
||||
override fun chapterListParse(response: Response): List<SChapter> {
|
||||
return manhwaLatinoSiteParser.getChapterListParse(response)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a chapter from the given element.
|
||||
*
|
||||
* @param element an element obtained from [chapterListSelector].
|
||||
*/
|
||||
override fun chapterFromElement(element: Element) = throw Exception("Not used")
|
||||
|
||||
/**
|
||||
* Returns the details of the manga from the given [document].
|
||||
*
|
||||
* @param document the parsed document.
|
||||
*/
|
||||
override fun mangaDetailsParse(document: Document): SManga {
|
||||
return manhwaLatinoSiteParser.getMangaDetails(document)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the request for getting the page list. Override only if it's needed to override the
|
||||
* url, send different headers or request method like POST.
|
||||
* (Request to Webseite with comic)
|
||||
*
|
||||
* @param chapter the chapter whose page list has to be fetched.
|
||||
*/
|
||||
override fun pageListRequest(chapter: SChapter): Request {
|
||||
return GET(baseUrl + chapter.url, headers)
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the response from the site and returns the page list.
|
||||
* (Parse the comic pages from the website with the chapter)
|
||||
*
|
||||
* @param response the response from the site.
|
||||
*/
|
||||
override fun pageListParse(response: Response): List<Page> {
|
||||
return manhwaLatinoSiteParser.getPageListParse(response)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a page list from the given document.
|
||||
*
|
||||
* @param document the parsed document.
|
||||
*/
|
||||
override fun pageListParse(document: Document) = throw Exception("Not Used")
|
||||
|
||||
override fun imageUrlParse(document: Document) = throw Exception("Not Used")
|
||||
|
||||
/**
|
||||
* Returns the list of filters for the source.
|
||||
*/
|
||||
override fun getFilterList() = FilterList(
|
||||
Filter.Header("NOTA: ¡La búsqueda de títulos no funciona!"), // "Title search not working"
|
||||
Filter.Separator(),
|
||||
GenreTagFilter(),
|
||||
// LetterFilter(),
|
||||
// StatusFilter(),
|
||||
// SortFilter()
|
||||
)
|
||||
}
|
|
@ -0,0 +1,294 @@
|
|||
package eu.kanade.tachiyomi.extension.es.manhwalatino
|
||||
|
||||
import android.net.Uri
|
||||
import eu.kanade.tachiyomi.extension.es.manhwalatino.filters.UriFilter
|
||||
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.util.asJsoup
|
||||
import okhttp3.Response
|
||||
import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Calendar
|
||||
import java.util.Locale
|
||||
|
||||
class ManhwaLatinoSiteParser(private val baseUrl: String) {
|
||||
|
||||
/**
|
||||
* TODO: ADD SEARCH_TAG
|
||||
*/
|
||||
enum class SearchType {
|
||||
SEARCH_FREE, SEARCH_FILTER
|
||||
}
|
||||
|
||||
/**
|
||||
* Type of search ( FREE, FILTER)
|
||||
*/
|
||||
var searchType = SearchType.SEARCH_FREE
|
||||
|
||||
private val urlHTMLSelector: String = "a"
|
||||
private val titleHTMLSelector: String = "h3"
|
||||
private val thumbnailUrlMangaListHTMLSelector: String = "div.item-thumb.c-image-hover img"
|
||||
private val authorHTMLSelector: String = "div.author-content"
|
||||
private val artistHTMLSelector: String = "div.artist-content"
|
||||
private val descriptionHTMLSelector: String = "div.summary__content.show-more p"
|
||||
private val genreHTMLSelector: String = "div.genres-content a"
|
||||
private val statusHTMLSelector: String =
|
||||
"div.summary_content div.post-status div.post-content_item div.summary-content"
|
||||
private val thumbnailUrlMangaDetailsHTMLSelector: String = "div.summary_image img"
|
||||
private val tagsHTMLSelector: String = "div.tags-content a"
|
||||
private val searchSiteMangasHTMLSelector = "div.c-tabs-item__content"
|
||||
private val genreSiteMangasHTMLSelector = "div.page-item-detail.manga"
|
||||
private val latestUpdatesSelectorUrl = "div.slider__thumb_item a"
|
||||
private val latestUpdatesSelectorThumbnailUrl = "div.slider__thumb_item a img"
|
||||
private val latestUpdatesSelectorTitle = "div.slider__content h4"
|
||||
private val chapterListParseSelector = "li.wp-manga-chapter"
|
||||
private val chapterLinkParser = "a"
|
||||
private val chapterReleaseDateLinkParser = "span.chapter-release-date a"
|
||||
private val chapterReleaseDateIParser = "span.chapter-release-date i"
|
||||
private val pageListParseSelector = "div.page-break.no-gaps img"
|
||||
|
||||
val searchMangaNextPageSelector = "link[rel=next]"
|
||||
val latestUpdatesSelector = "div.slider__item"
|
||||
|
||||
val popularMangaSelector = "div.page-item-detail.manga"
|
||||
val searchMangaSelector = "div.page-item-detail.manga"
|
||||
val popularMangaNextPageSelector = "a.nextpostslink"
|
||||
val latestUpdatesNextPageSelector = "div[role=navigation] a.last"
|
||||
|
||||
/**
|
||||
* The Latest Updates are in a Slider, this Methods get a Manga from the slide
|
||||
*/
|
||||
fun getMangaFromLastTranslatedSlide(element: Element): SManga {
|
||||
val manga = SManga.create()
|
||||
manga.url =
|
||||
getUrlWithoutDomain(element.select(latestUpdatesSelectorUrl).first().attr("abs:href"))
|
||||
manga.title = element.select(latestUpdatesSelectorTitle).text().trim()
|
||||
manga.thumbnail_url = element.select(latestUpdatesSelectorThumbnailUrl).attr("abs:data-src")
|
||||
return manga
|
||||
}
|
||||
|
||||
/**
|
||||
* The Latest Updates has only one site
|
||||
*/
|
||||
fun latestUpdatesHasNextPages() = false
|
||||
|
||||
/**
|
||||
* Get eine Liste mit Mangas from Search Site
|
||||
*/
|
||||
fun getMangasFromSearchSite(document: Document): List<SManga> {
|
||||
return document.select(searchSiteMangasHTMLSelector).map { getMangaFromList(it) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Get eine Liste mit Mangas from Genre Site
|
||||
*/
|
||||
fun getMangasFromGenreSite(document: Document): List<SManga> {
|
||||
return document.select(genreSiteMangasHTMLSelector).map { getMangaFromList(it) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse The Information from Mangas From Search or Genre Site
|
||||
* Title, Address and thumbnail_url
|
||||
*/
|
||||
fun getMangaFromList(element: Element): SManga {
|
||||
val manga = SManga.create()
|
||||
manga.url = getUrlWithoutDomain(element.select(urlHTMLSelector).first().attr("abs:href"))
|
||||
manga.title = element.select(titleHTMLSelector).text().trim()
|
||||
manga.thumbnail_url = element.select(thumbnailUrlMangaListHTMLSelector).attr("abs:data-src")
|
||||
return manga
|
||||
}
|
||||
|
||||
/**
|
||||
* Get The Details of a Manga Main Website
|
||||
* Description, genre, tags, picture (thumbnail_url)
|
||||
* status...
|
||||
*/
|
||||
fun getMangaDetails(document: Document): SManga {
|
||||
val manga = SManga.create()
|
||||
|
||||
val descriptionList = document.select(descriptionHTMLSelector).map { it.text() }
|
||||
val author = document.select(authorHTMLSelector).text()
|
||||
val artist = document.select(artistHTMLSelector).text()
|
||||
|
||||
val genrelist = document.select(genreHTMLSelector).map { it.text() }
|
||||
val tagList = document.select(tagsHTMLSelector).map { it.text() }
|
||||
val genreTagList = genrelist + tagList
|
||||
|
||||
manga.thumbnail_url =
|
||||
document.select(thumbnailUrlMangaDetailsHTMLSelector).attr("abs:data-src")
|
||||
manga.description = descriptionList.joinToString("\n")
|
||||
manga.author = if (author.isBlank()) "Autor Desconocido" else author
|
||||
manga.artist = artist
|
||||
manga.genre = genreTagList.joinToString(", ")
|
||||
manga.status = findMangaStatus(tagList, document)
|
||||
return manga
|
||||
}
|
||||
|
||||
private fun findMangaStatus(tagList: List<String>, document: Document): Int {
|
||||
return if (tagList.contains("Fin")) {
|
||||
SManga.COMPLETED
|
||||
} else {
|
||||
when (document.select(statusHTMLSelector)?.first()?.text()?.trim()) {
|
||||
"Publicandose" -> SManga.ONGOING
|
||||
else -> SManga.UNKNOWN
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the response from the site and returns a list of chapters.
|
||||
*
|
||||
* @param response the response from the site.
|
||||
*/
|
||||
fun getChapterListParse(response: Response): List<SChapter> {
|
||||
return response.asJsoup().select(chapterListParseSelector).map { element ->
|
||||
// Link to the Chapter with the info (address and chapter title)
|
||||
val chapterInfo = element.select(chapterLinkParser)
|
||||
// Chaptername
|
||||
val chapterName = chapterInfo.text().trim()
|
||||
// release date came as text with format dd/mm/yyyy from a link or <i>dd/mm/yyyy</i>
|
||||
val chapterReleaseDate = getChapterReleaseDate(element)
|
||||
SChapter.create().apply {
|
||||
name = chapterName
|
||||
chapter_number = getChapterNumber(chapterName)
|
||||
url = getUrlWithoutDomain(chapterInfo.attr("abs:href"))
|
||||
date_upload = parseChapterReleaseDate(chapterReleaseDate)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of Chapter from Chaptername
|
||||
*/
|
||||
private fun getChapterNumber(chapterName: String): Float =
|
||||
Regex("""\d+""").find(chapterName)?.value.toString().trim().toFloat()
|
||||
|
||||
/**
|
||||
* Get The String with the information about the Release date of the Chapter
|
||||
*/
|
||||
private fun getChapterReleaseDate(element: Element): String {
|
||||
val chapterReleaseDateLink = element.select(chapterReleaseDateLinkParser).attr("title")
|
||||
val chapterReleaseDateI = element.select(chapterReleaseDateIParser).text()
|
||||
return when {
|
||||
chapterReleaseDateLink.isNotEmpty() -> chapterReleaseDateLink
|
||||
chapterReleaseDateI.isNotEmpty() -> chapterReleaseDateI
|
||||
else -> ""
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform String with the Date of Release into Long format
|
||||
*/
|
||||
private fun parseChapterReleaseDate(releaseDateStr: String): Long {
|
||||
val regExSecs = Regex("""hace\s+(\d+)\s+segundos?""")
|
||||
val regExMins = Regex("""hace\s+(\d+)\s+mins?""")
|
||||
val regExHours = Regex("""hace\s+(\d+)\s+horas?""")
|
||||
val regExDays = Regex("""hace\s+(\d+)\s+días?""")
|
||||
val regExDate = Regex("""\d+/\d+/\d+""")
|
||||
|
||||
return when {
|
||||
regExSecs.containsMatchIn(releaseDateStr) ->
|
||||
getReleaseTime(releaseDateStr, Calendar.SECOND)
|
||||
|
||||
regExMins.containsMatchIn(releaseDateStr) ->
|
||||
getReleaseTime(releaseDateStr, Calendar.MINUTE)
|
||||
|
||||
regExHours.containsMatchIn(releaseDateStr) ->
|
||||
getReleaseTime(releaseDateStr, Calendar.HOUR)
|
||||
|
||||
regExDays.containsMatchIn(releaseDateStr) ->
|
||||
getReleaseTime(releaseDateStr, Calendar.DAY_OF_YEAR)
|
||||
|
||||
regExDate.containsMatchIn(releaseDateStr) ->
|
||||
SimpleDateFormat("dd/MM/yyyy", Locale.getDefault()).parse(releaseDateStr).time
|
||||
|
||||
else -> 0
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the Release time from a Text String
|
||||
* Format of the String "hace\s+\d+\s(segundo|minuto|hora|dia)s?"
|
||||
*/
|
||||
private fun getReleaseTime(releaseDateStr: String, timeType: Int): Long {
|
||||
val releaseTimeAgo = Regex("""\d+""").find(releaseDateStr)?.value.toString().toInt()
|
||||
val calendar = Calendar.getInstance()
|
||||
calendar.add(timeType, -releaseTimeAgo)
|
||||
return calendar.timeInMillis
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the response from the site and returns the page list.
|
||||
* (Parse the comic pages from the website with the chapter)
|
||||
*
|
||||
* @param response the response from the site.
|
||||
*/
|
||||
fun getPageListParse(response: Response): List<Page> {
|
||||
val list =
|
||||
response.asJsoup().select(pageListParseSelector).mapIndexed { index, imgElement ->
|
||||
Page(index, "", imgElement.attr("abs:data-src"))
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the request for the search manga given the page.
|
||||
*
|
||||
* @param page the page number to retrieve.
|
||||
* @param query the search query.
|
||||
* @param filters the list of filters to apply.
|
||||
*/
|
||||
fun searchMangaRequest(page: Int, query: String, filters: FilterList): Uri.Builder {
|
||||
val uri = Uri.parse(baseUrl).buildUpon()
|
||||
if (query.isNotBlank()) {
|
||||
searchType = SearchType.SEARCH_FREE
|
||||
uri.appendQueryParameter("s", query)
|
||||
.appendQueryParameter("post_type", "wp-manga")
|
||||
} else {
|
||||
searchType = SearchType.SEARCH_FILTER
|
||||
// Append uri filters
|
||||
filters.forEach {
|
||||
if (it is UriFilter)
|
||||
it.addToUri(uri)
|
||||
}
|
||||
uri.appendPath("page").appendPath(page.toString())
|
||||
}
|
||||
return uri
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the response from the site and returns a [MangasPage] object.
|
||||
*
|
||||
* @param response the response from the site.
|
||||
*/
|
||||
fun searchMangaParse(response: Response): MangasPage {
|
||||
val document = response.asJsoup()
|
||||
val hasNextPages = hasNextPages(document)
|
||||
val mangas: List<SManga>
|
||||
|
||||
when (searchType) {
|
||||
SearchType.SEARCH_FREE ->
|
||||
mangas = getMangasFromSearchSite(document)
|
||||
SearchType.SEARCH_FILTER ->
|
||||
mangas = getMangasFromGenreSite(document)
|
||||
}
|
||||
|
||||
return MangasPage(mangas, hasNextPages)
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if there ir another page to show
|
||||
*/
|
||||
fun hasNextPages(document: Document): Boolean {
|
||||
return !document.select(searchMangaNextPageSelector).isEmpty()
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Address url without the base url.
|
||||
*/
|
||||
protected fun getUrlWithoutDomain(url: String) = url.substringAfter(baseUrl)
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package eu.kanade.tachiyomi.extension.es.manhwalatino.filters
|
||||
|
||||
class GenreTagFilter : UriPartFilter(
|
||||
"Género o Tag",
|
||||
"filtro",
|
||||
arrayOf(
|
||||
Pair("manga-genre/manga", "Todas"),
|
||||
Pair("manga-genre/accion", "Acción"),
|
||||
Pair("manga-genre/adulto", "Adulto"),
|
||||
Pair("manga-genre/aventura", "Aventura"),
|
||||
Pair("manga-genre/bondage", "Bondage"),
|
||||
Pair("manga-genre/cambio-de-pareja", "Cambio de pareja"),
|
||||
Pair("manga-genre/chantaje", "Chantaje"),
|
||||
Pair("manga-genre/ciencia-ficcion", "Ciencia Ficción"),
|
||||
Pair("manga-genre/comedia", "Comedia"),
|
||||
Pair("manga-genre/doujinshi", "Doujinshi"),
|
||||
Pair("manga-genre/drama", "Drama"),
|
||||
Pair("manga-tag/lunes", "Dia Publicación Lunes"),
|
||||
Pair("manga-tag/martes", "Dia Publicación Martes"),
|
||||
Pair("manga-tag/miercoles", "Dia Publicación Miércoles"),
|
||||
Pair("manga-tag/jueves", "Dia Publicación Jueves"),
|
||||
Pair("manga-tag/viernes", "Dia Publicación Viernes"),
|
||||
Pair("manga-tag/sabado", "Dia Publicación Sábado"),
|
||||
Pair("manga-tag/domingo", "Dia Publicación Domingo"),
|
||||
Pair("manga-genre/ecchi", "Ecchi"),
|
||||
Pair("manga-tag/espanol", "Español"),
|
||||
Pair("manga-genre/exhibicion", "Exhibición"),
|
||||
Pair("manga-genre/familia", "Familia"),
|
||||
Pair("manga-genre/fantasia", "Fantasia"),
|
||||
Pair("manga-tag/fin", "Finalizado"),
|
||||
Pair("manga-genre/harem", "Harem"),
|
||||
Pair("manga-genre/manga", "Manga"),
|
||||
Pair("manga-genre/manhua", "Manhua"),
|
||||
Pair("manga-genre/manhwa", "Manhwa"),
|
||||
Pair("manga-genre/misterio", "Misterio"),
|
||||
Pair("manga-genre/ntr", "Ntr"),
|
||||
Pair("manga-genre/obsenidad", "Obsenidad"),
|
||||
Pair("manga-genre/relato vida", "Relato vida"),
|
||||
Pair("manga-genre/romance", "Romance"),
|
||||
Pair("manga-genre/sangre", "Sangre"),
|
||||
Pair("manga-genre/sexo-forzado", "Sexo forzado"),
|
||||
Pair("manga-genre/sometimiento", "Sometimiento"),
|
||||
Pair("manga-genre/tragedia", "Tragedia"),
|
||||
Pair("manga-genre/venganza", "Venganza"),
|
||||
Pair("manga-genre/vida-escolar", "Vida Escolar"),
|
||||
Pair("manga-genre/webtoon", "Webtoon")
|
||||
)
|
||||
)
|
|
@ -0,0 +1,10 @@
|
|||
package eu.kanade.tachiyomi.extension.es.manhwalatino.filters
|
||||
|
||||
import android.net.Uri
|
||||
|
||||
/**
|
||||
* Represents a filter that is able to modify a URI.
|
||||
*/
|
||||
interface UriFilter {
|
||||
fun addToUri(uri: Uri.Builder)
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package eu.kanade.tachiyomi.extension.es.manhwalatino.filters
|
||||
|
||||
import android.net.Uri
|
||||
import eu.kanade.tachiyomi.source.model.Filter
|
||||
|
||||
/**
|
||||
* Class that creates a select filter. Each entry in the dropdown has a name and a display name.
|
||||
* If an entry is selected it is appended as a query parameter onto the end of the URI.
|
||||
* If `firstIsUnspecified` is set to true, if the first entry is selected, nothing will be appended on the the URI.
|
||||
*/
|
||||
// vals: <name, display>
|
||||
open class UriPartFilter(
|
||||
displayName: String,
|
||||
private val uriParam: String,
|
||||
private val vals: Array<Pair<String, String>>,
|
||||
private 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) {
|
||||
val filter = vals[state].first
|
||||
uri.appendPath(filter)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue