From 30cb878aa0a3be09c8a9b4e2c8da18b86fcf56d6 Mon Sep 17 00:00:00 2001 From: Mike <51273546+SnakeDoc83@users.noreply.github.com> Date: Sat, 29 Jun 2019 10:55:15 -0400 Subject: [PATCH] PsychoPlay update (#1242) PsychoPlay update --- src/en/psychoplay/build.gradle | 2 +- .../extension/en/psychoplay/PsychoPlay.kt | 123 +++++++++++++----- 2 files changed, 90 insertions(+), 35 deletions(-) diff --git a/src/en/psychoplay/build.gradle b/src/en/psychoplay/build.gradle index ee327708a..835d10da9 100644 --- a/src/en/psychoplay/build.gradle +++ b/src/en/psychoplay/build.gradle @@ -5,7 +5,7 @@ ext { appName = 'Tachiyomi: PsychoPlay' pkgNameSuffix = 'en.psychoplay' extClass = '.PsychoPlay' - extVersionCode = 2 + extVersionCode = 3 libVersion = '1.2' } diff --git a/src/en/psychoplay/src/eu/kanade/tachiyomi/extension/en/psychoplay/PsychoPlay.kt b/src/en/psychoplay/src/eu/kanade/tachiyomi/extension/en/psychoplay/PsychoPlay.kt index ee89fcf3a..5c3ba9099 100644 --- a/src/en/psychoplay/src/eu/kanade/tachiyomi/extension/en/psychoplay/PsychoPlay.kt +++ b/src/en/psychoplay/src/eu/kanade/tachiyomi/extension/en/psychoplay/PsychoPlay.kt @@ -3,10 +3,13 @@ package eu.kanade.tachiyomi.extension.en.psychoplay import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.source.model.* import eu.kanade.tachiyomi.source.online.ParsedHttpSource +import eu.kanade.tachiyomi.util.asJsoup import okhttp3.OkHttpClient import okhttp3.Request +import okhttp3.Response import org.jsoup.nodes.Document import org.jsoup.nodes.Element +import org.jsoup.select.Elements import java.text.SimpleDateFormat import java.util.* @@ -22,10 +25,11 @@ class PsychoPlay : ParsedHttpSource() { override val client: OkHttpClient = network.cloudflareClient - override fun popularMangaSelector() = "div.thumbnail" + override fun popularMangaSelector() = "div.list-item" + private val popularMangaUrl = "$baseUrl/comics?page=" override fun popularMangaRequest(page: Int): Request { - return GET("$baseUrl/series?page=$page") + return GET("$popularMangaUrl$page") } override fun latestUpdatesSelector() = popularMangaSelector() @@ -36,51 +40,101 @@ class PsychoPlay : ParsedHttpSource() { override fun popularMangaFromElement(element: Element): SManga { val manga = SManga.create() - element.select("h6 a").first().let { + element.select("a.list-title").first().let { manga.setUrlWithoutDomain(it.attr("href")) manga.title = it.text() } - manga.thumbnail_url = baseUrl + element.select("img").first().attr("src") + manga.thumbnail_url = element.select("a.media-content").first().attr("style").substringAfter("(").substringBefore(")") return manga } override fun latestUpdatesFromElement(element: Element): SManga = popularMangaFromElement(element) - override fun popularMangaNextPageSelector() = ":containsOwn(next):not([href=\"\"])" + override fun popularMangaNextPageSelector() = "[rel=next]" override fun latestUpdatesNextPageSelector() = popularMangaNextPageSelector() + // Didn't see a search function on PsychoPlay's website when I updated this extension; so searching locally + private var searchQuery = "" + private var searchPage = 1 + private var nextPageSelectorElement = Elements() + override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { - val url = "$baseUrl/series?q=$query" - return GET(url, headers) + if (page == 1) searchPage = 1 + searchQuery = query.toLowerCase() + return GET("$popularMangaUrl$page") } - override fun searchMangaSelector() = "div.thumbnail" + override fun searchMangaParse(response: Response): MangasPage { + val searchMatches = mutableListOf<SManga>() + val document = response.asJsoup() + searchMatches.addAll(getMatchesFrom(document)) + + /* call another function if there's more pages to search + not doing it this way can lead to a false "no results found" + if no matches are found on the first page but there are matches + on subsequent pages */ + nextPageSelectorElement = document.select(searchMangaNextPageSelector()) + while (nextPageSelectorElement.hasText()) { + searchMatches.addAll(searchMorePages()) + } + + return MangasPage(searchMatches, false) + } + + // search the given document for matches + private fun getMatchesFrom(document: Document): MutableList<SManga> { + val searchMatches = mutableListOf<SManga>() + document.select(searchMangaSelector()).forEach { + if (it.text().toLowerCase().contains(searchQuery)) { + searchMatches.add(searchMangaFromElement(it)) + } + } + return searchMatches + } + + // search additional pages if called + private fun searchMorePages(): MutableList<SManga> { + searchPage++ + val nextPage = client.newCall(GET("$popularMangaUrl$searchPage", headers)).execute().asJsoup() + val searchMatches = mutableListOf<SManga>() + searchMatches.addAll(getMatchesFrom(nextPage)) + nextPageSelectorElement = nextPage.select(searchMangaNextPageSelector()) + + return searchMatches + } + + override fun searchMangaSelector() = popularMangaSelector() override fun searchMangaFromElement(element: Element) = popularMangaFromElement(element) override fun searchMangaNextPageSelector() = popularMangaNextPageSelector() override fun mangaDetailsParse(document: Document): SManga { - val infoElement = document.select("div.row").first() + val infoElement = document.select("div#content").first() val manga = SManga.create() - manga.title = infoElement.select("h2").first().text() + manga.title = infoElement.select("h5").first().text() - manga.description = document.select("div.panel-body").text().substringAfter("Synopsis ") - manga.thumbnail_url = baseUrl + document.select("div.media-left a").first().select("img").first().attr("src") + manga.description = document.select("div.col-lg-9").text().substringAfter("Description ").substringBefore(" Volume") + manga.thumbnail_url = document.select("div.media a").first().attr("style").substringAfter("(").substringBefore(")") return manga } - override fun chapterListSelector() = "li.media" + override fun chapterListSelector() = "div.col-lg-9 div.flex" override fun chapterFromElement(element: Element): SChapter { - val urlElement = element.select("a").first() + val urlElement = element.select("a.item-author") + val chapNum = urlElement.attr("href").split("/").last() val chapter = SChapter.create() chapter.setUrlWithoutDomain(urlElement.attr("href")) - chapter.name = urlElement.text().substringBefore("Added") - chapter.date_upload = parseChapterDate(urlElement.text().substringAfter("Added ")) ?: 0 + if (urlElement.text().contains("Chapter $chapNum")) { + chapter.name = urlElement.text() + } else { + chapter.name = "Ch. " + chapNum + ": " + urlElement.text() + } + chapter.date_upload = parseChapterDate(element.select("a.item-company").first().text()) ?: 0 return chapter } @@ -90,32 +144,28 @@ class PsychoPlay : ParsedHttpSource() { } } - // If the date string contains the word "on" simply dateformat it, otherwise send it off to parse relatively + // If the date string contains the word "ago" send it off for relative date parsing otherwise use dateFormat private fun parseChapterDate(string: String): Long? { - if ("on " in string) { - return dateFormat.parse(string.substringAfter("on ")).time - } else { + if ("ago" in string) { return parseRelativeDate(string) ?: 0 + } else { + return dateFormat.parse(string).time } } // Subtract relative date (e.g. posted 3 days ago) private fun parseRelativeDate(date: String): Long? { - var trimmedDate = date.substringBefore(" ago").replace(",", " ").split(" ") + val trimmedDate = date.substringBefore(" ago").split(" ") val calendar = Calendar.getInstance() - var numIndex = -1 - trimmedDate.forEach { - when (it){ - "month", "months" -> calendar.apply{add(Calendar.MONTH, -trimmedDate.get(numIndex).toInt())} - "week", "weeks" -> calendar.apply{add(Calendar.WEEK_OF_MONTH, -trimmedDate.get(numIndex).toInt())} - "day", "days" -> calendar.apply{add(Calendar.DAY_OF_MONTH, -trimmedDate.get(numIndex).toInt())} - "hour", "hours" -> calendar.apply{add(Calendar.HOUR_OF_DAY, -trimmedDate.get(numIndex).toInt())} - "minute", "minutes" -> calendar.apply{add(Calendar.MONTH, -trimmedDate.get(numIndex).toInt())} + when (trimmedDate[1]){ + "month", "months" -> calendar.apply{add(Calendar.MONTH, -trimmedDate[0].toInt())} + "week", "weeks" -> calendar.apply{add(Calendar.WEEK_OF_MONTH, -trimmedDate[0].toInt())} + "day", "days" -> calendar.apply{add(Calendar.DAY_OF_MONTH, -trimmedDate[0].toInt())} + "hour", "hours" -> calendar.apply{add(Calendar.HOUR_OF_DAY, -trimmedDate[0].toInt())} + "minute", "minutes" -> calendar.apply{add(Calendar.MONTH, -trimmedDate[0].toInt())} "second", "seconds" -> calendar.apply{add(Calendar.SECOND, 0)} } - numIndex++ - } return calendar.timeInMillis } @@ -123,14 +173,19 @@ class PsychoPlay : ParsedHttpSource() { override fun pageListParse(document: Document): List<Page> { val pages = mutableListOf<Page>() - document.select("div.row img")?.forEach { - pages.add(Page(pages.size, "", it.attr("src"))) + val allImages = document.select("script").first().data() + .substringAfter("[").substringBefore("];") + .replace(Regex("""["\\]"""), "") + .split(",") + + for (i in 0 until allImages.size) { + pages.add(Page(i, "", allImages[i])) } return pages } - override fun imageUrlParse(document: Document): String = throw UnsupportedOperationException("No used") + override fun imageUrlParse(document: Document): String = throw UnsupportedOperationException("Not used") override fun getFilterList() = FilterList()