fixed all issues regarding #10040 (#10042)

This commit is contained in:
THE_ORONCO 2021-12-09 11:44:16 +01:00 committed by GitHub
parent bd43b9f982
commit ef491c08ea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 162 additions and 101 deletions

View File

@ -5,7 +5,7 @@ ext {
extName = 'Kill Six Billion Demons'
pkgNameSuffix = 'en.killsixbilliondemons'
extClass = '.KillSixBillionDemons'
extVersionCode = 3
extVersionCode = 4
}
apply from: "$rootDir/common.gradle"

View File

@ -1,7 +1,6 @@
package eu.kanade.tachiyomi.extension.en.killsixbilliondemons
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.asObservableSuccess
import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.source.model.MangasPage
import eu.kanade.tachiyomi.source.model.Page
@ -11,12 +10,15 @@ import eu.kanade.tachiyomi.source.online.HttpSource
import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.Request
import okhttp3.Response
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import rx.Observable
import java.text.SimpleDateFormat
import java.util.Locale
/**
* original creator:
* @author Aria Moradi <aria.moradi007@gmail.com>
* fixed some bugs and added title pages:
* @author THE_ORONCO <the_oronco@posteo.net>
*/
class KillSixBillionDemons : HttpSource() {
@ -29,138 +31,197 @@ class KillSixBillionDemons : HttpSource() {
override val supportsLatest: Boolean = false
// list of books
override fun popularMangaParse(response: Response): MangasPage {
val document = response.asJsoup()
val mangas = document.select(popularMangaSelector()).map { element ->
popularMangaFromElement(element)
}
return MangasPage(mangas, false)
}
private val authorKSBD = "Abbadon"
private val bookSelector: String = "#chapter option:contains(book)"
private val pagesOrder = "?order=ASC"
private val urlDateFormat = SimpleDateFormat("yyyy/MM", Locale.US)
private val descriptionKSBD =
"Q: What is this all about?\nThis is a webcomic! Its graphic novel style, meaning its meant to be read in large chunks, but you can subject yourself to the agony of reading it a couple pages a week!\n" +
"\nQ: Do you have a twitter/tumble machine? Just who the hell draws this thing anyway?\n" +
"A mysterious comics goblin named Abbadon draws this mess. My twitter is @orbitaldropkick, my tumblr is orbitaldropkick.tumblr.com. If youre feeling dangerous, you can e-mail me at ksbdabbadon@gmail.com\n" +
"\nQ: A webcomic, eh? When does it update?\n" +
"Tuesday and Friday evenings (and occasionally weekends). Sometimes it will be up quite late on those days.\n" +
"\nQ: Whos this YISUN guy that keeps getting talked about?\n" +
"Someone has not read their Psalms and Spasms recently!\n" +
"\nQ: Whats this about suggestions?\n" +
"KSBD will periodically take suggestions, mostly on characters to stick in the background. You can also stick fanart, character ideas, concepts, and literature in the Submit section up above. You need tumblr for this. If you want to suggest directly, the best way to do it is through the comments section below the comic! A huge chunk of minor characters have been named and inspired by reader comments so far.\n" +
"\nQ: Can I buy this book in a more traditional format?\n" +
"You absolutely can. You can get your hands on a print copy of the first and second books from Image comics in your local comics shop or anywhere else you can get comics. It looks fantastic in print and if you dont like reading stuff online I highly recommend it."
override fun popularMangaRequest(page: Int): Request {
return GET(baseUrl)
return GET(baseUrl, headers)
}
private fun popularMangaSelector(): String {
return "#chapter option:contains(book)"
// list of books
override fun popularMangaParse(response: Response): MangasPage {
return generateKSBDMangasPage()
}
private fun popularMangaFromElement(element: Element): SManga {
return SManga.create().apply {
title = element.text().substringBefore(" (")
thumbnail_url = "https://dummyimage.com/768x994/000/ffffff.jpg&text=$title"
artist = "Abbadon"
author = "Abbadon"
status = SManga.UNKNOWN
url = title // this url is not useful at all but must set to something unique or the app breaks!
/**
* @return the MangasPage containing the different books of Kill Six Billion Demons as manga
*/
private fun generateKSBDMangasPage(): MangasPage {
return MangasPage(fetchBooksAsMangas(), false)
}
/**
* This fetches the different books of Kill Six Billion Demons as different manga.
* @return a list of all books in form of multiple manga
*/
private fun fetchBooksAsMangas(): List<SManga> {
val doc = client.newCall(GET(baseUrl, headers)).execute().asJsoup()
val bookElements = doc.select(bookSelector)
return bookElements.map { bookElement ->
val bookOverviewUrl = bookElement.attr("value")
val bookTitle = bookElement.text().substringBefore(" (")
SManga.create().apply {
title = bookTitle
setUrlWithoutDomain(bookOverviewUrl)
artist = authorKSBD
author = authorKSBD
description = descriptionKSBD
thumbnail_url = fetchThumbnailUrl(bookOverviewUrl)
status = fetchStatusForBook(bookTitle)
}
}
}
/**
* This fetches the Thumbnail given the url to a book overview. In ascending order the first
* image will always be the cover of the given book.
*
* @param bookOverviewUrl url to the book overview
* @return url to the cover of the book
*/
private fun fetchThumbnailUrl(bookOverviewUrl: String): String {
val overviewDoc =
client.newCall(GET(bookOverviewUrl + pagesOrder, headers)).execute().asJsoup()
return overviewDoc.selectFirst(".comic-thumbnail-in-archive a img").attr("src")
}
private fun String.lowercase(): String {
return this.toLowerCase(Locale.ROOT)
}
/**
* Get the SManga status for a given book by checking if the title of the newest page contains
* the title of the the given book.
*
* @param bookTitle name of the book the status should be fetched for
* @return the status of the book (as Enum value of SManga because chapters are mangas)
*/
private fun fetchStatusForBook(bookTitle: String): Int {
val bookTitleWithoutBook = bookTitle.substringAfter(": ")
val newestPage = client.newCall(GET(baseUrl, headers)).execute().asJsoup()
val postTitle = newestPage.selectFirst(".post-title")?.text() ?: ""
// title is "<book name> <page(s)>"
return if (postTitle.lowercase().contains(bookTitleWithoutBook.lowercase())) SManga.UNKNOWN
else SManga.COMPLETED
}
// latest Updates not used
override fun latestUpdatesParse(response: Response): MangasPage = throw Exception("Not used")
override fun latestUpdatesRequest(page: Int): Request = throw Exception("Not used")
// books dont change around here, but still write the data again to avoid bugs in backup restore
override fun fetchMangaDetails(manga: SManga): Observable<SManga> {
return client.newCall(popularMangaRequest(1))
.asObservableSuccess()
.map { response ->
popularMangaParse(response).mangas.find { manga.title == it.title }
}
return Observable.just(fetchBooksAsMangas().find { manga.title == it.title })
}
override fun mangaDetailsParse(response: Response): SManga = throw Exception("Not used")
override fun fetchChapterList(manga: SManga): Observable<List<SChapter>> {
return client.newCall(chapterListRequest(manga))
.asObservableSuccess()
.map { response ->
chapterListParse(response, manga)
}
return Observable.just(
fetchChapterListTR(
baseUrl + manga.url + pagesOrder,
mutableListOf()
)
)
}
override fun chapterListRequest(manga: SManga): Request = popularMangaRequest(1)
/**
* Though this is recursive this will be optimized by the compiler into a for loop equivalent
* thing. This has to be done this way because the maximum number of further chapter overview
* pages that will be shown on one chapter overview page will at maximum be 5 enven though there
* might be more.
*
* @param currentUrl url of the current page / the page this algorithm will start the recursion on
* @param foundChapters a list of all found chapters (should be empty)
* @return a list of all chapters that were found under "currentUrl" and following pages
*/
private tailrec fun fetchChapterListTR(
currentUrl: String,
foundChapters: MutableList<SChapter>
): MutableList<SChapter> {
val numberOfPreviousChapters = foundChapters.size
val currentPage = client.newCall(GET(currentUrl, headers)).execute().asJsoup()
val chaptersOnCurrentPage = currentPage.select(".post-content")
.mapIndexed { index, chapterElement ->
val chapterTitle: String = chapterElement.select(".post-title a").text()
val chapterUrl: String =
chapterElement.select(".comic-thumbnail-in-archive a").attr("href")
val imageUrl =
chapterElement.select(".comic-thumbnail-in-archive a img").attr("src")
SChapter.create().apply {
setUrlWithoutDomain(chapterUrl)
name = chapterTitle
chapter_number = numberOfPreviousChapters + index + 1f
date_upload = extractDateFromImageUrl(imageUrl)
}
}
foundChapters.addAll(chaptersOnCurrentPage)
val potentialNextPageUrl = currentPage.select(".paginav-next a").attr("href")
return if (potentialNextPageUrl.isEmpty()) {
foundChapters
} else {
fetchChapterListTR(potentialNextPageUrl, foundChapters)
}
}
/**
* @param imageUrl Url the date should be got from
* @return date of the image upload as a long
*/
private fun extractDateFromImageUrl(imageUrl: String): Long {
val dateRegex = "[0-9]{4}/[0-9]{2}".toRegex()
val dateString = dateRegex.find(imageUrl)
return if (dateString?.value != null) {
return urlDateFormat.parse(dateString.value)?.time ?: 0L
} else 0L
}
override fun chapterListRequest(manga: SManga): Request = throw Exception("Not used")
override fun chapterListParse(response: Response): List<SChapter> = throw Exception("Not used")
private fun chapterListParse(response: Response, manga: SManga): List<SChapter> {
val document = response.asJsoup()
val options = document.select(chapterListSelector())
val chapters = mutableListOf<SChapter>()
var bookNum = 0
val targetBookNum = manga.title.split(":")[0].split(" ")[1].toInt()
for (element in options) {
val text = element.text()
if (text.startsWith("Book")) {
bookNum += 1
continue
}
if (bookNum > targetBookNum)
break
if (bookNum == targetBookNum) {
chapters.add(
SChapter.create().apply {
url = element.attr("value")
val textSplit = text.split(" ")
name = "Chapter ${textSplit[0]}"
}
)
}
}
return chapters.reversed()
}
private fun chapterListSelector(): String {
return "#chapter option"
}
override fun fetchPageList(chapter: SChapter): Observable<List<Page>> {
val wordpressPages = mutableListOf<Document>()
// get the first page and add ir to the list
val firstPageURL = chapter.url + "?order=ASC" // change the url to ask Wordpress to reverse the posts
val firstPage = client.newCall(GET(firstPageURL)).execute().asJsoup()
wordpressPages.add(firstPage)
val otherPages = firstPage.select("#paginav a")
for (i in 0 until (otherPages.size - 1)) // ignore the last one (last page button)
wordpressPages.add(client.newCall(GET(otherPages[i].attr("href"))).execute().asJsoup())
val chapterPages = mutableListOf<Page>()
var pageNum = 1
wordpressPages.forEach { wordpressPage ->
wordpressPage.select(".post-content .entry a:has(img)").forEach { postImage ->
chapterPages.add(
Page(pageNum, postImage.attr("href"), postImage.select("img").attr("src"))
)
pageNum++
val chapterDoc = client.newCall(GET(baseUrl + chapter.url, headers)).execute().asJsoup()
val pages = chapterDoc.select("#comic img")
.mapIndexed { index, imageElement ->
val imageUrl = imageElement.attr("src")
Page(index + 1, "", imageUrl)
}
}
return Observable.just(chapterPages)
return Observable.just(pages)
}
override fun imageUrlParse(response: Response): String = throw Exception("Not used")
override fun pageListParse(response: Response): List<Page> = throw Exception("Not used")
override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> = throw Exception("Search functionality is not available.")
override fun fetchSearchManga(
page: Int,
query: String,
filters: FilterList
): Observable<MangasPage> = throw Exception("Search functionality is not available.")
override fun searchMangaParse(response: Response): MangasPage = throw Exception("Not used")
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request = throw Exception("Not used")
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request =
throw Exception("Not used")
}