[RU]UniComics Events & Filters parse (break id/url in library) (#11781)

* [RU]UniComics filters

* filter list

* extVersionCode

* no blank search

* baseDefaultUrl

* simple CheckboxCaptcha

* Events parse/filters (break id/url in library)

* search fixes

* only

* toUpperCase

* fix/change chapter naming

* chapter_number substringAfterLast

* fix open WebView
This commit is contained in:
Ejan 2022-05-09 18:14:13 +05:00 committed by GitHub
parent 93054925ae
commit 51b2cc75b5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 147 additions and 35 deletions

View File

@ -6,7 +6,7 @@ ext {
extName = 'UniComics'
pkgNameSuffix = 'ru.unicomics'
extClass = '.UniComics'
extVersionCode = 2
extVersionCode = 3
}
dependencies {

View File

@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.extension.ru.unicomics
import eu.kanade.tachiyomi.lib.ratelimit.RateLimitInterceptor
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
@ -11,6 +12,7 @@ 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.HttpUrl.Companion.toHttpUrlOrNull
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
@ -46,11 +48,36 @@ class UniComics : ParsedHttpSource() {
override fun latestUpdatesRequest(page: Int): Request =
GET("$baseDefaultUrl/comics/online/page/$page", headers)
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request =
GET("https://yandex.ru/search/site/?frame=1&lr=172&searchid=1959358&topdoc=xdm_e=$baseDefaultUrl&xdm_c=default5044&xdm_p=1&v=2.0&web=0&text=$query&p=$page", headers)
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
(if (filters.isEmpty()) getFilterList() else filters).forEach { filter ->
when (filter) {
is getEventsList -> {
if (filter.state > 0) {
return GET("$baseDefaultUrl$PATH_events", headers)
}
}
is Publishers -> {
if (filter.state > 0) {
val publisherName = getPublishersList()[filter.state].url
val publisherUrl =
"$baseDefaultUrl$PATH_publishers/$publisherName/page/$page".toHttpUrlOrNull()!!
.newBuilder()
return GET(publisherUrl.toString(), headers)
}
}
else -> return@forEach
}
}
if (query.isNotEmpty()) {
return GET(
"https://yandex.ru/search/site/?frame=1&lr=172&searchid=1959358&topdoc=xdm_e=$baseDefaultUrl&xdm_c=default5044&xdm_p=1&v=2.0&web=0&text=$query&p=$page",
headers
)
}
return popularMangaRequest(page)
}
override fun searchMangaSelector() =
".b-serp-item__content:has(.b-serp-url__item:contains(/comics/):not(:contains(/comics/events)):not(:contains(/comics/publishers)):not(:contains(/page/))):has(.b-serp-item__title-link:not(:contains(Комиксы читать онлайн бесплатно)))"
".b-serp-item__content:has(.b-serp-url__item:contains(/comics/):not(:contains($PATH_events)):not(:contains($PATH_publishers)):not(:contains(/page/))):has(.b-serp-item__title-link:not(:contains(Комиксы читать онлайн бесплатно)))"
override fun searchMangaNextPageSelector() = ".b-pager__next"
override fun searchMangaFromElement(element: Element): SManga {
@ -61,7 +88,7 @@ class UniComics : ParsedHttpSource() {
"/characters$|/creators$".toRegex().replace(
"/page$".toRegex().replace(
"/[0-9]+/?$".toRegex().replace(
originUrl.substringAfter(PATH_URL).substringAfter(PATH_online).substringAfter(PATH_issue), ""
originUrl.replace(PATH_online, PATH_URL).replace(PATH_issue, PATH_URL), ""
),
""
),
@ -81,18 +108,37 @@ class UniComics : ParsedHttpSource() {
override fun searchMangaParse(response: Response): MangasPage {
val document = response.asJsoup()
if (document.select(".CheckboxCaptcha").isNotEmpty() && baseUrl == baseDefaultUrl) {
if (document.location().contains("$baseDefaultUrl$PATH_events")) {
val mangas = document.select(".list_events").map { element ->
SManga.create().apply {
element.select("a").first().let {
setUrlWithoutDomain("/" + it.attr("href"))
title = it.text()
}
}
}
return MangasPage(mangas, false)
}
if (document.location().contains("$baseDefaultUrl/comics")) {
val mangas = document.select(popularMangaSelector()).map { element ->
popularMangaFromElement(element)
}
return MangasPage(mangas, mangas.isNotEmpty())
}
if (document.select(".CheckboxCaptcha").isNotEmpty()) {
baseUrl = document.location()
throw Exception("Пройдите капчу в WebView(слишком много запросов)")
} else if (baseUrl != baseDefaultUrl) {
baseUrl = baseDefaultUrl
}
var hasNextPage = false
val mangas = document.select(searchMangaSelector()).map { element ->
searchMangaFromElement(element)
}
var hasNextPage = false
val nextSearchPage = document.select(searchMangaNextPageSelector())
if (nextSearchPage.isNotEmpty()) {
hasNextPage = true
@ -111,7 +157,7 @@ class UniComics : ParsedHttpSource() {
.asObservableSuccess()
.map { response ->
val details = mangaDetailsParse(response)
details.url = realQuery
details.url = PATH_URL + realQuery
MangasPage(listOf(details), false)
}
} else {
@ -129,21 +175,14 @@ class UniComics : ParsedHttpSource() {
override fun popularMangaFromElement(element: Element): SManga {
val manga = SManga.create()
manga.thumbnail_url = element.select(".left_comics img").first().attr("src").replace(".jpg", "_big.jpg")
manga.thumbnail_url = element.select(".left_comics img")!!.first().attr("src").replace(".jpg", "_big.jpg")
element.select("a").first().let {
manga.setUrlWithoutDomain(it.attr("href").substringAfter(PATH_URL))
manga.setUrlWithoutDomain(it.attr("href"))
}
manga.title = element.select(".list_title").first().text()
return manga
}
override fun popularMangaParse(response: Response): MangasPage {
val document = response.asJsoup()
val mangas = document.select(popularMangaSelector()).map { element ->
popularMangaFromElement(element)
}
return MangasPage(mangas, true)
}
override fun popularMangaParse(response: Response) = searchMangaParse(response)
override fun latestUpdatesFromElement(element: Element): SManga = popularMangaFromElement(element)
override fun latestUpdatesParse(response: Response): MangasPage = popularMangaParse(response)
@ -153,20 +192,23 @@ class UniComics : ParsedHttpSource() {
override fun latestUpdatesNextPageSelector() = popularMangaNextPageSelector()
override fun mangaDetailsRequest(manga: SManga): Request {
return GET(baseDefaultUrl + PATH_URL + manga.url, headers)
return GET(baseDefaultUrl + manga.url, headers)
}
override fun mangaDetailsParse(document: Document): SManga = SManga.create().apply {
val infoElement = document.select(".block.left.common").first()
val infoElement = document.select(".left_container div").first()
title = infoElement.select("h1").first().text()
thumbnail_url = infoElement.select("img").first().attr("src")
thumbnail_url = if (infoElement.select("img").isNotEmpty())
infoElement.select("img").first().attr("src")
else
document.select(".left_comics img").first().attr("src").replace(".jpg", "_big.jpg")
description = infoElement.select("p").last()?.text()
author = infoElement.select("tr:contains(Издательство)").text()
genre = infoElement.select("tr:contains(Жанр) a").joinToString { it.text() }
}
override fun fetchChapterList(manga: SManga): Observable<List<SChapter>> {
val document = client.newCall(GET(baseDefaultUrl + PATH_URL + manga.url, headers)).execute().asJsoup()
val document = client.newCall(GET(baseDefaultUrl + manga.url, headers)).execute().asJsoup()
val pages = mutableListOf(1)
val dataStrArray = document.toString()
.substringAfter("new Paginator(")
@ -177,33 +219,41 @@ class UniComics : ParsedHttpSource() {
}
return Observable.just(
pages.flatMap { page ->
chapterListParse(client.newCall(chapterPageListRequest(manga, page)).execute())
chapterListParse(client.newCall(chapterPageListRequest(manga, page)).execute(), manga)
}.reversed()
)
}
private fun chapterPageListRequest(manga: SManga, page: Int): Request {
return GET("$baseDefaultUrl$PATH_URL${manga.url}/page/$page", headers)
return GET("$baseDefaultUrl${manga.url}/page/$page", headers)
}
override fun chapterListSelector() = "div.right_comics"
override fun chapterFromElement(element: Element): SChapter {
val urlElement = element.select(".button.online a").first()
private fun chapterListParse(response: Response, manga: SManga): List<SChapter> {
val document = response.asJsoup()
return document.select(chapterListSelector()).map { chapterFromElement(it, manga) }
}
private fun chapterFromElement(element: Element, manga: SManga): SChapter {
val urlElement = element.select("td:eq(1) a")
val chapter = SChapter.create()
element.select(".list_title").first().text().let {
if (it.contains("")) {
chapter.name = it.substringAfterLast(" ")
chapter.chapter_number = it.substringAfter("").toFloatOrNull() ?: -1f
} else {
chapter.name = "$it Сингл"
chapter.chapter_number = 0f
val titleNoPrefix = it.removePrefix(manga.title).removePrefix(":").trim()
chapter.name = if (titleNoPrefix.isNotEmpty())
titleNoPrefix.replaceFirst(titleNoPrefix.first(), titleNoPrefix.first().toUpperCase())
else
"Сингл"
if (titleNoPrefix.contains("")) {
chapter.chapter_number = titleNoPrefix.substringAfterLast("").toFloatOrNull() ?: -1f
}
}
chapter.setUrlWithoutDomain(urlElement.attr("href"))
return chapter
}
override fun chapterFromElement(element: Element) = throw UnsupportedOperationException("Not used")
override fun pageListRequest(chapter: SChapter): Request {
return GET(baseDefaultUrl + chapter.url, headers)
}
@ -218,13 +268,75 @@ class UniComics : ParsedHttpSource() {
}
}
override fun imageUrlParse(document: Document): String {
return document.select("#b_image").attr("src")
return document.select(".image_online").attr("src")
}
private class Publishers(publishers: Array<String>) : Filter.Select<String>("Издательства (только)", publishers)
override fun getFilterList() = FilterList(
Publishers(publishersName),
getEventsList()
)
private class getEventsList : Filter.Select<String>(
"События (только)",
arrayOf("Нет", "в комиксах")
)
private data class Publisher(val name: String, val url: String)
private fun getPublishersList() = listOf(
Publisher("Все", "not"),
Publisher("Marvel", "marvel"),
Publisher("DC Comics", "dc"),
Publisher("Image Comics", "imagecomics"),
Publisher("Dark Horse Comics", "dark-horse-comics"),
Publisher("IDW Publishing", "idw"),
Publisher("Vertigo", "vertigo"),
Publisher("WildStorm", "wildstorm"),
Publisher("Dynamite Entertainment", "dynamite"),
Publisher("Boom! Studios", "boomstudios"),
Publisher("Avatar Press", "avatarpress"),
Publisher("Fox Atomicg", "foxatomic"),
Publisher("Top Shelf Productions", "topshelfproduct"),
Publisher("Topps", "topps"),
Publisher("Radical Publishing", "radical-publishing"),
Publisher("Top Cow", "top-cow"),
Publisher("Zenescope Entertainment", "zenescope"),
Publisher("88MPH", "88mph"),
Publisher("Soleil", "soleil"),
Publisher("Warner Bros. Entertainment", "warner-bros"),
Publisher("Ubisoft Entertainment", "ubisoft"),
Publisher("Oni Press", "oni-press"),
Publisher("Armada", "delcourt"),
Publisher("Heavy Metal", "heavy-metal"),
Publisher("Harris Comics", "harris-comics"),
Publisher("Antarctic Press", "antarctic-press"),
Publisher("Valiant", "valiant"),
Publisher("Disney", "disney"),
Publisher("Malibu", "malibu"),
Publisher("Slave Labor", "slave-labor"),
Publisher("Nbm", "nbm"),
Publisher("Viper Comics", "viper-comics"),
Publisher("Random House", "random-house"),
Publisher("Active Images", "active-images"),
Publisher("Eurotica", "eurotica"),
Publisher("Vortex", "vortex"),
Publisher("Fantagraphics", "fantagraphics"),
Publisher("Epic", "epic"),
Publisher("Warp Graphics", "warp-graphics"),
Publisher("Scholastic Book Services", "scholastic-book-services"),
Publisher("Ballantine Books", "ballantine-books"),
Publisher("Id Software", "id-software")
)
private val publishersName = getPublishersList().map {
it.name
}.toTypedArray()
companion object {
const val PREFIX_SLUG_SEARCH = "slug:"
private const val PATH_URL = "/comics/series/"
private const val PATH_online = "/comics/online/"
private const val PATH_issue = "/comics/issue/"
private const val PATH_publishers = "/comics/publishers"
private const val PATH_events = "/comics/events"
}
}