Skip to content

Commit 0764c67

Browse files
al-shamirygithub-actions[bot]
authored andcommitted
ReadAllComics: fix search & missing chapters (#13875)
* fix: popular page asks user to use search * fix: bug in searching titles * fix: comic description * chore: bump extVersionCode from 6 to 7 * fear: migrate from ParsedHttpSource to HttpSource * fix: proper server-side search pagination * fix: address pr review comments
1 parent f7fa6c5 commit 0764c67

File tree

2 files changed

+44
-91
lines changed

2 files changed

+44
-91
lines changed
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
ext {
22
extName = 'ReadAllComics'
33
extClass = '.ReadAllComics'
4-
extVersionCode = 6
4+
extVersionCode = 7
55
}
66

77
apply from: "$rootDir/common.gradle"
Lines changed: 43 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,24 @@
11
package eu.kanade.tachiyomi.extension.en.readallcomicscom
22

33
import eu.kanade.tachiyomi.network.GET
4-
import eu.kanade.tachiyomi.network.asObservableSuccess
54
import eu.kanade.tachiyomi.source.model.FilterList
65
import eu.kanade.tachiyomi.source.model.MangasPage
76
import eu.kanade.tachiyomi.source.model.Page
87
import eu.kanade.tachiyomi.source.model.SChapter
98
import eu.kanade.tachiyomi.source.model.SManga
10-
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
9+
import eu.kanade.tachiyomi.source.online.HttpSource
1110
import eu.kanade.tachiyomi.util.asJsoup
1211
import keiyoushi.utils.tryParse
1312
import okhttp3.HttpUrl.Companion.toHttpUrl
1413
import okhttp3.Request
1514
import okhttp3.Response
16-
import org.jsoup.nodes.Document
1715
import org.jsoup.nodes.Element
18-
import org.jsoup.select.Elements
1916
import rx.Observable
2017
import java.text.SimpleDateFormat
2118
import java.util.Locale
2219
import java.util.TimeZone
2320

24-
class ReadAllComics : ParsedHttpSource() {
21+
class ReadAllComics : HttpSource() {
2522

2623
override val name = "ReadAllComics"
2724

@@ -31,125 +28,81 @@ class ReadAllComics : ParsedHttpSource() {
3128

3229
override val supportsLatest = false
3330

34-
private lateinit var searchPageElements: Elements
35-
3631
override val client = network.cloudflareClient
3732

38-
override fun popularMangaRequest(page: Int): Request {
39-
val url = baseUrl.toHttpUrl().newBuilder().apply {
40-
addPathSegments("page/$page")
41-
}.build()
33+
// Popular
4234

43-
return GET(url, headers)
44-
}
35+
override fun fetchPopularManga(page: Int): Observable<MangasPage> = throw Exception("Use search to find comics.")
4536

46-
override fun popularMangaFromElement(element: Element): SManga {
47-
val manga = SManga.create().apply {
48-
val category = element.classNames()
49-
.firstOrNull { it.startsWith("category-") }!!
50-
.substringAfter("category-")
51-
setUrlWithoutDomain("/category/$category")
52-
title = category.replace("-", " ").titleCaseWords()
53-
thumbnail_url = element.selectFirst("img")?.attr("src")
54-
}
55-
56-
return manga
57-
}
37+
override fun popularMangaRequest(page: Int) = throw UnsupportedOperationException()
38+
override fun popularMangaParse(response: Response) = throw UnsupportedOperationException()
5839

59-
override fun popularMangaSelector() = "#post-area > div"
60-
override fun popularMangaNextPageSelector() = "a.page-numbers.next"
61-
62-
override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> = if (page == 1) {
63-
client.newCall(searchMangaRequest(page, query, filters))
64-
.asObservableSuccess()
65-
.map { searchMangaParse(it) }
66-
} else {
67-
Observable.just(searchPageParse(page))
68-
}
40+
// Search
6941

7042
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
7143
val url = baseUrl.toHttpUrl().newBuilder().apply {
7244
addQueryParameter("story", query)
7345
addQueryParameter("s", "")
7446
addQueryParameter("type", "comic")
47+
if (page > 1) addQueryParameter("paged", page.toString())
7548
}.build()
7649

7750
return GET(url, headers)
7851
}
7952

8053
override fun searchMangaParse(response: Response): MangasPage {
81-
searchPageElements = response.asJsoup().select(searchMangaSelector())
82-
83-
return searchPageParse(1)
54+
val document = response.asJsoup()
55+
val mangas = document.select("ul.list-story.categories li").map { mangaFromElement(it) }
56+
val hasNextPage = document.selectFirst("a.next") != null
57+
return MangasPage(mangas, hasNextPage)
8458
}
8559

86-
private fun searchPageParse(page: Int): MangasPage {
87-
val mangas = mutableListOf<SManga>()
88-
val endRange = ((page * 24) - 1).let { if (it <= searchPageElements.lastIndex) it else searchPageElements.lastIndex }
60+
private fun mangaFromElement(element: Element) = SManga.create().apply {
61+
val titleAnchor = element.selectFirst("a.cat-title")!!
62+
setUrlWithoutDomain(titleAnchor.attr("abs:href"))
63+
title = titleAnchor.text()
64+
thumbnail_url = element.selectFirst("img.book-cover")?.attr("abs:src")
65+
}
8966

90-
for (i in (((page - 1) * 24)..endRange)) {
91-
mangas.add(
92-
searchMangaFromElement(searchPageElements[i]),
93-
)
94-
}
67+
// Manga details
9568

96-
return MangasPage(mangas, endRange < searchPageElements.lastIndex)
69+
override fun mangaDetailsParse(response: Response) = SManga.create().apply {
70+
val archive = response.asJsoup().selectFirst(".description-archive")!!
71+
title = archive.selectFirst("h1")!!.text()
72+
thumbnail_url = archive.selectFirst("p img")?.attr("abs:src")
73+
val infoStrongs = archive.select(".b > p strong")
74+
genre = infoStrongs.firstOrNull()?.text()
75+
author = infoStrongs.lastOrNull()?.text()
76+
description = archive.selectFirst("#hidden-description")?.wholeText()?.trim()
9777
}
9878

99-
override fun searchMangaFromElement(element: Element) = SManga.create().apply {
100-
setUrlWithoutDomain(element.attr("href"))
101-
title = element.text()
102-
thumbnail_url = ""
103-
}
79+
// Chapters
10480

105-
override fun searchMangaSelector() = ".categories a"
106-
override fun searchMangaNextPageSelector() = null
107-
108-
override fun mangaDetailsParse(document: Document) = SManga.create().apply {
109-
title = document.selectFirst("h1")!!.text()
110-
genre = document.select("p strong").joinToString { it.text() }
111-
author = document.select("p > strong").last()?.text()
112-
description = buildString {
113-
document.select(".b > strong").forEach { element ->
114-
val vol = element.previousElementSibling()
115-
if (isNotBlank()) {
116-
append("\n\n")
117-
}
118-
if (vol?.tagName() == "span") {
119-
append(vol.text(), "\n")
120-
}
121-
append(element.text())
122-
}
81+
override fun chapterListParse(response: Response): List<SChapter> = response.asJsoup().select(".list-story a").map { element ->
82+
SChapter.create().apply {
83+
setUrlWithoutDomain(element.attr("abs:href"))
84+
name = element.text()
85+
val year = name.substringAfterLast('(').substringBefore(')')
86+
date_upload = dateFormat.tryParse("$year-1-1")
12387
}
124-
thumbnail_url = document.select("p img").attr("abs:src")
12588
}
12689

127-
override fun chapterListSelector() = ".list-story a"
90+
// Pages
12891

129-
override fun chapterFromElement(element: Element) = SChapter.create().apply {
130-
setUrlWithoutDomain(element.attr("href"))
131-
name = element.text()
132-
// can only get the year from chapter title
133-
val year = name.substringAfterLast('(').substringBefore(')')
134-
date_upload = dateFormat.tryParse("$year-1-1")
92+
override fun pageListParse(response: Response): List<Page> = response.asJsoup().select("body img:not(div[id=logo] img)").mapIndexed { idx, element ->
93+
Page(idx, imageUrl = element.attr("abs:src"))
13594
}
13695

137-
override fun pageListParse(document: Document): List<Page> = document.select("body img:not(body div[id=\"logo\"] img)").mapIndexed { idx, element ->
138-
Page(idx, "", element.attr("abs:src"))
139-
}
96+
override fun imageUrlParse(response: Response) = throw UnsupportedOperationException()
14097

141-
private fun String.titleCaseWords(): String {
142-
val words = this.split(" ")
143-
return words.joinToString(" ") { word -> word.replaceFirstChar { it.titlecase() } }
144-
}
98+
// Latest (unsupported)
14599

146-
override fun imageUrlParse(document: Document) = throw UnsupportedOperationException()
147100
override fun latestUpdatesRequest(page: Int) = throw UnsupportedOperationException()
148-
override fun latestUpdatesFromElement(element: Element) = throw UnsupportedOperationException()
149-
override fun latestUpdatesSelector() = throw UnsupportedOperationException()
150-
override fun latestUpdatesNextPageSelector() = throw UnsupportedOperationException()
101+
override fun latestUpdatesParse(response: Response) = throw UnsupportedOperationException()
151102

152103
companion object {
153-
val dateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.US).apply { timeZone = TimeZone.getTimeZone("UTC") }
104+
val dateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.US).apply {
105+
timeZone = TimeZone.getTimeZone("UTC")
106+
}
154107
}
155108
}

0 commit comments

Comments
 (0)