From e4af261b5a1ee14756f370d2f1ea1e963917c8a8 Mon Sep 17 00:00:00 2001 From: Mike <51273546+SnakeDoc83@users.noreply.github.com> Date: Thu, 27 Aug 2020 23:21:10 -0400 Subject: [PATCH] RisensTeam - update for their new API (#4233) --- src/ru/risensteam/build.gradle | 2 +- .../extension/ru/risensteam/RisensTeam.kt | 187 +++++++++--------- 2 files changed, 95 insertions(+), 94 deletions(-) diff --git a/src/ru/risensteam/build.gradle b/src/ru/risensteam/build.gradle index 4eafc7ae1..91eda1f4e 100644 --- a/src/ru/risensteam/build.gradle +++ b/src/ru/risensteam/build.gradle @@ -5,7 +5,7 @@ ext { extName = 'Risens Team' pkgNameSuffix = 'ru.risensteam' extClass = '.RisensTeam' - extVersionCode = 1 + extVersionCode = 2 libVersion = '1.2' } diff --git a/src/ru/risensteam/src/eu/kanade/tachiyomi/extension/ru/risensteam/RisensTeam.kt b/src/ru/risensteam/src/eu/kanade/tachiyomi/extension/ru/risensteam/RisensTeam.kt index 650d93960..877dabdeb 100644 --- a/src/ru/risensteam/src/eu/kanade/tachiyomi/extension/ru/risensteam/RisensTeam.kt +++ b/src/ru/risensteam/src/eu/kanade/tachiyomi/extension/ru/risensteam/RisensTeam.kt @@ -1,27 +1,33 @@ package eu.kanade.tachiyomi.extension.ru.risensteam import com.github.salomonbrys.kotson.fromJson +import com.github.salomonbrys.kotson.get import com.github.salomonbrys.kotson.int +import com.github.salomonbrys.kotson.nullString import com.github.salomonbrys.kotson.string import com.google.gson.Gson +import com.google.gson.JsonArray +import com.google.gson.JsonElement import com.google.gson.JsonObject import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.POST +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 import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SManga -import eu.kanade.tachiyomi.source.online.ParsedHttpSource -import eu.kanade.tachiyomi.util.asJsoup -import okhttp3.MultipartBody +import eu.kanade.tachiyomi.source.online.HttpSource +import java.text.ParseException +import java.text.SimpleDateFormat +import java.util.Locale +import okhttp3.MediaType import okhttp3.Request import okhttp3.RequestBody import okhttp3.Response -import org.jsoup.nodes.Document -import org.jsoup.nodes.Element +import rx.Observable -class RisensTeam : ParsedHttpSource() { - override fun pageListParse(document: Document): List = throw Exception("Not Used") +class RisensTeam : HttpSource() { override val name = "Risens Team" @@ -31,111 +37,106 @@ class RisensTeam : ParsedHttpSource() { override val supportsLatest = false + override val versionId: Int = 2 + private val gson by lazy { Gson() } - override fun popularMangaRequest(page: Int): Request = - GET("$baseUrl/manga/page/$page/", headers) + // Popular (source only returns manga sorted by latest) + + override fun popularMangaRequest(page: Int): Request { + return GET("https://risens.team/api/title/list?type=1", headers) + } + + private fun mangaFromJson(json: JsonElement): SManga { + return SManga.create().apply { + url = "${json["id"].int}/${json["furl"].string}" + title = json["title"].string + thumbnail_url = baseUrl + json["poster"].string + description = json["description"].nullString + status = try { if (json["active"].int == 1) SManga.ONGOING else SManga.UNKNOWN } catch (_: Exception) { SManga.UNKNOWN } + } + } + + override fun popularMangaParse(response: Response): MangasPage { + val mangas = gson.fromJson(response.body()!!.string()) + .map { json -> mangaFromJson(json) } + + return MangasPage(mangas, false) + } + + // Latest + + override fun latestUpdatesRequest(page: Int): Request = throw UnsupportedOperationException("Not used") + override fun latestUpdatesParse(response: Response): MangasPage = throw UnsupportedOperationException("Not used") + + // Search override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { - return POST(baseUrl, headers, buildRequestBody(query, page)) + val rbody = RequestBody.create(MediaType.parse("application/json;charset=utf-8"), """{"queryString":"$query","limit":3}""") + return POST("$baseUrl/api/title/search", headers, rbody) } - private fun buildRequestBody(query: String, page: Int): RequestBody { - return MultipartBody.Builder() - .setType(MultipartBody.FORM) - .addFormDataPart("do", "search") - .addFormDataPart("subaction", "search") - .addFormDataPart("story", query) - .addFormDataPart("catlist[]", "33") - .addFormDataPart("search_start", (page - 1).toString()) - .build() + override fun searchMangaParse(response: Response): MangasPage = popularMangaParse(response) + + // Details + + override fun fetchMangaDetails(manga: SManga): Observable { + return client.newCall(apiMangaDetailsRequest(manga)) + .asObservableSuccess() + .map { response -> + mangaDetailsParse(response).apply { initialized = true } + } } - override fun popularMangaSelector() = ".mb-2:not([align])" - - override fun searchMangaSelector() = ".card.h-100" - - override fun popularMangaFromElement(element: Element): SManga { - val manga = SManga.create() - val coverElem = element.select(".card-img-top").first() - val imgUrl = coverElem.attr("src") - manga.thumbnail_url = baseUrl + if (imgUrl.contains("/pagespeed_static/")) coverElem.attr("data-pagespeed-lazy-src") else imgUrl - manga.setUrlWithoutDomain(element.select("b-link").first().attr("to")) - manga.title = coverElem.attr("alt").split('/').first().replace("(Манга)", "").trim() - - return manga + private fun apiMangaDetailsRequest(manga: SManga): Request { + return GET("$baseUrl/api/title/show/${manga.url.substringBefore("/")}") } - override fun searchMangaFromElement(element: Element): SManga { - val manga = SManga.create() - val coverElem = element.select(".card-img-top").first() - manga.thumbnail_url = coverElem.attr("src") - manga.setUrlWithoutDomain(coverElem.parent().attr("href")) - manga.title = coverElem.attr("alt").split('/').first().replace("(Манга)", "").trim() - - return manga + override fun mangaDetailsRequest(manga: SManga): Request { + return GET("$baseUrl/title/${manga.url}") } - override fun popularMangaNextPageSelector() = "b-list-group-item.next > a" - - override fun searchMangaNextPageSelector() = popularMangaNextPageSelector() - - override fun mangaDetailsParse(document: Document): SManga { - val manga = SManga.create() - manga.thumbnail_url = baseUrl + document.select("b-img[fluid]").first().attr("src") - manga.genre = document.select("td:containsOwn(Жанр:) + td > a").joinToString { it.ownText() } - manga.description = document.select(".news-body").text() - manga.status = when (document.select("td:containsOwn(Состояние:) + td").first().ownText()) { - "Выход продолжается" -> SManga.ONGOING - "Выход завершён", "Выход завершен" -> SManga.COMPLETED - else -> SManga.UNKNOWN - } - return manga + override fun mangaDetailsParse(response: Response): SManga { + return mangaFromJson(gson.fromJson(response.body()!!.string())) } + // Chapters + + override fun chapterListRequest(manga: SManga): Request = apiMangaDetailsRequest(manga) + override fun chapterListParse(response: Response): List { - val document = response.asJsoup() - - val id = document.select("#reader").first().attr("src").split("?id=").last().toInt() - val jsonData = client.newCall(GET(baseUrl + MANGA_API_URL + id)).execute().body()!!.string() - val jsonArray = gson.fromJson>(jsonData) - val chapters = mutableListOf() - jsonArray.forEach { - val chapter = SChapter.create() - chapter.url = CHAPTER_API_URL + it["id"].int - chapter.name = "Глава ${it["chapter"].string}" - chapter.chapter_number = it["chapter"].string.toFloat() - chapters.add(chapter) + return gson.fromJson(response.body()!!.string())["entities"].asJsonArray.map { json -> + SChapter.create().apply { + url = json["id"].int.toString() + name = listOfNotNull(json["label"].nullString, json["name"].nullString).joinToString(" - ") + date_upload = json["updated_at"].toDate() + } } - return chapters.reversed() + } + + private val simpleDateFormat by lazy { + SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()) + } + + private fun JsonElement.toDate(): Long { + val date = this.nullString ?: return 0 + return try { + simpleDateFormat.parse(date)?.time ?: 0 + } catch (e: ParseException) { + 0 + } + } + + // Pages + + override fun pageListRequest(chapter: SChapter): Request { + return GET("$baseUrl/api/yandex/chapter/${chapter.url}", headers) } override fun pageListParse(response: Response): List { - val jsonData = response.body()!!.string() - val jsonArray = gson.fromJson>(jsonData) - val pages = mutableListOf() - jsonArray.forEachIndexed { index, imageUrl -> - pages.add(Page(index, imageUrl = imageUrl)) - } - return pages + return gson.fromJson(response.body()!!.string()) + .mapIndexed { i, json -> Page(i, "", json.string) } } - override fun latestUpdatesRequest(page: Int): Request = throw Exception("Not Used") - - override fun chapterFromElement(element: Element): SChapter = throw Exception("Not Used") - - override fun imageUrlParse(document: Document) = throw Exception("Not Used") - - override fun chapterListSelector() = throw Exception("Not Used") - - override fun latestUpdatesNextPageSelector() = throw Exception("Not Used") - - override fun latestUpdatesFromElement(element: Element): SManga = throw Exception("Not Used") - - override fun latestUpdatesSelector() = throw Exception("Not Used") - - companion object { - const val MANGA_API_URL = "/risensteam/api/manga.php?id=" - const val CHAPTER_API_URL = "/risensteam/api/chapter.php?id=" - } + override fun imageUrlParse(response: Response): String = throw UnsupportedOperationException("Not used") }