Manga-Raw.club: Refactor (#11036)

Improved chapter title
Added alternative title in manga description
This commit is contained in:
Davide 2022-03-07 14:11:04 +01:00 committed by GitHub
parent 2b5359ca26
commit e50ade5026
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 93 additions and 164 deletions

View File

@ -5,7 +5,7 @@ ext {
extName = 'manga-raw.club'
pkgNameSuffix = 'en.mangarawclub'
extClass = '.MangaRawClub'
extVersionCode = 6
extVersionCode = 7
isNsfw = true
}

View File

@ -14,7 +14,6 @@ import okhttp3.FormBody
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import rx.Observable
@ -34,6 +33,10 @@ class MangaRawClub : ParsedHttpSource() {
.readTimeout(30, TimeUnit.SECONDS)
.build()
companion object {
const val altName = "Alternative Name: "
}
override fun popularMangaRequest(page: Int): Request {
return GET("$baseUrl/browse/?results=$page&filter=views", headers)
}
@ -42,60 +45,56 @@ class MangaRawClub : ParsedHttpSource() {
return GET("$baseUrl/listy/manga/?results=$page", headers)
}
override fun popularMangaSelector() = "ul.novel-list.grid.col.col2 > li"
override fun searchMangaSelector() = "ul.novel-list > li.novel-item"
override fun popularMangaSelector() = searchMangaSelector()
override fun latestUpdatesSelector() = searchMangaSelector()
// override fun popularMangaSelector() = "li.novel-item"
override fun latestUpdatesSelector() = popularMangaSelector()
override fun searchMangaSelector() = "ul.novel-list.grid.col.col1 > li"
override fun popularMangaFromElement(element: Element): SManga {
override fun searchMangaFromElement(element: Element): SManga {
val manga = SManga.create()
val coverElement = element.getElementsByClass("novel-cover").first()
var titleElement = element.getElementsByClass("novel-title text1row").first()
if (titleElement == null) {
titleElement = element.getElementsByClass("novel-title text2row").first()
}
manga.thumbnail_url = coverElement.select("img").attr("abs:data-src")
manga.title = element.select(".novel-title").first()?.text() ?: ""
manga.thumbnail_url = element.select(".novel-cover img").attr("abs:data-src")
manga.setUrlWithoutDomain(element.select("a").first().attr("href"))
manga.title = titleElement.text()
return manga
}
override fun popularMangaFromElement(element: Element): SManga = searchMangaFromElement(element)
override fun latestUpdatesFromElement(element: Element): SManga = searchMangaFromElement(element)
override fun latestUpdatesFromElement(element: Element): SManga =
popularMangaFromElement(element)
override fun searchMangaFromElement(element: Element): SManga = popularMangaFromElement(element)
override fun popularMangaNextPageSelector() = "ul.pagination > li:last-child > a"
override fun latestUpdatesNextPageSelector() = popularMangaNextPageSelector()
override fun searchMangaNextPageSelector() = popularMangaNextPageSelector()
override fun searchMangaNextPageSelector() = "ul.pagination > li:last-child > a"
override fun popularMangaNextPageSelector() = searchMangaNextPageSelector()
override fun latestUpdatesNextPageSelector() = searchMangaNextPageSelector()
override fun mangaDetailsParse(document: Document): SManga {
val manga = SManga.create()
val authorElement = document.getElementsByClass("author").first()
manga.author = authorElement.select("a").attr("title")
// manga.author = document.select("a[class=\"property-item\"]").first().attr("title")
manga.artist = ""
val author = document.select(".author a").first()?.attr("title") ?: ""
manga.author = if (author != "Updating") author else null
var description = document.select(".description").first()?.text() ?: ""
description = description.substringAfter("The Summary is").trim()
val otherTitle = document.select(".alternative-title").first()?.text() ?: ""
if (otherTitle != "Updating")
description += "\n\n$altName$otherTitle"
manga.description = description.trim()
val genres = mutableListOf<String>()
document.select("a[href*=genre]").forEach { element ->
val genre = element.attr("title")
document.select(".categories a[href*=genre]").forEach { element ->
val genre = element.attr("title").removeSuffix("Genre").trim()
genres.add(genre)
}
manga.genre = genres.joinToString(", ")
val status = when {
document.select("div.header-stats").select("strong.completed").first() != null -> SManga.COMPLETED
document.select("div.header-stats").select("strong.ongoing").first() != null -> SManga.ONGOING
val statusElement = document.select("div.header-stats")
manga.status = when {
statusElement.select("strong.completed").isNotEmpty() -> SManga.COMPLETED
statusElement.select("strong.ongoing").isNotEmpty() -> SManga.ONGOING
else -> SManga.UNKNOWN
}
manga.status = status
manga.description = document.getElementsByClass("description").first().text()
val coverElement = document.getElementsByClass("cover").select("img")
val coverUrl = when {
coverElement.attr("data-src").isNotBlank() -> coverElement.attr("data-src")
val coverElement = document.select(".cover img")
manga.thumbnail_url = when {
coverElement.attr("data-src").isNotEmpty() -> coverElement.attr("data-src")
else -> coverElement.attr("src")
}
manga.thumbnail_url = coverUrl
return manga
}
@ -107,120 +106,93 @@ class MangaRawClub : ParsedHttpSource() {
}
override fun chapterFromElement(element: Element): SChapter {
val anchor = element.select("a").first()
val chapter = SChapter.create()
chapter.setUrlWithoutDomain(anchor.attr("href"))
chapter.name = anchor.select(".chapter-title").first().text()
val date = anchor.select("time").first().attr("datetime")
chapter.date_upload = parseChapterDate(date)
chapter.setUrlWithoutDomain(element.select("a").attr("href"))
val name = element.select(".chapter-title").text().removeSuffix("-eng-li")
chapter.name = "Chapter $name"
val date = parseChapterDate(element.select(".chapter-update").attr("datetime"))
if (date != null)
chapter.date_upload = date
return chapter
}
private fun parseChapterDate(date: String): Long {
private fun parseChapterDate(date: String): Long? {
if (date.isEmpty())
return null
// "April 21, 2021, 4:05 p.m."
val fdate = date.replace(".", "").replace("Sept", "Sep")
val format = "MMMMM dd, yyyy, h:mm a"
val format2 = "MMMMM dd, yyyy, h a" // because sometimes if it is exact hour it wont have minutes because why not
val sdf = SimpleDateFormat(format, Locale.ENGLISH)
return try {
try {
val value = sdf.parse(fdate)
value!!.time
SimpleDateFormat("MMMMM dd, yyyy, h:mm a", Locale.ENGLISH).parse(fdate)!!.time
} catch (e: ParseException) {
val sdfF = SimpleDateFormat(format2, Locale.ENGLISH)
val value = sdfF.parse(fdate)
value!!.time
// because sometimes if it is exact hour it wont have minutes
SimpleDateFormat("MMMMM dd, yyyy, h a", Locale.ENGLISH).parse(fdate)!!.time
}
} catch (e: ParseException) {
0
null
}
}
override fun pageListParse(document: Document): List<Page> {
val pages = mutableListOf<Page>()
document.select("img[onerror][style=\"max-width: 100%;max-height: 100%;\"]").forEachIndexed { i, it ->
pages.add(Page(i, "", it.attr("src")))
document.select(".page-in img[onerror]").forEachIndexed { i, it ->
pages.add(Page(i, imageUrl = it.attr("src")))
}
if (!pages.any()) {
document.select("img[onerror]").forEachIndexed { i, it ->
pages.add(Page(i, "", it.attr("src")))
}
}
if (!pages.any()) {
document.select("article > div > center > img, section.page-in.content-wrap > div > center > img, section.page-in.content-wrap > center > div > center > img").forEachIndexed { i, it ->
pages.add(Page(i, "", it.attr("src")))
}
}
return pages
}
override fun imageUrlParse(document: Document) = ""
override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> {
val request = searchMangaRequest(page, query, filters)
return client.newCall(request).asObservableSuccess().map {
response ->
queryParse(response)
return client.newCall(request).asObservableSuccess().map { response ->
val mangas = mutableListOf<SManga>()
val document = response.asJsoup()
document.select(searchMangaSelector()).forEach { element ->
mangas.add(searchMangaFromElement(element))
}
val nextPage = document.select(searchMangaNextPageSelector()).isNotEmpty()
MangasPage(mangas, nextPage)
}
}
private fun queryParse(response: Response): MangasPage {
val mangas = mutableListOf<SManga>()
val document = response.asJsoup()
document.select(latestUpdatesSelector()).forEach { element ->
mangas.add(latestUpdatesFromElement(element))
}
val nextPage = document.select(latestUpdatesNextPageSelector()).first() != null
return MangasPage(mangas, nextPage)
}
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
if (query.isNotEmpty()) {
if (query.isNotEmpty()) // Query search
return GET("$baseUrl/search/?search=$query", headers)
}
// Filter search
val url = "$baseUrl/browse/".toHttpUrlOrNull()!!.newBuilder()
.addQueryParameter("results", page.toString())
val requestBody = FormBody.Builder()
url.addQueryParameter("results", page.toString())
filters.forEach { filter ->
when (filter) {
is GenreList -> {
val genreInclude = mutableListOf<String>()
filter.state.forEach {
if (it.state == 1) {
genreInclude.add(it.name)
}
}
if (genreInclude.isNotEmpty()) {
genreInclude.forEach { genre ->
requestBody.add("options[]", genre)
}
is GenrePairList -> url.addQueryParameter("genre", filter.toUriPart()) // GET
is Order -> url.addQueryParameter("filter", filter.toUriPart()) // GET
is Status -> requestBody.add("status", filter.toUriPart()) // POST
is Action -> requestBody.add("action", filter.toUriPart()) // POST
is GenreList -> { // POST
filter.state.filter { it.state == 1 }.forEach {
requestBody.add("options[]", it.name)
}
}
is GenrePairList -> url.addQueryParameter("genre", filter.toUriPart())
is Order -> url.addQueryParameter("filter", filter.toUriPart())
is Status -> requestBody.add("status", filter.toUriPart())
is Action -> requestBody.add("action", filter.toUriPart())
}
}
return GET(url.toString(), headers)
// val built = requestBody.build()
// return POST("$baseUrl/search", headers, requestBody.build())
// url: String,
// headers: Headers = DEFAULT_HEADERS,
// body: RequestBody = DEFAULT_BODY,
// cache: CacheControl = DEFAULT_CACHE_CONTROL)
// return GET(url.toString(), headers)
// return POST("$baseUrl/search", headers, requestBody.build()) // csrfmiddlewaretoken required
}
override fun getFilterList() = FilterList(
Filter.Header("NOTE: Ignored if using text search!"),
Filter.Separator(),
Order(),
GenrePairList(),
// Action(),
// Status(),
// GenreList(getGenreList())
)
private class Action : UriPartFilter(
"Action",
arrayOf(
@ -236,13 +208,10 @@ class MangaRawClub : ParsedHttpSource() {
Pair("Random", "Random"),
Pair("Updated", "Updated"),
Pair("New", "New"),
Pair("Views", "views"),
Pair("Views", "views")
)
)
private class Genre(name: String, val id: String = name) : Filter.TriState(name)
private class GenreList(genres: List<Genre>) : Filter.Group<Genre>("Genres", genres)
private class Status : UriPartFilter(
"Status",
arrayOf(
@ -272,6 +241,7 @@ class MangaRawClub : ParsedHttpSource() {
Pair("Horror", "Horror"),
Pair("Isekai", "Isekai"),
Pair("Josei", "Josei"),
Pair("Ladies", "ladies"),
Pair("Manhua", "Manhua"),
Pair("Manhwa", "Manhwa"),
Pair("Martial arts", "Martial arts"),
@ -291,59 +261,18 @@ class MangaRawClub : ParsedHttpSource() {
Pair("Sports", "Sports"),
Pair("Supernatural", "Supernatural"),
Pair("Tragedy", "Tragedy"),
Pair("Webtoons", "Webtoons"),
Pair("ladies", "ladies")
Pair("Webtoons", "Webtoons")
)
)
override fun getFilterList() = FilterList(
Filter.Header("NOTE: Ignored if using text search!"),
Filter.Separator(),
// Status(),
// Action(),
Order(),
GenrePairList(),
// GenreList(getGenreList())
)
private fun getGenreList(): List<Genre> {
return GenrePairList().vals.map {
Genre(it.first)
}
}
private fun getGenreList() = listOf(
Genre("Action"),
Genre("Adult"),
Genre("Adventure"),
Genre("Comedy"),
Genre("Cooking"),
Genre("Doujinshi"),
Genre("Drama"),
Genre("Ecchi"),
Genre("Fantasy"),
Genre("Gender bender"),
Genre("Harem"),
Genre("Historical"),
Genre("Horror"),
Genre("Isekai"),
Genre("Josei"),
Genre("Manhua"),
Genre("Manhwa"),
Genre("Martial arts"),
Genre("Mature"),
Genre("Mecha"),
Genre("Medical"),
Genre("Mystery"),
Genre("One shot"),
Genre("Psychological"),
Genre("Romance"),
Genre("School life"),
Genre("Sci fi"),
Genre("Seinen"),
Genre("Shoujo"),
Genre("Shounen"),
Genre("Slice of life"),
Genre("Sports"),
Genre("Supernatural"),
Genre("Tragedy"),
Genre("Webtoons"),
Genre("ladies")
)
private class Genre(name: String, id: String = name) : Filter.TriState(name)
private class GenreList(genres: List<Genre>) : Filter.Group<Genre>("Genres+", genres)
private open class UriPartFilter(displayName: String, val vals: Array<Pair<String, String>>) :
Filter.Select<String>(displayName, vals.map { it.first }.toTypedArray()) {