Replace JsonParser with kotlinx.serialization in some extensions (#7620)
* Replace JsonParser with kotlinx.serialization. * Remove wildcard import. * Remove more usages of JsonParser.
This commit is contained in:
parent
71986a1c6e
commit
3f91c5f75e
|
@ -1,11 +1,12 @@
|
|||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlinx-serialization'
|
||||
|
||||
ext {
|
||||
extName = 'Hitomi.la'
|
||||
pkgNameSuffix = 'all.hitomi'
|
||||
extClass = '.HitomiFactory'
|
||||
extVersionCode = 5
|
||||
extVersionCode = 6
|
||||
libVersion = '1.2'
|
||||
containsNsfw = true
|
||||
}
|
||||
|
|
|
@ -2,10 +2,6 @@ package eu.kanade.tachiyomi.extension.all.hitomi
|
|||
|
||||
import android.app.Application
|
||||
import android.content.SharedPreferences
|
||||
import com.github.salomonbrys.kotson.array
|
||||
import com.github.salomonbrys.kotson.get
|
||||
import com.github.salomonbrys.kotson.string
|
||||
import com.google.gson.JsonParser
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
||||
import eu.kanade.tachiyomi.source.ConfigurableSource
|
||||
|
@ -16,6 +12,10 @@ import eu.kanade.tachiyomi.source.model.SChapter
|
|||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.jsonArray
|
||||
import kotlinx.serialization.json.jsonObject
|
||||
import kotlinx.serialization.json.jsonPrimitive
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import org.jsoup.nodes.Document
|
||||
|
@ -24,6 +24,7 @@ import rx.Single
|
|||
import rx.schedulers.Schedulers
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.util.Locale
|
||||
import androidx.preference.CheckBoxPreference as AndroidXCheckBoxPreference
|
||||
import androidx.preference.PreferenceScreen as AndroidXPreferenceScreen
|
||||
|
@ -41,6 +42,8 @@ open class Hitomi(override val lang: String, private val nozomiLang: String) : H
|
|||
|
||||
override val baseUrl = BASE_URL
|
||||
|
||||
private val json: Json by injectLazy()
|
||||
|
||||
// Popular
|
||||
|
||||
override fun fetchPopularManga(page: Int): Observable<MangasPage> {
|
||||
|
@ -271,21 +274,25 @@ open class Hitomi(override val lang: String, private val nozomiLang: String) : H
|
|||
return GET("$LTN_BASE_URL/galleries/${hlIdFromUrl(chapter.url)}.js")
|
||||
}
|
||||
|
||||
private val jsonParser = JsonParser()
|
||||
|
||||
override fun pageListParse(response: Response): List<Page> {
|
||||
val str = response.body!!.string()
|
||||
val json = jsonParser.parse(str.removePrefix("var galleryinfo = "))
|
||||
return json["files"].array.mapIndexed { i, jsonElement ->
|
||||
val hash = jsonElement["hash"].string
|
||||
val ext = if (jsonElement["haswebp"].string == "0" || !hitomiAlwaysWebp()) jsonElement["name"].string.split('.').last() else "webp"
|
||||
val path = if (jsonElement["haswebp"].string == "0" || !hitomiAlwaysWebp()) "images" else "webp"
|
||||
val jsonRaw = response.body!!.string().removePrefix("var galleryinfo = ")
|
||||
val jsonResult = json.parseToJsonElement(jsonRaw).jsonObject
|
||||
|
||||
return jsonResult["files"]!!.jsonArray.mapIndexed { i, jsonEl ->
|
||||
val jsonObj = jsonEl.jsonObject
|
||||
val hash = jsonObj["hash"]!!.jsonPrimitive.content
|
||||
val hasWebp = jsonObj["haswebp"]!!.jsonPrimitive.content == "0"
|
||||
val hasAvif = jsonObj["hasavif"]!!.jsonPrimitive.content == "0"
|
||||
val ext = if (hasWebp || !hitomiAlwaysWebp())
|
||||
jsonObj["name"]!!.jsonPrimitive.content.substringAfterLast(".") else "webp"
|
||||
val path = if (hasWebp || !hitomiAlwaysWebp())
|
||||
"images" else "webp"
|
||||
val hashPath1 = hash.takeLast(1)
|
||||
val hashPath2 = hash.takeLast(3).take(2)
|
||||
|
||||
// https://ltn.hitomi.la/reader.js
|
||||
// function make_image_element()
|
||||
val secondSubdomain = if (jsonElement["haswebp"].string == "0" && jsonElement["hasavif"].string == "0") "b" else "a"
|
||||
val secondSubdomain = if (hasWebp && hasAvif) "b" else "a"
|
||||
|
||||
Page(i, "", "https://${firstSubdomainFromGalleryId(hashPath2)}$secondSubdomain.hitomi.la/$path/$hashPath1/$hashPath2/$hash.$ext")
|
||||
}
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlinx-serialization'
|
||||
|
||||
ext {
|
||||
extName = 'Home Hero Scans'
|
||||
pkgNameSuffix = "en.homeheroscans"
|
||||
extClass = '.HomeHeroScans'
|
||||
extVersionCode = 3
|
||||
extVersionCode = 4
|
||||
libVersion = '1.2'
|
||||
}
|
||||
|
||||
|
|
|
@ -1,29 +1,36 @@
|
|||
package eu.kanade.tachiyomi.extension.en.homeheroscans
|
||||
|
||||
import com.github.salomonbrys.kotson.forEach
|
||||
import com.google.gson.JsonParser
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.POST
|
||||
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.HttpSource
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.jsonArray
|
||||
import kotlinx.serialization.json.jsonObject
|
||||
import kotlinx.serialization.json.jsonPrimitive
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
||||
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
||||
import okhttp3.Request
|
||||
import okhttp3.RequestBody.Companion.toRequestBody
|
||||
import okhttp3.Response
|
||||
import rx.Observable
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
|
||||
open class HomeHeroScans : HttpSource() {
|
||||
override val lang = "en"
|
||||
|
||||
final override val name = "Home Hero Scans"
|
||||
|
||||
override val lang = "en"
|
||||
|
||||
final override val baseUrl = "https://hhs.vercel.app"
|
||||
|
||||
final override val supportsLatest = false
|
||||
|
||||
private val json: Json by injectLazy()
|
||||
|
||||
// { seriesId |---> chapter |---> numPages }
|
||||
private val chapterNumberCache: MutableMap<String, MutableMap<String, Int>> = mutableMapOf()
|
||||
|
||||
|
@ -42,38 +49,39 @@ open class HomeHeroScans : HttpSource() {
|
|||
}
|
||||
|
||||
val memoizedFetchPopularManga = memoizeObservable { page: Int -> super.fetchPopularManga(page) }
|
||||
// reduce number of times we call their api, user can force a call to api by relaunching the app
|
||||
override fun fetchPopularManga(page: Int) = memoizedFetchPopularManga(page)
|
||||
override fun popularMangaRequest(page: Int) = GET("$baseUrl/series.json", headers)
|
||||
override fun popularMangaParse(response: Response): MangasPage {
|
||||
val res = JsonParser.parseString(response.body?.string()).asJsonObject
|
||||
val manga = mutableListOf<SManga>()
|
||||
res.forEach { s, jsonElement ->
|
||||
val data = jsonElement.asJsonObject
|
||||
fun get(k: String) = data[k]?.asString
|
||||
|
||||
manga.add(
|
||||
SManga.create().apply {
|
||||
artist = get("artist")
|
||||
author = get("author")
|
||||
description = get("description")
|
||||
genre = get("genre")
|
||||
title = get("title")!!
|
||||
thumbnail_url = "$baseUrl${get("cover")}"
|
||||
url = "/series?series=$s"
|
||||
status = SManga.ONGOING // isn't reported
|
||||
}
|
||||
)
|
||||
// Reduce number of times we call their api, user can force a call to api by relaunching the app
|
||||
override fun fetchPopularManga(page: Int) = memoizedFetchPopularManga(page)
|
||||
|
||||
override fun popularMangaRequest(page: Int) = GET("$baseUrl/series.json", headers)
|
||||
|
||||
override fun popularMangaParse(response: Response): MangasPage {
|
||||
val jsonResult = json.parseToJsonElement(response.body!!.string()).jsonObject
|
||||
|
||||
val mangaList = jsonResult.entries.map { entry ->
|
||||
val jsonObj = entry.value.jsonObject
|
||||
|
||||
SManga.create().apply {
|
||||
artist = jsonObj["artist"]!!.jsonPrimitive.content
|
||||
author = jsonObj["author"]!!.jsonPrimitive.content
|
||||
description = jsonObj["description"]!!.jsonPrimitive.content
|
||||
genre = jsonObj["genre"]!!.jsonPrimitive.content
|
||||
title = jsonObj["title"]!!.jsonPrimitive.content
|
||||
thumbnail_url = baseUrl + jsonObj["cover"]!!.jsonPrimitive.content
|
||||
url = "/series?series=" + entry.key
|
||||
status = SManga.ONGOING
|
||||
}
|
||||
}
|
||||
return MangasPage(manga, false)
|
||||
|
||||
return MangasPage(mangaList, hasNextPage = false)
|
||||
}
|
||||
|
||||
// latest
|
||||
// Latest
|
||||
override fun latestUpdatesRequest(page: Int) = throw UnsupportedOperationException("Not used")
|
||||
|
||||
override fun latestUpdatesParse(response: Response) = throw UnsupportedOperationException("Not used")
|
||||
|
||||
// search
|
||||
|
||||
// Search
|
||||
private fun getMangaId(s: String): String? {
|
||||
return s.toHttpUrlOrNull()?.let { url ->
|
||||
// allow for trailing slash
|
||||
|
@ -89,34 +97,43 @@ open class HomeHeroScans : HttpSource() {
|
|||
|
||||
override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> {
|
||||
if (!query.startsWith(URL_SEARCH_PREFIX))
|
||||
// site doesn't have a search, so just return the popular page
|
||||
// Site doesn't have a search, so just return the popular page
|
||||
return fetchPopularManga(page)
|
||||
return getMangaId(query.substringAfter(URL_SEARCH_PREFIX))?.let { id ->
|
||||
fetchBySeriesId(id).map { MangasPage(it, false) }
|
||||
} ?: Observable.just(MangasPage(emptyList(), false))
|
||||
}
|
||||
|
||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList) = throw UnsupportedOperationException("Not used")
|
||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList) =
|
||||
throw UnsupportedOperationException("Not used")
|
||||
|
||||
override fun searchMangaParse(response: Response) = throw UnsupportedOperationException("Not used")
|
||||
|
||||
// chapter list (is paginated),
|
||||
// Chapter list (is paginated)
|
||||
override fun chapterListParse(response: Response): List<SChapter> {
|
||||
return JsonParser.parseString(response.body?.string()!!).asJsonObject["data"].asJsonArray.map {
|
||||
val chapterData = it.asJsonObject["data"].asJsonObject
|
||||
fun get(k: String) = chapterData[k].asString
|
||||
if (chapterNumberCache[get("series")] == null)
|
||||
chapterNumberCache[get("series")] = mutableMapOf()
|
||||
chapterNumberCache[get("series")]!![get("chapter")] = get("numPages").toInt()
|
||||
SChapter.create().apply {
|
||||
url = "/chapter?series=${get("series")}&ch=${get("chapter")}"
|
||||
val jsonResult = json.parseToJsonElement(response.body!!.string()).jsonObject
|
||||
|
||||
name = "Ch. ${get("chapter")} ${get("title")}"
|
||||
return jsonResult["data"]!!.jsonArray
|
||||
.map { jsonEl ->
|
||||
val jsonObj = jsonEl.jsonObject
|
||||
val chapterData = jsonObj["data"]!!.jsonObject
|
||||
val series = chapterData["series"]!!.jsonPrimitive.content
|
||||
val chapter = chapterData["chapter"]!!.jsonPrimitive.content
|
||||
|
||||
date_upload = SimpleDateFormat("MM/dd/yyyy").parse(get("date")).time
|
||||
if (chapterNumberCache[series] == null) {
|
||||
chapterNumberCache[series] = mutableMapOf()
|
||||
}
|
||||
|
||||
chapter_number = get("chapter").toFloat()
|
||||
chapterNumberCache[series]!![chapter] = chapterData["numPages"]!!.jsonPrimitive.content.toInt()
|
||||
|
||||
SChapter.create().apply {
|
||||
name = "Ch. $chapter ${chapterData["title"]!!.jsonPrimitive.content}"
|
||||
chapter_number = chapter.toFloatOrNull() ?: -1f
|
||||
date_upload = DATE_FORMATTER.parse(chapterData["date"]!!.jsonPrimitive.content)?.time ?: 0L
|
||||
url = "/chapter?series=$series&ch=$chapter"
|
||||
}
|
||||
}
|
||||
}.sortedByDescending { it.chapter_number }
|
||||
.sortedByDescending { it.chapter_number }
|
||||
}
|
||||
|
||||
override fun chapterListRequest(manga: SManga): Request {
|
||||
|
@ -134,7 +151,8 @@ open class HomeHeroScans : HttpSource() {
|
|||
} ?: Observable.just(manga)
|
||||
|
||||
override fun mangaDetailsParse(response: Response) = throw UnsupportedOperationException("Not used")
|
||||
// default implementation of mangaDetailsRequest has to exist for webview to work
|
||||
|
||||
// Default implementation of mangaDetailsRequest has to exist for webview to work
|
||||
// override fun mangaDetailsRequest(manga: SManga) = throw UnsupportedOperationException("Not used")
|
||||
|
||||
// Pages
|
||||
|
@ -146,9 +164,9 @@ open class HomeHeroScans : HttpSource() {
|
|||
return if (chapterPages() != null) {
|
||||
Observable.just(chapterPages()!!)
|
||||
} else {
|
||||
// has side effect of setting numPages in cache
|
||||
// Has side effect of setting numPages in cache
|
||||
fetchChapterList(
|
||||
// super hacky, url is wrong but has query parameter we need
|
||||
// Super hacky, url is wrong but has query parameter we need
|
||||
SManga.create().apply { this.url = chapter.url }
|
||||
).map {
|
||||
chapterPages()
|
||||
|
@ -161,10 +179,14 @@ open class HomeHeroScans : HttpSource() {
|
|||
}
|
||||
|
||||
override fun pageListParse(response: Response) = throw UnsupportedOperationException("Not used")
|
||||
|
||||
override fun pageListRequest(chapter: SChapter) = throw UnsupportedOperationException("Not Used")
|
||||
override fun imageUrlParse(response: Response): String = throw UnsupportedOperationException("Not used")
|
||||
|
||||
override fun imageUrlParse(response: Response): String = ""
|
||||
|
||||
companion object {
|
||||
private val DATE_FORMATTER = SimpleDateFormat("MM/dd/yyyy", Locale.ENGLISH)
|
||||
|
||||
const val URL_SEARCH_PREFIX = "url:"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlinx-serialization'
|
||||
|
||||
ext {
|
||||
extName = 'HonkaiImpact3'
|
||||
pkgNameSuffix = 'en.honkaiimpact'
|
||||
extClass = '.Honkaiimpact'
|
||||
extVersionCode = 1
|
||||
extVersionCode = 2
|
||||
libVersion = '1.2'
|
||||
}
|
||||
|
||||
|
|
|
@ -1,34 +1,39 @@
|
|||
package eu.kanade.tachiyomi.extension.en.honkaiimpact
|
||||
|
||||
import com.github.salomonbrys.kotson.float
|
||||
import com.github.salomonbrys.kotson.get
|
||||
import com.github.salomonbrys.kotson.int
|
||||
import com.github.salomonbrys.kotson.string
|
||||
import com.google.gson.JsonElement
|
||||
import com.google.gson.JsonParser
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
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 kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.JsonObject
|
||||
import kotlinx.serialization.json.float
|
||||
import kotlinx.serialization.json.int
|
||||
import kotlinx.serialization.json.jsonArray
|
||||
import kotlinx.serialization.json.jsonObject
|
||||
import kotlinx.serialization.json.jsonPrimitive
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Response
|
||||
import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
// Info - Based of BH3
|
||||
// This is the english version of the site
|
||||
class Honkaiimpact : ParsedHttpSource() {
|
||||
|
||||
// Info - Based of BH3
|
||||
// This is the english version of the site
|
||||
override val name = "Honkai Impact 3rd"
|
||||
|
||||
override val baseUrl = "https://manga.honkaiimpact3.com"
|
||||
|
||||
override val lang = "en"
|
||||
|
||||
override val supportsLatest = false
|
||||
|
||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
.connectTimeout(1, TimeUnit.MINUTES)
|
||||
.readTimeout(1, TimeUnit.MINUTES)
|
||||
|
@ -36,25 +41,33 @@ class Honkaiimpact : ParsedHttpSource() {
|
|||
.followRedirects(true)
|
||||
.build()
|
||||
|
||||
private val json: Json by injectLazy()
|
||||
|
||||
// Popular
|
||||
override fun popularMangaSelector() = "a[href*=book]"
|
||||
|
||||
override fun popularMangaNextPageSelector(): String? = null
|
||||
|
||||
override fun popularMangaRequest(page: Int) = GET("$baseUrl/book", headers)
|
||||
|
||||
override fun popularMangaFromElement(element: Element) = mangaFromElement(element)
|
||||
|
||||
// Latest
|
||||
override fun latestUpdatesSelector() = throw Exception("Not Used")
|
||||
|
||||
override fun latestUpdatesNextPageSelector(): String? = null
|
||||
|
||||
override fun latestUpdatesRequest(page: Int) = throw Exception("Not Used")
|
||||
|
||||
override fun latestUpdatesFromElement(element: Element) = mangaFromElement(element)
|
||||
|
||||
// Search
|
||||
override fun searchMangaSelector() = throw Exception("Not Used")
|
||||
|
||||
override fun searchMangaNextPageSelector(): String? = null
|
||||
|
||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList) = throw Exception("No search")
|
||||
|
||||
override fun searchMangaFromElement(element: Element) = mangaFromElement(element)
|
||||
|
||||
private fun mangaFromElement(element: Element): SManga {
|
||||
|
@ -78,22 +91,20 @@ class Honkaiimpact : ParsedHttpSource() {
|
|||
override fun chapterListSelector() = throw Exception("Not Used")
|
||||
|
||||
override fun chapterFromElement(element: Element) = throw Exception("Not Used")
|
||||
|
||||
override fun chapterListRequest(manga: SManga) = GET(baseUrl + manga.url + "/get_chapter", headers)
|
||||
|
||||
override fun chapterListParse(response: Response): List<SChapter> {
|
||||
val jsondata = response.body!!.string()
|
||||
val json = JsonParser().parse(jsondata).asJsonArray
|
||||
val chapters = mutableListOf<SChapter>()
|
||||
json.forEach {
|
||||
chapters.add(createChapter(it))
|
||||
}
|
||||
return chapters
|
||||
val jsonResult = json.parseToJsonElement(response.body!!.string()).jsonArray
|
||||
|
||||
return jsonResult.map { jsonEl -> createChapter(jsonEl.jsonObject) }
|
||||
}
|
||||
|
||||
private fun createChapter(json: JsonElement) = SChapter.create().apply {
|
||||
name = json["title"].string
|
||||
url = "/book/${json["bookid"].int}/${json["chapterid"].int}"
|
||||
date_upload = parseDate(json["timestamp"].string)
|
||||
chapter_number = json["chapterid"].float
|
||||
private fun createChapter(jsonObj: JsonObject) = SChapter.create().apply {
|
||||
name = jsonObj["title"]!!.jsonPrimitive.content
|
||||
url = "/book/${jsonObj["bookid"]!!.jsonPrimitive.int}/${jsonObj["chapterid"]!!.jsonPrimitive.int}"
|
||||
date_upload = parseDate(jsonObj["timestamp"]!!.jsonPrimitive.content)
|
||||
chapter_number = jsonObj["chapterid"]!!.jsonPrimitive.float
|
||||
}
|
||||
|
||||
private fun parseDate(date: String): Long {
|
||||
|
@ -101,13 +112,12 @@ class Honkaiimpact : ParsedHttpSource() {
|
|||
}
|
||||
|
||||
// Manga Pages
|
||||
override fun pageListParse(response: Response): List<Page> = mutableListOf<Page>().apply {
|
||||
val body = response.asJsoup()
|
||||
body.select("img.lazy.comic_img")?.forEach {
|
||||
add(Page(size, "", it.attr("data-original")))
|
||||
|
||||
override fun pageListParse(document: Document): List<Page> {
|
||||
return document.select("img.lazy.comic_img").mapIndexed { i, el ->
|
||||
Page(i, "", el.attr("data-original"))
|
||||
}
|
||||
}
|
||||
|
||||
override fun pageListParse(document: Document) = throw Exception("Not Used")
|
||||
override fun imageUrlParse(document: Document) = throw Exception("Not Used")
|
||||
override fun imageUrlParse(document: Document) = ""
|
||||
}
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlinx-serialization'
|
||||
|
||||
ext {
|
||||
extName = 'MangaDog'
|
||||
pkgNameSuffix = 'en.mangadog'
|
||||
extClass = '.Mangadog'
|
||||
extVersionCode = 1
|
||||
extVersionCode = 2
|
||||
libVersion = '1.2'
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
package eu.kanade.tachiyomi.extension.en.mangadog
|
||||
|
||||
import android.net.Uri
|
||||
import com.github.salomonbrys.kotson.get
|
||||
import com.github.salomonbrys.kotson.string
|
||||
import com.google.gson.JsonElement
|
||||
import com.google.gson.JsonParser
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||
|
@ -13,23 +9,39 @@ import eu.kanade.tachiyomi.source.model.SChapter
|
|||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.JsonObject
|
||||
import kotlinx.serialization.json.float
|
||||
import kotlinx.serialization.json.jsonArray
|
||||
import kotlinx.serialization.json.jsonObject
|
||||
import kotlinx.serialization.json.jsonPrimitive
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
|
||||
class Mangadog : HttpSource() {
|
||||
|
||||
override val name = "MangaDog"
|
||||
|
||||
override val baseUrl = "https://mangadog.club"
|
||||
|
||||
private val cdn = "https://cdn.mangadog.club"
|
||||
|
||||
override val lang = "en"
|
||||
|
||||
override val supportsLatest = true
|
||||
|
||||
override val client: OkHttpClient = network.cloudflareClient
|
||||
|
||||
private val json: Json by injectLazy()
|
||||
|
||||
override fun popularMangaRequest(page: Int) = GET("$baseUrl/index/classification/search_test?page=$page&state=all&demographic=all&genre=all", headers)
|
||||
|
||||
override fun latestUpdatesRequest(page: Int) = GET("$baseUrl/index/latestupdate/getUpdateResult?page=$page", headers)
|
||||
|
||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
||||
val uri = Uri.parse("$baseUrl/index/keywordsearch/index").buildUpon()
|
||||
.appendQueryParameter("query", query)
|
||||
|
@ -37,61 +49,49 @@ class Mangadog : HttpSource() {
|
|||
}
|
||||
|
||||
override fun popularMangaParse(response: Response): MangasPage {
|
||||
// val page = response.request.url.queryParameterValues("page").toString().toInt()
|
||||
val jsonData = response.body!!.string()
|
||||
val results = JsonParser().parse(jsonData)
|
||||
val data = results["data"]["data"]
|
||||
val mangas = mutableListOf<SManga>()
|
||||
for (i in 0 until data.asJsonArray.size()) {
|
||||
mangas.add(popularMangaFromjson(data[i]))
|
||||
val jsonResult = json.parseToJsonElement(response.body!!.string()).jsonObject
|
||||
|
||||
val mangaList = jsonResult["data"]!!.jsonObject["data"]!!.jsonArray.map { jsonEl ->
|
||||
popularMangaFromJson(jsonEl.jsonObject)
|
||||
}
|
||||
|
||||
val hasNextPage = true // page < results["data"]["pageNum"].int
|
||||
return MangasPage(mangas, hasNextPage)
|
||||
return MangasPage(mangaList, hasNextPage = true)
|
||||
}
|
||||
|
||||
private fun popularMangaFromjson(json: JsonElement): SManga {
|
||||
val manga = SManga.create()
|
||||
manga.title = json["name"].string.trim()
|
||||
manga.thumbnail_url = cdn + json["image"].string.replace("\\/", "/")
|
||||
val searchname = json["search_name"].string
|
||||
val id = json["id"].string
|
||||
manga.url = "/detail/$searchname/$id.html"
|
||||
return manga
|
||||
private fun popularMangaFromJson(jsonObj: JsonObject): SManga = SManga.create().apply {
|
||||
title = jsonObj["name"]!!.jsonPrimitive.content.trim()
|
||||
thumbnail_url = cdn + jsonObj["image"]!!.jsonPrimitive.content.replace("\\/", "/")
|
||||
|
||||
val searchName = jsonObj["search_name"]!!.jsonPrimitive.content
|
||||
val id = jsonObj["id"]!!.jsonPrimitive.content
|
||||
url = "/detail/$searchName/$id.html"
|
||||
}
|
||||
|
||||
override fun latestUpdatesParse(response: Response): MangasPage {
|
||||
val jsonData = response.body!!.string()
|
||||
val results = JsonParser().parse(jsonData)
|
||||
val data = results["data"]
|
||||
val mangas = mutableListOf<SManga>()
|
||||
for (i in 0 until data.asJsonArray.size()) {
|
||||
mangas.add(popularMangaFromjson(data[i]))
|
||||
val jsonResult = json.parseToJsonElement(response.body!!.string()).jsonObject
|
||||
|
||||
val mangaList = jsonResult["data"]!!.jsonArray.map { jsonEl ->
|
||||
popularMangaFromJson(jsonEl.jsonObject)
|
||||
}
|
||||
|
||||
val hasNextPage = true // data.asJsonArray.size()>18
|
||||
return MangasPage(mangas, hasNextPage)
|
||||
return MangasPage(mangaList, hasNextPage = true)
|
||||
}
|
||||
|
||||
override fun searchMangaParse(response: Response): MangasPage {
|
||||
val jsonData = response.body!!.string()
|
||||
val results = JsonParser().parse(jsonData)
|
||||
val data = results["suggestions"]
|
||||
val mangas = mutableListOf<SManga>()
|
||||
for (i in 0 until 1) {
|
||||
mangas.add(searchMangaFromjson(data[i]))
|
||||
val jsonResult = json.parseToJsonElement(response.body!!.string()).jsonObject
|
||||
|
||||
val mangaList = jsonResult["suggestions"]!!.jsonArray.map { jsonEl ->
|
||||
searchMangaFromJson(jsonEl.jsonObject)
|
||||
}
|
||||
|
||||
val hasNextPage = false
|
||||
return MangasPage(mangas, hasNextPage)
|
||||
return MangasPage(mangaList, hasNextPage = false)
|
||||
}
|
||||
|
||||
private fun searchMangaFromjson(json: JsonElement): SManga {
|
||||
val manga = SManga.create()
|
||||
manga.title = json["value"].string.trim()
|
||||
val data = json["data"].string.replace("\\/", "/")
|
||||
manga.url = "/detail/$data.html"
|
||||
return manga
|
||||
private fun searchMangaFromJson(jsonObj: JsonObject): SManga = SManga.create().apply{
|
||||
title = jsonObj["value"]!!.jsonPrimitive.content.trim()
|
||||
|
||||
val dataValue = jsonObj["data"]!!.jsonPrimitive.content.replace("\\/", "/")
|
||||
url = "/detail/$dataValue.html"
|
||||
}
|
||||
|
||||
override fun chapterListRequest(manga: SManga): Request {
|
||||
|
@ -100,57 +100,51 @@ class Mangadog : HttpSource() {
|
|||
}
|
||||
|
||||
override fun chapterListParse(response: Response): List<SChapter> {
|
||||
val jsonData = response.body!!.string()
|
||||
val results = JsonParser().parse(jsonData)
|
||||
val data = results["data"]["data"]
|
||||
val chapters = mutableListOf<SChapter>()
|
||||
for (i in 0 until data.asJsonArray.size()) {
|
||||
chapters.add(chapterFromjson(data[i]))
|
||||
val jsonResult = json.parseToJsonElement(response.body!!.string()).jsonObject
|
||||
|
||||
return jsonResult["data"]!!.jsonObject["data"]!!.jsonArray.map { jsonEl ->
|
||||
chapterFromJson(jsonEl.jsonObject)
|
||||
}
|
||||
return chapters
|
||||
}
|
||||
|
||||
private fun chapterFromjson(json: JsonElement): SChapter {
|
||||
val chapter = SChapter.create()
|
||||
val searchname = json["search_name"].string
|
||||
val id = json["comic_id"].string
|
||||
chapter.url = "/read/read/$searchname/$id.html" // The url should include the manga name but it doesn't seem to matter
|
||||
chapter.name = json["name"].string.trim()
|
||||
chapter.chapter_number = json["obj_id"].asFloat
|
||||
chapter.date_upload = parseDate(json["create_date"].string)
|
||||
return chapter
|
||||
private fun chapterFromJson(jsonObj: JsonObject): SChapter = SChapter.create().apply {
|
||||
// The url should include the manga name but it doesn't seem to matter
|
||||
val searchname = jsonObj["search_name"]!!.jsonPrimitive.content
|
||||
val id = jsonObj["comic_id"]!!.jsonPrimitive.content
|
||||
url = "/read/read/$searchname/$id.html"
|
||||
|
||||
name = jsonObj["name"]!!.jsonPrimitive.content.trim()
|
||||
chapter_number = jsonObj["obj_id"]!!.jsonPrimitive.float
|
||||
date_upload = parseDate(jsonObj["create_date"]!!.jsonPrimitive.content)
|
||||
}
|
||||
|
||||
private fun parseDate(date: String): Long {
|
||||
return SimpleDateFormat("yyyy-MM-dd", Locale.US).parse(date)?.time ?: 0L
|
||||
}
|
||||
|
||||
override fun mangaDetailsParse(response: Response): SManga {
|
||||
override fun mangaDetailsParse(response: Response): SManga = SManga.create().apply{
|
||||
val document = response.asJsoup()
|
||||
val manga = SManga.create()
|
||||
manga.thumbnail_url = document.select("img.detail-post-img").attr("abs:src")
|
||||
manga.description = document.select("h2.fs15 + p").text().trim()
|
||||
manga.author = document.select("a[href*=artist]").text()
|
||||
manga.artist = document.select("a[href*=artist]").text()
|
||||
val glist = document.select("div.col-sm-10.col-xs-9.text-left.toe.mlr0.text-left-m a[href*=genre]").map { it.text().substringAfter(",").capitalize() }
|
||||
manga.genre = glist.joinToString(", ")
|
||||
manga.status = when (document.select("span.label.label-success").first().text()) {
|
||||
|
||||
thumbnail_url = document.select("img.detail-post-img").attr("abs:src")
|
||||
description = document.select("h2.fs15 + p").text().trim()
|
||||
author = document.select("a[href*=artist]").text()
|
||||
artist = document.select("a[href*=artist]").text()
|
||||
genre = document.select("div.col-sm-10.col-xs-9.text-left.toe.mlr0.text-left-m a[href*=genre]")
|
||||
.joinToString { it.text().substringAfter(",").capitalize(Locale.ROOT) }
|
||||
status = when (document.select("span.label.label-success").first().text()) {
|
||||
"update" -> SManga.ONGOING
|
||||
"finished" -> SManga.COMPLETED
|
||||
else -> SManga.UNKNOWN
|
||||
}
|
||||
return manga
|
||||
}
|
||||
|
||||
override fun pageListParse(response: Response): List<Page> {
|
||||
val body = response.asJsoup()
|
||||
val pages = mutableListOf<Page>()
|
||||
val elements = body.select("img[data-src]")
|
||||
for (i in 0 until elements.size) {
|
||||
pages.add(Page(i, "", elements[i].select("img").attr("data-src")))
|
||||
val document = response.asJsoup()
|
||||
|
||||
return document.select("img[data-src]").mapIndexed { i, el ->
|
||||
Page(i, "", el.select("img").attr("data-src"))
|
||||
}
|
||||
return pages
|
||||
}
|
||||
|
||||
override fun imageUrlParse(response: Response) = throw Exception("Not used")
|
||||
override fun imageUrlParse(response: Response) = ""
|
||||
}
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlinx-serialization'
|
||||
|
||||
ext {
|
||||
extName = 'Mangahasu'
|
||||
pkgNameSuffix = 'en.mangahasu'
|
||||
extClass = '.Mangahasu'
|
||||
extVersionCode = 11
|
||||
extVersionCode = 12
|
||||
libVersion = '1.2'
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,6 @@
|
|||
package eu.kanade.tachiyomi.extension.en.mangahasu
|
||||
|
||||
import android.util.Base64
|
||||
import com.github.salomonbrys.kotson.array
|
||||
import com.github.salomonbrys.kotson.get
|
||||
import com.github.salomonbrys.kotson.int
|
||||
import com.github.salomonbrys.kotson.string
|
||||
import com.google.gson.JsonParser
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.source.model.Filter
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
|
@ -13,12 +8,18 @@ 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 kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.int
|
||||
import kotlinx.serialization.json.jsonArray
|
||||
import kotlinx.serialization.json.jsonObject
|
||||
import kotlinx.serialization.json.jsonPrimitive
|
||||
import okhttp3.Headers
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
|
||||
|
@ -34,9 +35,10 @@ class Mangahasu : ParsedHttpSource() {
|
|||
|
||||
override val client: OkHttpClient = network.cloudflareClient
|
||||
|
||||
override fun headersBuilder(): Headers.Builder {
|
||||
return super.headersBuilder().add("Referer", baseUrl)
|
||||
}
|
||||
private val json: Json by injectLazy()
|
||||
|
||||
override fun headersBuilder(): Headers.Builder = super.headersBuilder()
|
||||
.add("Referer", baseUrl)
|
||||
|
||||
override fun popularMangaRequest(page: Int): Request =
|
||||
GET("$baseUrl/directory.html?page=$page", headers)
|
||||
|
@ -143,34 +145,40 @@ class Mangahasu : ParsedHttpSource() {
|
|||
}
|
||||
|
||||
override fun pageListParse(document: Document): List<Page> {
|
||||
|
||||
// Grab All Pages from site
|
||||
// Some images are place holders on new chapters.
|
||||
|
||||
val pages = mutableListOf<Page>().apply {
|
||||
document.select("div.img img").forEach {
|
||||
val pageNumber = it.attr("class").substringAfter("page").toInt()
|
||||
add(Page(pageNumber, "", it.attr("src")))
|
||||
val pageList = document.select("div.img img")
|
||||
.mapIndexed { i, el ->
|
||||
val pageNumber = el.attr("class").substringAfter("page").toInt()
|
||||
Page(pageNumber, "", el.attr("src"))
|
||||
}
|
||||
}
|
||||
.toMutableList()
|
||||
|
||||
// Some images are not yet loaded onto Mangahasu's image server.
|
||||
// Decode temporary URLs and replace placeholder images.
|
||||
|
||||
val lstDUrls =
|
||||
document.select("script:containsData(lstDUrls)").html().substringAfter("lstDUrls")
|
||||
.substringAfter("\"").substringBefore("\"")
|
||||
if (lstDUrls != "W10=") { // Base64 = [] or empty file
|
||||
val decoded = String(Base64.decode(lstDUrls, Base64.DEFAULT))
|
||||
val json = JsonParser().parse(decoded).array
|
||||
json.forEach {
|
||||
val pageNumber = it["page"].int
|
||||
pages.removeAll { page -> page.index == pageNumber }
|
||||
pages.add(Page(pageNumber, "", it["url"].string))
|
||||
val lstDUrls = document.select("script:containsData(lstDUrls)")
|
||||
.html()
|
||||
.substringAfter("lstDUrls")
|
||||
.substringAfter("\"")
|
||||
.substringBefore("\"")
|
||||
|
||||
// Base64 = [] or empty file
|
||||
if (lstDUrls != "W10=") {
|
||||
val jsonRaw = String(Base64.decode(lstDUrls, Base64.DEFAULT))
|
||||
val jsonArr = json.parseToJsonElement(jsonRaw).jsonArray
|
||||
|
||||
jsonArr.forEach { jsonEl ->
|
||||
val jsonObj = jsonEl.jsonObject
|
||||
val pageNumber = jsonObj["page"]!!.jsonPrimitive.int
|
||||
|
||||
pageList.removeAll { page -> page.index == pageNumber }
|
||||
pageList.add(Page(pageNumber, "", jsonObj["url"]!!.jsonPrimitive.content))
|
||||
}
|
||||
}
|
||||
pages.sortBy { page -> page.index }
|
||||
return pages
|
||||
|
||||
return pageList.sortedBy { page -> page.index }
|
||||
}
|
||||
|
||||
override fun imageUrlParse(document: Document) = ""
|
||||
|
|
|
@ -1,17 +1,13 @@
|
|||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlinx-serialization'
|
||||
|
||||
ext {
|
||||
extName = 'Kumanga'
|
||||
pkgNameSuffix = 'es.kumanga'
|
||||
extClass = '.Kumanga'
|
||||
extVersionCode = 6
|
||||
extVersionCode = 7
|
||||
libVersion = '1.2'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly 'com.google.code.gson:gson:2.8.5'
|
||||
compileOnly 'com.github.salomonbrys.kotson:kotson:2.5.0'
|
||||
}
|
||||
|
||||
apply from: "$rootDir/common.gradle"
|
||||
|
|
|
@ -1,12 +1,7 @@
|
|||
package eu.kanade.tachiyomi.extension.es.kumanga
|
||||
|
||||
import android.util.Base64
|
||||
import com.github.salomonbrys.kotson.array
|
||||
import com.github.salomonbrys.kotson.get
|
||||
import com.github.salomonbrys.kotson.int
|
||||
import com.github.salomonbrys.kotson.string
|
||||
import com.google.gson.JsonElement
|
||||
import com.google.gson.JsonParser
|
||||
import com.github.salomonbrys.kotson.jsonObject
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.POST
|
||||
import eu.kanade.tachiyomi.source.model.Filter
|
||||
|
@ -17,18 +12,33 @@ import eu.kanade.tachiyomi.source.model.SChapter
|
|||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.JsonObject
|
||||
import kotlinx.serialization.json.int
|
||||
import kotlinx.serialization.json.jsonArray
|
||||
import kotlinx.serialization.json.jsonObject
|
||||
import kotlinx.serialization.json.jsonPrimitive
|
||||
import okhttp3.Headers
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import org.jsoup.nodes.Element
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
class Kumanga : HttpSource() {
|
||||
|
||||
override val name = "Kumanga"
|
||||
|
||||
override val baseUrl = "https://www.kumanga.com"
|
||||
|
||||
override val lang = "es"
|
||||
|
||||
override val supportsLatest = false
|
||||
|
||||
override val client: OkHttpClient = network.cloudflareClient
|
||||
.newBuilder()
|
||||
.followRedirects(true)
|
||||
|
@ -45,13 +55,7 @@ class Kumanga : HttpSource() {
|
|||
}
|
||||
.build()
|
||||
|
||||
override val name = "Kumanga"
|
||||
|
||||
override val baseUrl = "https://www.kumanga.com"
|
||||
|
||||
override val lang = "es"
|
||||
|
||||
override val supportsLatest = false
|
||||
private val json: Json by injectLazy()
|
||||
|
||||
override fun headersBuilder(): Headers.Builder = Headers.Builder()
|
||||
.add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:79.0) Gecko/20100101 Firefox/79.0")
|
||||
|
@ -72,8 +76,10 @@ class Kumanga : HttpSource() {
|
|||
|
||||
private fun getKumangaToken(): String {
|
||||
val body = client.newCall(GET("$baseUrl/mangalist?&page=1", headers)).execute().asJsoup()
|
||||
var dt = body.select("#searchinput").attr("dt").toString()
|
||||
var kumangaTokenKey = encodeAndReverse(encodeAndReverse(dt)).replace("=", "k").toLowerCase()
|
||||
val dt = body.select("#searchinput").attr("dt").toString()
|
||||
val kumangaTokenKey = encodeAndReverse(encodeAndReverse(dt))
|
||||
.replace("=", "k")
|
||||
.toLowerCase(Locale.ROOT)
|
||||
kumangaToken = body.select("div.input-group [type=hidden]").attr(kumangaTokenKey)
|
||||
return kumangaToken
|
||||
}
|
||||
|
@ -82,40 +88,28 @@ class Kumanga : HttpSource() {
|
|||
|
||||
private fun getMangaUrl(mangaId: String, mangaSlug: String, page: Int) = "/manga/$mangaId/p/$page/$mangaSlug#cl"
|
||||
|
||||
private fun parseMangaFromJson(json: JsonElement) = SManga.create().apply {
|
||||
title = json["name"].string
|
||||
description = json["description"].string.replace("\\", "")
|
||||
url = getMangaUrl(json["id"].string, json["slug"].string, 1)
|
||||
thumbnail_url = getMangaCover(json["id"].string)
|
||||
|
||||
val genresArray = json["categories"].array
|
||||
genre = genresArray.joinToString { jsonObject ->
|
||||
parseGenresFromJson(jsonObject)
|
||||
}
|
||||
private fun parseMangaFromJson(jsonObj: JsonObject) = SManga.create().apply {
|
||||
title = jsonObj["name"]!!.jsonPrimitive.content
|
||||
description = jsonObj["description"]!!.jsonPrimitive.content.replace("\\", "")
|
||||
url = getMangaUrl(jsonObj["id"]!!.jsonPrimitive.content, jsonObj["slug"]!!.jsonPrimitive.content, 1)
|
||||
thumbnail_url = getMangaCover(jsonObj["id"]!!.jsonPrimitive.content)
|
||||
genre = jsonObj["categories"]!!.jsonArray
|
||||
.joinToString { it.jsonObject["name"]!!.jsonPrimitive.content }
|
||||
}
|
||||
|
||||
private fun parseJson(json: String): JsonElement {
|
||||
return JsonParser().parse(json)
|
||||
}
|
||||
|
||||
private fun parseGenresFromJson(json: JsonElement) = json["name"].string
|
||||
|
||||
override fun popularMangaRequest(page: Int): Request {
|
||||
return POST("$baseUrl/backend/ajax/searchengine.php?page=$page&perPage=10&keywords=&retrieveCategories=true&retrieveAuthors=false&contentType=manga&token=$kumangaToken", headers)
|
||||
}
|
||||
|
||||
override fun popularMangaParse(response: Response): MangasPage {
|
||||
val res = response.body!!.string()
|
||||
val json = parseJson(res)
|
||||
val data = json["contents"].array
|
||||
val retrievedCount = json["retrievedCount"].int
|
||||
val hasNextPage = retrievedCount == 10
|
||||
val jsonResult = json.parseToJsonElement(response.body!!.string()).jsonObject
|
||||
|
||||
val mangas = data.map { jsonObject ->
|
||||
parseMangaFromJson(jsonObject)
|
||||
}
|
||||
val mangaList = jsonResult["contents"]!!.jsonArray
|
||||
.map { jsonEl -> parseMangaFromJson(jsonEl.jsonObject) }
|
||||
|
||||
return MangasPage(mangas, hasNextPage)
|
||||
val hasNextPage = jsonResult["retrievedCount"]!!.jsonPrimitive.int == 10
|
||||
|
||||
return MangasPage(mangaList, hasNextPage)
|
||||
}
|
||||
|
||||
override fun latestUpdatesRequest(page: Int) = throw Exception("Not Used")
|
||||
|
@ -174,20 +168,22 @@ class Kumanga : HttpSource() {
|
|||
} else throw Exception("No fue posible obtener los capítulos")
|
||||
}
|
||||
|
||||
override fun pageListParse(response: Response): List<Page> = mutableListOf<Page>().apply {
|
||||
override fun pageListParse(response: Response): List<Page> {
|
||||
val document = response.asJsoup()
|
||||
var imagesJsonListStr = document.select("script:containsData(var pUrl=)").firstOrNull()?.data()
|
||||
val imagesJsonRaw = document.select("script:containsData(var pUrl=)").firstOrNull()
|
||||
?.data()
|
||||
?.substringAfter("var pUrl=")
|
||||
?.substringBefore(";")
|
||||
?.let { decodeBase64(decodeBase64(it).reversed().dropLast(10).drop(10)) }
|
||||
?: throw Exception("imagesJsonListStr null")
|
||||
imagesJsonListStr = decodeBase64(decodeBase64(imagesJsonListStr).reversed().dropLast(10).drop(10))
|
||||
val imagesJsonList = parseJson(imagesJsonListStr).array
|
||||
|
||||
imagesJsonList.forEach {
|
||||
val fakeImageUrl = it["imgURL"].string.replace("\\", "")
|
||||
val imageUrl = baseUrl + fakeImageUrl
|
||||
val jsonResult = json.parseToJsonElement(imagesJsonRaw).jsonArray
|
||||
|
||||
add(Page(size, "", imageUrl))
|
||||
return jsonResult.mapIndexed { i, jsonEl ->
|
||||
val jsonObj = jsonEl.jsonObject
|
||||
val imagePath = jsonObj["imgURL"]!!.jsonPrimitive.content.replace("\\", "")
|
||||
|
||||
Page(i, "", baseUrl + imagePath)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlinx-serialization'
|
||||
|
||||
ext {
|
||||
extName = 'MangaMx'
|
||||
pkgNameSuffix = 'es.mangamx'
|
||||
extClass = '.MangaMx'
|
||||
extVersionCode = 10
|
||||
extVersionCode = 11
|
||||
libVersion = '1.2'
|
||||
}
|
||||
|
||||
|
|
|
@ -4,10 +4,6 @@ import android.app.Application
|
|||
import android.content.SharedPreferences
|
||||
import android.net.Uri
|
||||
import android.util.Base64
|
||||
import com.github.salomonbrys.kotson.get
|
||||
import com.github.salomonbrys.kotson.string
|
||||
import com.google.gson.JsonElement
|
||||
import com.google.gson.JsonParser
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.POST
|
||||
import eu.kanade.tachiyomi.source.ConfigurableSource
|
||||
|
@ -19,6 +15,11 @@ 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 kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.JsonObject
|
||||
import kotlinx.serialization.json.jsonArray
|
||||
import kotlinx.serialization.json.jsonObject
|
||||
import kotlinx.serialization.json.jsonPrimitive
|
||||
import okhttp3.FormBody
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
|
@ -26,6 +27,7 @@ import org.jsoup.nodes.Document
|
|||
import org.jsoup.nodes.Element
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.nio.charset.Charset
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
|
@ -44,6 +46,8 @@ open class MangaMx : ConfigurableSource, ParsedHttpSource() {
|
|||
|
||||
private var csrfToken = ""
|
||||
|
||||
private val json: Json by injectLazy()
|
||||
|
||||
override fun popularMangaRequest(page: Int) = GET(
|
||||
"$baseUrl/directorio?genero=false" +
|
||||
"&estado=false&filtro=visitas&tipo=false&adulto=${if (hideNSFWContent()) "0" else "false"}&orden=desc&p=$page",
|
||||
|
@ -154,20 +158,22 @@ open class MangaMx : ConfigurableSource, ParsedHttpSource() {
|
|||
|
||||
return MangasPage(mangas, hasNextPage)
|
||||
} else {
|
||||
val body = response.body!!.string()
|
||||
if (body == "[]") throw Exception("Término de búsqueda demasiado corto")
|
||||
val json = JsonParser().parse(body)["mangas"].asJsonArray
|
||||
val jsonResult = json.parseToJsonElement(response.body!!.string()).jsonArray
|
||||
|
||||
val mangas = json.map { jsonElement -> searchMangaFromJson(jsonElement) }
|
||||
val hasNextPage = false
|
||||
return MangasPage(mangas, hasNextPage)
|
||||
if (jsonResult.isEmpty()) {
|
||||
throw Exception("Término de búsqueda demasiado corto")
|
||||
}
|
||||
|
||||
val mangaList = jsonResult.map { jsonEl -> searchMangaFromJson(jsonEl.jsonObject) }
|
||||
|
||||
return MangasPage(mangaList, hasNextPage = false)
|
||||
}
|
||||
}
|
||||
|
||||
private fun searchMangaFromJson(jsonElement: JsonElement): SManga = SManga.create().apply {
|
||||
title = jsonElement["nombre"].string
|
||||
setUrlWithoutDomain(jsonElement["url"].string)
|
||||
thumbnail_url = jsonElement["img"].string.replace("/thumb", "/cover")
|
||||
private fun searchMangaFromJson(jsonObj: JsonObject): SManga = SManga.create().apply {
|
||||
title = jsonObj["nombre"]!!.jsonPrimitive.content
|
||||
thumbnail_url = jsonObj["img"]!!.jsonPrimitive.content.replace("/thumb", "/cover")
|
||||
setUrlWithoutDomain(jsonObj["url"]!!.jsonPrimitive.content)
|
||||
}
|
||||
|
||||
override fun mangaDetailsParse(document: Document): SManga {
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlinx-serialization'
|
||||
|
||||
ext {
|
||||
extName = 'Japanread'
|
||||
pkgNameSuffix = 'fr.japanread'
|
||||
extClass = '.Japanread'
|
||||
extVersionCode = 7
|
||||
extVersionCode = 8
|
||||
libVersion = '1.2'
|
||||
containsNsfw = true
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package eu.kanade.tachiyomi.extension.fr.japanread
|
||||
|
||||
import android.net.Uri
|
||||
import com.github.salomonbrys.kotson.string
|
||||
import com.google.gson.JsonParser
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
||||
import eu.kanade.tachiyomi.source.model.Filter
|
||||
|
@ -12,11 +10,16 @@ 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 kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.jsonArray
|
||||
import kotlinx.serialization.json.jsonObject
|
||||
import kotlinx.serialization.json.jsonPrimitive
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
import rx.Observable
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.util.Calendar
|
||||
|
||||
class Japanread : ParsedHttpSource() {
|
||||
|
@ -29,6 +32,8 @@ class Japanread : ParsedHttpSource() {
|
|||
|
||||
override val supportsLatest = true
|
||||
|
||||
private val json: Json by injectLazy()
|
||||
|
||||
// Generic (used by popular/latest/search)
|
||||
private fun mangaListFromElement(element: Element): SManga {
|
||||
return SManga.create().apply {
|
||||
|
@ -224,20 +229,19 @@ class Japanread : ParsedHttpSource() {
|
|||
override fun pageListParse(document: Document): List<Page> {
|
||||
val chapterId = document.select("meta[data-chapter-id]").attr("data-chapter-id")
|
||||
|
||||
val apiResponse = client.newCall(GET("$baseUrl/api/?id=$chapterId&type=chapter", apiHeaders())).execute()
|
||||
val apiRequest = GET("$baseUrl/api/?id=$chapterId&type=chapter", apiHeaders())
|
||||
val apiResponse = client.newCall(apiRequest).execute()
|
||||
|
||||
val jsonData = apiResponse.body!!.string()
|
||||
val json = JsonParser.parseString(jsonData).asJsonObject
|
||||
val jsonResult = json.parseToJsonElement(apiResponse.body!!.string()).jsonObject
|
||||
|
||||
val baseImagesUrl = json["baseImagesUrl"].string
|
||||
val baseImagesUrl = jsonResult["baseImagesUrl"]!!.jsonPrimitive.content
|
||||
|
||||
return json["page_array"].asJsonArray.mapIndexed { idx, it ->
|
||||
val imgUrl = "$baseUrl$baseImagesUrl/${it.asString}"
|
||||
Page(idx, baseUrl, imgUrl)
|
||||
return jsonResult["page_array"]!!.jsonArray.mapIndexed { i, jsonEl ->
|
||||
Page(i, baseUrl, "$baseUrl$baseImagesUrl/${jsonEl.jsonPrimitive.content}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun imageUrlParse(document: Document): String = throw UnsupportedOperationException("Not Used")
|
||||
override fun imageUrlParse(document: Document) = ""
|
||||
|
||||
override fun imageRequest(page: Page): Request {
|
||||
return GET(page.imageUrl!!, headers)
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlinx-serialization'
|
||||
|
||||
ext {
|
||||
extName = 'Japscan'
|
||||
pkgNameSuffix = 'fr.japscan'
|
||||
extClass = '.Japscan'
|
||||
extVersionCode = 28
|
||||
extVersionCode = 29
|
||||
libVersion = '1.2'
|
||||
}
|
||||
|
||||
|
|
|
@ -18,13 +18,6 @@ import android.webkit.WebResourceRequest
|
|||
import android.webkit.WebResourceResponse
|
||||
import android.webkit.WebView
|
||||
import android.webkit.WebViewClient
|
||||
import com.github.salomonbrys.kotson.fromJson
|
||||
import com.github.salomonbrys.kotson.get
|
||||
import com.github.salomonbrys.kotson.string
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.JsonElement
|
||||
import com.google.gson.JsonObject
|
||||
import com.google.gson.JsonParser
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.POST
|
||||
import eu.kanade.tachiyomi.source.ConfigurableSource
|
||||
|
@ -36,6 +29,11 @@ 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 kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.JsonObject
|
||||
import kotlinx.serialization.json.jsonArray
|
||||
import kotlinx.serialization.json.jsonObject
|
||||
import kotlinx.serialization.json.jsonPrimitive
|
||||
import okhttp3.FormBody
|
||||
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
||||
import okhttp3.OkHttpClient
|
||||
|
@ -46,6 +44,7 @@ import org.jsoup.nodes.Document
|
|||
import org.jsoup.nodes.Element
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.text.ParseException
|
||||
|
@ -66,6 +65,8 @@ class Japscan : ConfigurableSource, ParsedHttpSource() {
|
|||
|
||||
override val supportsLatest = true
|
||||
|
||||
private val json: Json by injectLazy()
|
||||
|
||||
private val preferences: SharedPreferences by lazy {
|
||||
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
||||
}
|
||||
|
@ -173,7 +174,9 @@ class Japscan : ConfigurableSource, ParsedHttpSource() {
|
|||
}
|
||||
|
||||
override fun popularMangaNextPageSelector(): String? = null
|
||||
|
||||
override fun popularMangaSelector() = "#top_mangas_week li > span"
|
||||
|
||||
override fun popularMangaFromElement(element: Element): SManga {
|
||||
val manga = SManga.create()
|
||||
element.select("a").first().let {
|
||||
|
@ -201,10 +204,10 @@ class Japscan : ConfigurableSource, ParsedHttpSource() {
|
|||
}
|
||||
|
||||
override fun latestUpdatesNextPageSelector(): String? = null
|
||||
override fun latestUpdatesSelector() = "#chapters > div > h3.text-truncate"
|
||||
override fun latestUpdatesFromElement(element: Element): SManga = popularMangaFromElement(element)
|
||||
|
||||
private val gson = Gson()
|
||||
override fun latestUpdatesSelector() = "#chapters > div > h3.text-truncate"
|
||||
|
||||
override fun latestUpdatesFromElement(element: Element): SManga = popularMangaFromElement(element)
|
||||
|
||||
// Search
|
||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
||||
|
@ -227,20 +230,22 @@ class Japscan : ConfigurableSource, ParsedHttpSource() {
|
|||
.build()
|
||||
|
||||
try {
|
||||
return client.newCall(POST("$baseUrl/live-search/", searchHeaders, formBody)).execute().use { response ->
|
||||
if (!response.isSuccessful) throw Exception("Unexpected code $response")
|
||||
val searchRequest = POST("$baseUrl/live-search/", searchHeaders, formBody)
|
||||
val searchResponse = client.newCall(searchRequest).execute()
|
||||
|
||||
val jsonObject = gson.fromJson<JsonObject>(response.body!!.string())
|
||||
|
||||
if (jsonObject.asJsonArray.size() === 0) {
|
||||
Log.d("japscan", "Search not returning anything, using duckduckgo")
|
||||
|
||||
throw Exception("No data")
|
||||
}
|
||||
|
||||
return response.request
|
||||
if (!searchResponse.isSuccessful) {
|
||||
throw Exception("Unexpected code ${searchResponse.code}")
|
||||
}
|
||||
} finally {
|
||||
|
||||
val jsonResult = json.parseToJsonElement(searchResponse.body!!.string()).jsonArray
|
||||
|
||||
if (jsonResult.isEmpty()) {
|
||||
Log.d("japscan", "Search not returning anything, using duckduckgo")
|
||||
throw Exception("No data")
|
||||
}
|
||||
|
||||
return searchRequest
|
||||
} catch (e: Exception) {
|
||||
// Fallback to duckduckgo if the search does not return any result
|
||||
val uri = Uri.parse("https://duckduckgo.com/lite/").buildUpon()
|
||||
.appendQueryParameter("q", "$query site:$baseUrl/manga/")
|
||||
|
@ -250,42 +255,30 @@ class Japscan : ConfigurableSource, ParsedHttpSource() {
|
|||
}
|
||||
}
|
||||
|
||||
override fun searchMangaNextPageSelector(): String? = "li.page-item:last-child:not(li.active),.next_form .navbutton"
|
||||
override fun searchMangaNextPageSelector(): String = "li.page-item:last-child:not(li.active),.next_form .navbutton"
|
||||
|
||||
override fun searchMangaSelector(): String = "div.card div.p-2, a.result-link"
|
||||
|
||||
override fun searchMangaParse(response: Response): MangasPage {
|
||||
if ("live-search" in response.request.url.toString()) {
|
||||
val body = response.body!!.string()
|
||||
val json = JsonParser().parse(body).asJsonArray
|
||||
val mangas = json.map { jsonElement ->
|
||||
searchMangaFromJson(jsonElement)
|
||||
}
|
||||
val jsonResult = json.parseToJsonElement(response.body!!.string()).jsonArray
|
||||
|
||||
val hasNextPage = false
|
||||
val mangaList = jsonResult.map { jsonEl -> searchMangaFromJson(jsonEl.jsonObject) }
|
||||
|
||||
return MangasPage(mangas, hasNextPage)
|
||||
} else {
|
||||
val document = response.asJsoup()
|
||||
|
||||
val mangas = document.select(searchMangaSelector()).map { element ->
|
||||
searchMangaFromElement(element)
|
||||
}
|
||||
|
||||
val hasNextPage = searchMangaNextPageSelector()?.let { selector ->
|
||||
document.select(selector).first()
|
||||
} != null
|
||||
|
||||
return MangasPage(mangas, hasNextPage)
|
||||
return MangasPage(mangaList, hasNextPage = false)
|
||||
}
|
||||
|
||||
return super.searchMangaParse(response)
|
||||
}
|
||||
|
||||
override fun searchMangaFromElement(element: Element): SManga {
|
||||
if (element.attr("class") == "result-link") {
|
||||
return SManga.create().apply {
|
||||
return if (element.attr("class") == "result-link") {
|
||||
SManga.create().apply {
|
||||
title = element.text().substringAfter(" ").substringBefore(" | JapScan")
|
||||
setUrlWithoutDomain(element.attr("abs:href"))
|
||||
}
|
||||
} else {
|
||||
return SManga.create().apply {
|
||||
SManga.create().apply {
|
||||
thumbnail_url = element.select("img").attr("abs:src")
|
||||
element.select("p a").let {
|
||||
title = it.text()
|
||||
|
@ -295,9 +288,9 @@ class Japscan : ConfigurableSource, ParsedHttpSource() {
|
|||
}
|
||||
}
|
||||
|
||||
private fun searchMangaFromJson(jsonElement: JsonElement): SManga = SManga.create().apply {
|
||||
title = jsonElement["name"].string
|
||||
url = jsonElement["url"].string
|
||||
private fun searchMangaFromJson(jsonObj: JsonObject): SManga = SManga.create().apply {
|
||||
title = jsonObj["name"]!!.jsonPrimitive.content
|
||||
url = jsonObj["url"]!!.jsonPrimitive.content
|
||||
}
|
||||
|
||||
override fun mangaDetailsParse(document: Document): SManga {
|
||||
|
@ -365,7 +358,7 @@ class Japscan : ConfigurableSource, ParsedHttpSource() {
|
|||
val checkNew = ArrayList<String>(pagecount)
|
||||
var maxIter = document.getElementsByTag("option").size
|
||||
var isSinglePage = false
|
||||
if ((zjs.toLowerCase().split("new image").size - 1) == 1) {
|
||||
if ((zjs.toLowerCase(Locale.ROOT).split("new image").size - 1) == 1) {
|
||||
isSinglePage = true
|
||||
maxIter = 1
|
||||
}
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlinx-serialization'
|
||||
|
||||
ext {
|
||||
extName = 'Scan-Manga'
|
||||
pkgNameSuffix = 'fr.scanmanga'
|
||||
extClass = '.ScanManga'
|
||||
extVersionCode = 4
|
||||
extVersionCode = 5
|
||||
libVersion = '1.2'
|
||||
containsNsfw = true
|
||||
}
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
package eu.kanade.tachiyomi.extension.fr.scanmanga
|
||||
|
||||
import com.github.salomonbrys.kotson.get
|
||||
import com.github.salomonbrys.kotson.string
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.JsonParser
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
|
@ -13,6 +9,10 @@ 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 kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.jsonArray
|
||||
import kotlinx.serialization.json.jsonObject
|
||||
import kotlinx.serialization.json.jsonPrimitive
|
||||
import okhttp3.Headers
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
|
@ -21,6 +21,7 @@ import org.jsoup.nodes.Document
|
|||
import org.jsoup.nodes.Element
|
||||
import org.jsoup.parser.Parser
|
||||
import rx.Observable
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import kotlin.random.Random
|
||||
|
||||
class ScanManga : ParsedHttpSource() {
|
||||
|
@ -44,7 +45,7 @@ class ScanManga : ParsedHttpSource() {
|
|||
chain.proceed(newReq)
|
||||
}.build()!!
|
||||
|
||||
private val gson = Gson()
|
||||
private val json: Json by injectLazy()
|
||||
|
||||
override fun headersBuilder(): Headers.Builder = super.headersBuilder()
|
||||
.add("Accept-Language", "fr-FR")
|
||||
|
@ -93,7 +94,7 @@ class ScanManga : ParsedHttpSource() {
|
|||
|
||||
override fun searchMangaParse(response: Response): MangasPage = parseMangaFromJson(response)
|
||||
|
||||
fun shuffle(s: String?): String? {
|
||||
private fun shuffle(s: String?): String {
|
||||
val result = StringBuffer(s!!)
|
||||
var n = result.length
|
||||
while (n > 1) {
|
||||
|
@ -106,10 +107,11 @@ class ScanManga : ParsedHttpSource() {
|
|||
}
|
||||
|
||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
||||
val searchHeaders = headersBuilder().apply {
|
||||
add("Referer", "$baseUrl/scanlation/liste_series.html")
|
||||
add("x-requested-with", "XMLHttpRequest")
|
||||
}.build()
|
||||
val searchHeaders = headersBuilder()
|
||||
.add("Referer", "$baseUrl/scanlation/liste_series.html")
|
||||
.add("x-requested-with", "XMLHttpRequest")
|
||||
.build()
|
||||
|
||||
return GET("$baseUrl/scanlation/scan.data.json", searchHeaders)
|
||||
}
|
||||
|
||||
|
@ -126,58 +128,58 @@ class ScanManga : ParsedHttpSource() {
|
|||
}
|
||||
|
||||
private fun parseMangaFromJson(response: Response): MangasPage {
|
||||
val jsonData = response.body!!.string()!!
|
||||
if (jsonData == "") {
|
||||
return MangasPage(listOf<SManga>(), false)
|
||||
val jsonRaw = response.body!!.string()
|
||||
|
||||
if (jsonRaw.isEmpty()) {
|
||||
return MangasPage(emptyList(), hasNextPage = false)
|
||||
}
|
||||
|
||||
val jsonObject = JsonParser().parse(jsonData).asJsonObject
|
||||
val jsonObj = json.parseToJsonElement(jsonRaw).jsonObject
|
||||
|
||||
val mangas = jsonObject.keySet()
|
||||
.map { key ->
|
||||
// "95","%24100-is-Too-Cheap","0","3","One Shot","","2 avril 2010","","335","178","4010",""
|
||||
SManga.create().apply {
|
||||
url = "/" + jsonObject[key][0].string + "/" + jsonObject[key][1].string + ".html"
|
||||
title = Parser.unescapeEntities(key, false)
|
||||
genre = jsonObject[key][2].string.let {
|
||||
when {
|
||||
it.contains("0") -> "Shōnen"
|
||||
it.contains("1") -> "Shōjo"
|
||||
it.contains("2") -> "Seinen"
|
||||
it.contains("3") -> "Josei"
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
status = jsonObject[key][3].string.let {
|
||||
when {
|
||||
it.contains("0") -> SManga.ONGOING // En cours
|
||||
it.contains("1") -> SManga.ONGOING // En pause
|
||||
it.contains("2") -> SManga.COMPLETED // Terminé
|
||||
it.contains("3") -> SManga.COMPLETED // One shot
|
||||
else -> SManga.UNKNOWN
|
||||
}
|
||||
val mangaList = jsonObj.entries.map { entry ->
|
||||
SManga.create().apply {
|
||||
title = Parser.unescapeEntities(entry.key, false)
|
||||
genre = entry.value.jsonArray[2].jsonPrimitive.content.let {
|
||||
when {
|
||||
it.contains("0") -> "Shōnen"
|
||||
it.contains("1") -> "Shōjo"
|
||||
it.contains("2") -> "Seinen"
|
||||
it.contains("3") -> "Josei"
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
status = entry.value.jsonArray[3].jsonPrimitive.content.let {
|
||||
when {
|
||||
it.contains("0") -> SManga.ONGOING // En cours
|
||||
it.contains("1") -> SManga.ONGOING // En pause
|
||||
it.contains("2") -> SManga.COMPLETED // Terminé
|
||||
it.contains("3") -> SManga.COMPLETED // One shot
|
||||
else -> SManga.UNKNOWN
|
||||
}
|
||||
}
|
||||
url = "/" + entry.value.jsonArray[0].jsonPrimitive.content + "/" +
|
||||
entry.value.jsonArray[1].jsonPrimitive.content + ".html"
|
||||
}
|
||||
}
|
||||
|
||||
return MangasPage(mangas, false)
|
||||
return MangasPage(mangaList, hasNextPage = false)
|
||||
}
|
||||
|
||||
override fun searchMangaSelector() = throw UnsupportedOperationException("Not used")
|
||||
|
||||
// Details
|
||||
override fun mangaDetailsParse(document: Document): SManga {
|
||||
return SManga.create().apply {
|
||||
title = document.select("h2[itemprop=\"name\"]").text()
|
||||
author = document.select("li[itemprop=\"author\"] a").joinToString { it.text() }
|
||||
description = document.select("p[itemprop=\"description\"]").text()
|
||||
thumbnail_url = document.select(".contenu_fiche_technique .image_manga img").attr("src")
|
||||
}
|
||||
override fun mangaDetailsParse(document: Document): SManga = SManga.create().apply {
|
||||
title = document.select("h2[itemprop=\"name\"]").text()
|
||||
author = document.select("li[itemprop=\"author\"] a").joinToString { it.text() }
|
||||
description = document.select("p[itemprop=\"description\"]").text()
|
||||
thumbnail_url = document.select(".contenu_fiche_technique .image_manga img").attr("src")
|
||||
}
|
||||
|
||||
// Chapters
|
||||
override fun chapterListSelector() = throw Exception("Not used")
|
||||
|
||||
override fun chapterFromElement(element: Element): SChapter = throw Exception("Not used")
|
||||
|
||||
override fun chapterListParse(response: Response): List<SChapter> {
|
||||
val document = response.asJsoup()
|
||||
|
||||
|
@ -207,9 +209,10 @@ class ScanManga : ParsedHttpSource() {
|
|||
override fun imageUrlParse(document: Document): String = throw UnsupportedOperationException("Not Used")
|
||||
|
||||
override fun imageRequest(page: Page): Request {
|
||||
val imgHeaders = headersBuilder().apply {
|
||||
add("Referer", page.url)
|
||||
}.build()
|
||||
val imgHeaders = headersBuilder()
|
||||
.add("Referer", page.url)
|
||||
.build()
|
||||
|
||||
return GET(page.imageUrl!!, imgHeaders)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlinx-serialization'
|
||||
|
||||
ext {
|
||||
extName = 'DigitalTeam'
|
||||
pkgNameSuffix = 'it.digitalteam'
|
||||
extClass = '.DigitalTeam'
|
||||
extVersionCode = 1
|
||||
extVersionCode = 2
|
||||
libVersion = '1.2'
|
||||
containsNsfw = false
|
||||
}
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
package eu.kanade.tachiyomi.extension.it.digitalteam
|
||||
|
||||
import com.github.salomonbrys.kotson.string
|
||||
import com.google.gson.JsonParser
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.POST
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
|
@ -10,12 +8,18 @@ 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 kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.jsonArray
|
||||
import kotlinx.serialization.json.jsonObject
|
||||
import kotlinx.serialization.json.jsonPrimitive
|
||||
import okhttp3.FormBody
|
||||
import okhttp3.Headers
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okhttp3.RequestBody
|
||||
import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.text.ParseException
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
|
@ -23,117 +27,152 @@ import java.util.Locale
|
|||
class DigitalTeam : ParsedHttpSource() {
|
||||
|
||||
override val name = "DigitalTeam"
|
||||
|
||||
override val baseUrl = "https://dgtread.com"
|
||||
|
||||
override val lang = "it"
|
||||
|
||||
override val supportsLatest = false
|
||||
|
||||
override val client: OkHttpClient = network.cloudflareClient
|
||||
|
||||
private val json: Json by injectLazy()
|
||||
|
||||
override fun popularMangaRequest(page: Int): Request {
|
||||
return GET("$baseUrl/reader/series", headers)
|
||||
}
|
||||
override fun latestUpdatesRequest(page: Int): Request = popularMangaRequest(page)
|
||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request = throw Exception("La ricerca è momentaneamente disabilitata.")
|
||||
|
||||
// LIST SELECTOR
|
||||
override fun latestUpdatesRequest(page: Int): Request = popularMangaRequest(page)
|
||||
|
||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request =
|
||||
throw Exception("La ricerca è momentaneamente disabilitata.")
|
||||
|
||||
// LIST SELECTOR
|
||||
override fun popularMangaSelector() = "ul li.manga_block"
|
||||
|
||||
override fun latestUpdatesSelector() = popularMangaSelector()
|
||||
|
||||
override fun searchMangaSelector() = popularMangaSelector()
|
||||
|
||||
// ELEMENT
|
||||
override fun popularMangaFromElement(element: Element): SManga {
|
||||
val manga = SManga.create()
|
||||
manga.thumbnail_url = element.select("img").attr("src")
|
||||
manga.setUrlWithoutDomain(element.select(".manga_title a").first().attr("href"))
|
||||
manga.title = element.select(".manga_title a").text()
|
||||
return manga
|
||||
// ELEMENT
|
||||
override fun popularMangaFromElement(element: Element): SManga = SManga.create().apply {
|
||||
title = element.select(".manga_title a").text()
|
||||
thumbnail_url = element.select("img").attr("src")
|
||||
setUrlWithoutDomain(element.select(".manga_title a").first().attr("href"))
|
||||
}
|
||||
|
||||
override fun searchMangaFromElement(element: Element): SManga = throw Exception("Not Used")
|
||||
|
||||
override fun latestUpdatesFromElement(element: Element): SManga = throw Exception("Not Used")
|
||||
|
||||
// NEXT SELECTOR
|
||||
// NEXT SELECTOR
|
||||
// Not needed
|
||||
override fun popularMangaNextPageSelector(): String? = null
|
||||
override fun latestUpdatesNextPageSelector() = popularMangaNextPageSelector()
|
||||
override fun searchMangaNextPageSelector() = popularMangaNextPageSelector()
|
||||
// ////////////////
|
||||
|
||||
override fun mangaDetailsParse(document: Document): SManga {
|
||||
override fun latestUpdatesNextPageSelector() = popularMangaNextPageSelector()
|
||||
|
||||
override fun searchMangaNextPageSelector() = popularMangaNextPageSelector()
|
||||
|
||||
override fun mangaDetailsParse(document: Document): SManga = SManga.create().apply{
|
||||
val infoElement = document.select("#manga_left")
|
||||
val manga = SManga.create()
|
||||
manga.author = infoElement.select(".info_name:contains(Autore)").next()?.text()
|
||||
manga.artist = infoElement.select(".info_name:contains(Artista)").next()?.text()
|
||||
manga.genre = infoElement.select(".info_name:contains(Genere)").next()?.text()
|
||||
manga.status = parseStatus(infoElement.select(".info_name:contains(Status)").next().text())
|
||||
manga.description = document.select("div.plot")?.text()
|
||||
manga.thumbnail_url = infoElement.select(".cover img").attr("src")
|
||||
return manga
|
||||
|
||||
author = infoElement.select(".info_name:contains(Autore)").next()?.text()
|
||||
artist = infoElement.select(".info_name:contains(Artista)").next()?.text()
|
||||
genre = infoElement.select(".info_name:contains(Genere)").next()?.text()
|
||||
status = parseStatus(infoElement.select(".info_name:contains(Status)").next().text())
|
||||
description = document.select("div.plot")?.text()
|
||||
thumbnail_url = infoElement.select(".cover img").attr("src")
|
||||
}
|
||||
|
||||
private fun parseStatus(element: String): Int = when {
|
||||
element.toLowerCase().contains("in corso") -> SManga.ONGOING
|
||||
element.toLowerCase().contains("completo") -> SManga.COMPLETED
|
||||
element.toLowerCase(Locale.ROOT).contains("in corso") -> SManga.ONGOING
|
||||
element.toLowerCase(Locale.ROOT).contains("completo") -> SManga.COMPLETED
|
||||
else -> SManga.UNKNOWN
|
||||
}
|
||||
|
||||
override fun chapterListSelector() = ".chapter_list ul li"
|
||||
|
||||
override fun chapterFromElement(element: Element): SChapter {
|
||||
override fun chapterFromElement(element: Element): SChapter = SChapter.create().apply {
|
||||
val urlElement = element.select("a").first()
|
||||
val chapter = SChapter.create()
|
||||
chapter.setUrlWithoutDomain(urlElement.attr("href"))
|
||||
chapter.name = urlElement.text()
|
||||
chapter.date_upload = element.select(".ch_bottom").first()?.text()?.replace("Pubblicato il ", "")?.let {
|
||||
try {
|
||||
SimpleDateFormat("dd-MM-yyyy", Locale.ITALY).parse(it).time
|
||||
} catch (e: ParseException) {
|
||||
SimpleDateFormat("H", Locale.ITALY).parse(it).time
|
||||
}
|
||||
} ?: 0
|
||||
return chapter
|
||||
|
||||
setUrlWithoutDomain(urlElement.attr("href"))
|
||||
name = urlElement.text()
|
||||
date_upload = element.select(".ch_bottom").first()?.text()
|
||||
?.replace("Pubblicato il ", "")
|
||||
?.let {
|
||||
try {
|
||||
DATE_FORMAT_FULL.parse(it)?.time
|
||||
} catch (e: ParseException) {
|
||||
DATE_FORMAT_SIMPLE.parse(it)?.time
|
||||
}
|
||||
} ?: 0
|
||||
}
|
||||
|
||||
protected fun getXhrPages(script_content: String, title: String): String {
|
||||
val xhrHeaders = headersBuilder().add("Content-Type: application/x-www-form-urlencoded; charset=UTF-8")
|
||||
private fun getXhrPages(script_content: String, title: String): String {
|
||||
val infoManga = script_content.substringAfter("m='").substringBefore("'")
|
||||
val infoChapter = script_content.substringAfter("ch='").substringBefore("'")
|
||||
val infoChSub = script_content.substringAfter("chs='").substringBefore("'")
|
||||
|
||||
val formBody = FormBody.Builder()
|
||||
.add("info[manga]", infoManga)
|
||||
.add("info[chapter]", infoChapter)
|
||||
.add("info[ch_sub]", infoChSub)
|
||||
.add("info[title]", title)
|
||||
.build()
|
||||
|
||||
// This can be improved, i don't know how to do it with Regex
|
||||
var infomanga = script_content.substringAfter("m='").substringBefore("'")
|
||||
var infochapter = script_content.substringAfter("ch='").substringBefore("'")
|
||||
var infoch_sub = script_content.substringAfter("chs='").substringBefore("'")
|
||||
val body = RequestBody.create(null, "info[manga]=$infomanga&info[chapter]=$infochapter&info[ch_sub]=$infoch_sub&info[title]=$title")
|
||||
return client.newCall(POST("$baseUrl/reader/c_i", xhrHeaders, body))
|
||||
.execute()
|
||||
.asJsoup().select("body").text()
|
||||
.replace("\\", "").removeSurrounding("\"")
|
||||
val xhrHeaders = headersBuilder()
|
||||
.add("Content-Length", formBody.contentLength().toString())
|
||||
.add("Content-Type", formBody.contentType().toString())
|
||||
.build()
|
||||
|
||||
val request = POST("$baseUrl/reader/c_i", xhrHeaders, formBody)
|
||||
val response = client.newCall(request).execute()
|
||||
|
||||
return response.asJsoup()
|
||||
.select("body")
|
||||
.text()
|
||||
.replace("\\", "")
|
||||
.removeSurrounding("\"")
|
||||
}
|
||||
|
||||
override fun pageListParse(document: Document): List<Page> {
|
||||
val pages = mutableListOf<Page>()
|
||||
val script_content = document.body()!!.toString().substringAfter("current_page=").substringBefore(";")
|
||||
val scriptContent = document.body().toString()
|
||||
.substringAfter("current_page=")
|
||||
.substringBefore(";")
|
||||
val title = document.select("title").first().text()
|
||||
val imagesJsonList = JsonParser().parse(getXhrPages(script_content, title)).asJsonArray
|
||||
val image_url = imagesJsonList.get(2).string
|
||||
val images_name = imagesJsonList.get(1).asJsonArray
|
||||
val images_data = imagesJsonList.get(0).asJsonArray
|
||||
images_name.forEachIndexed { index, imagename ->
|
||||
val imageUrl =
|
||||
"$baseUrl/reader$image_url" +
|
||||
"${images_data.get(index).asJsonObject.get("name").string}" +
|
||||
"${imagename.string}" +
|
||||
"${images_data.get(index).asJsonObject.get("ex").string}"
|
||||
pages.add(Page(index, "", imageUrl))
|
||||
|
||||
val xhrPages = getXhrPages(scriptContent, title)
|
||||
val jsonResult = json.parseToJsonElement(xhrPages).jsonArray
|
||||
|
||||
val imageData = jsonResult[0].jsonArray
|
||||
val imagePath = jsonResult[2].jsonPrimitive.content
|
||||
|
||||
return jsonResult[1].jsonArray.mapIndexed { i, jsonEl ->
|
||||
val imageUrl = "$baseUrl/reader$imagePath" +
|
||||
imageData[i].jsonObject["name"]!!.jsonPrimitive.content +
|
||||
jsonEl.jsonPrimitive.content +
|
||||
imageData[i].jsonObject["ex"]!!.jsonPrimitive.content
|
||||
|
||||
Page(i, "", imageUrl)
|
||||
}
|
||||
return pages
|
||||
}
|
||||
|
||||
override fun imageUrlParse(document: Document) = ""
|
||||
|
||||
override fun imageRequest(page: Page): Request {
|
||||
val imgHeader = Headers.Builder().apply {
|
||||
add("User-Agent", "Mozilla/5.0 (Linux; U; Android 4.1.1; en-gb; Build/KLP) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30")
|
||||
add("Referer", baseUrl)
|
||||
}.build()
|
||||
val imgHeader = Headers.Builder()
|
||||
.add("User-Agent", USER_AGENT)
|
||||
.add("Referer", baseUrl)
|
||||
.build()
|
||||
|
||||
return GET(page.imageUrl!!, imgHeader)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val USER_AGENT = "Mozilla/5.0 (Linux; U; Android 4.1.1; en-gb; Build/KLP) " +
|
||||
"AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30"
|
||||
|
||||
private val DATE_FORMAT_FULL = SimpleDateFormat("dd-MM-yyyy", Locale.ITALY)
|
||||
private val DATE_FORMAT_SIMPLE = SimpleDateFormat("H", Locale.ITALY)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlinx-serialization'
|
||||
|
||||
ext {
|
||||
extName = 'Mangahub'
|
||||
pkgNameSuffix = 'ru.mangahub'
|
||||
extClass = '.Mangahub'
|
||||
extVersionCode = 9
|
||||
extVersionCode = 10
|
||||
libVersion = '1.2'
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package eu.kanade.tachiyomi.extension.ru.mangahub
|
||||
|
||||
import com.google.gson.JsonParser
|
||||
import eu.kanade.tachiyomi.lib.ratelimit.RateLimitInterceptor
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
|
@ -8,11 +7,16 @@ 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 kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.jsonArray
|
||||
import kotlinx.serialization.json.jsonObject
|
||||
import kotlinx.serialization.json.jsonPrimitive
|
||||
import okhttp3.Headers
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
|
||||
|
@ -26,12 +30,11 @@ open class Mangahub : ParsedHttpSource() {
|
|||
|
||||
override val supportsLatest = true
|
||||
|
||||
private val rateLimitInterceptor = RateLimitInterceptor(2)
|
||||
|
||||
private val jsonParser = JsonParser()
|
||||
|
||||
override val client: OkHttpClient = network.client.newBuilder()
|
||||
.addNetworkInterceptor(rateLimitInterceptor).build()
|
||||
.addNetworkInterceptor(RateLimitInterceptor(2))
|
||||
.build()
|
||||
|
||||
private val json: Json by injectLazy()
|
||||
|
||||
override fun popularMangaRequest(page: Int): Request =
|
||||
GET("$baseUrl/explore?filter[sort]=rating&filter[dateStart][left_number]=1900&filter[dateStart][right_number]=2099&page=$page", headers)
|
||||
|
@ -114,25 +117,25 @@ open class Mangahub : ParsedHttpSource() {
|
|||
}
|
||||
|
||||
override fun pageListParse(document: Document): List<Page> {
|
||||
val chapInfo = document.select("reader").attr("data-store").replace(""", "\"").replace("\\/", "/")
|
||||
val chapter = jsonParser.parse(chapInfo).asJsonObject
|
||||
val scans = chapter["scans"].asJsonArray
|
||||
val chapInfo = document.select("reader")
|
||||
.attr("data-store")
|
||||
.replace(""", "\"")
|
||||
.replace("\\/", "/")
|
||||
val chapter = json.parseToJsonElement(chapInfo).jsonObject
|
||||
|
||||
val pages = mutableListOf<Page>()
|
||||
scans.mapIndexed { i, page ->
|
||||
pages.add(Page(i, "", "https:${page.asJsonObject.get("src").asString}"))
|
||||
return chapter["scans"]!!.jsonArray.mapIndexed { i, jsonEl ->
|
||||
Page(i, "", "https:" + jsonEl.jsonObject["src"]!!.jsonPrimitive.content)
|
||||
}
|
||||
|
||||
return pages
|
||||
}
|
||||
|
||||
override fun imageUrlParse(document: Document) = ""
|
||||
|
||||
override fun imageRequest(page: Page): Request {
|
||||
val imgHeader = Headers.Builder().apply {
|
||||
add("User-Agent", "Mozilla/5.0 (Windows NT 6.3; WOW64)")
|
||||
add("Referer", baseUrl)
|
||||
}.build()
|
||||
val imgHeader = Headers.Builder()
|
||||
.add("User-Agent", "Mozilla/5.0 (Windows NT 6.3; WOW64)")
|
||||
.add("Referer", baseUrl)
|
||||
.build()
|
||||
|
||||
return GET(page.imageUrl!!, imgHeader)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlinx-serialization'
|
||||
|
||||
ext {
|
||||
extName = 'BH3'
|
||||
pkgNameSuffix = 'zh.bh3'
|
||||
extClass = '.BH3'
|
||||
extVersionCode = 2
|
||||
extVersionCode = 3
|
||||
libVersion = '1.2'
|
||||
}
|
||||
|
||||
|
|
|
@ -1,22 +1,23 @@
|
|||
package eu.kanade.tachiyomi.extension.zh.bh3
|
||||
|
||||
import com.github.salomonbrys.kotson.float
|
||||
import com.github.salomonbrys.kotson.get
|
||||
import com.github.salomonbrys.kotson.int
|
||||
import com.github.salomonbrys.kotson.string
|
||||
import com.google.gson.JsonElement
|
||||
import com.google.gson.JsonParser
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
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 kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.JsonObject
|
||||
import kotlinx.serialization.json.float
|
||||
import kotlinx.serialization.json.int
|
||||
import kotlinx.serialization.json.jsonArray
|
||||
import kotlinx.serialization.json.jsonObject
|
||||
import kotlinx.serialization.json.jsonPrimitive
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Response
|
||||
import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
@ -24,35 +25,48 @@ import java.util.concurrent.TimeUnit
|
|||
class BH3 : ParsedHttpSource() {
|
||||
|
||||
override val name = "《崩坏3》IP站"
|
||||
|
||||
override val baseUrl = "https://comic.bh3.com"
|
||||
|
||||
override val lang = "zh"
|
||||
|
||||
override val supportsLatest = false
|
||||
|
||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
.connectTimeout(1, TimeUnit.MINUTES)
|
||||
.readTimeout(1, TimeUnit.MINUTES)
|
||||
.retryOnConnectionFailure(true)
|
||||
.followRedirects(true)
|
||||
.build()!!
|
||||
.build()
|
||||
|
||||
private val json: Json by injectLazy()
|
||||
|
||||
override fun popularMangaSelector() = "a[href*=book]"
|
||||
override fun latestUpdatesSelector() = throw Exception("Not Used")
|
||||
override fun searchMangaSelector() = throw Exception("Not Used")
|
||||
override fun chapterListSelector() = throw Exception("Not Used")
|
||||
|
||||
override fun popularMangaNextPageSelector() = "none"
|
||||
override fun latestUpdatesNextPageSelector() = "none"
|
||||
override fun searchMangaNextPageSelector() = "none"
|
||||
override fun latestUpdatesSelector() = ""
|
||||
|
||||
override fun searchMangaSelector() = ""
|
||||
|
||||
override fun chapterListSelector() = ""
|
||||
|
||||
override fun popularMangaNextPageSelector(): String? = null
|
||||
|
||||
override fun latestUpdatesNextPageSelector(): String? = null
|
||||
|
||||
override fun searchMangaNextPageSelector(): String? = null
|
||||
|
||||
override fun popularMangaRequest(page: Int) = GET("$baseUrl/book", headers)
|
||||
|
||||
override fun latestUpdatesRequest(page: Int) = throw Exception("Not Used")
|
||||
|
||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList) = throw Exception("No search")
|
||||
|
||||
// override fun mangaDetailsRequest(manga: SManga) = GET(baseUrl + manga.url, headers)
|
||||
// override fun pageListRequest(chapter: SChapter) = GET(baseUrl + chapter.url, headers)
|
||||
override fun chapterListRequest(manga: SManga) = GET(baseUrl + manga.url + "/get_chapter", headers)
|
||||
|
||||
override fun popularMangaFromElement(element: Element) = mangaFromElement(element)
|
||||
|
||||
override fun latestUpdatesFromElement(element: Element) = mangaFromElement(element)
|
||||
|
||||
override fun searchMangaFromElement(element: Element) = mangaFromElement(element)
|
||||
|
||||
private fun mangaFromElement(element: Element): SManga {
|
||||
|
@ -66,41 +80,33 @@ class BH3 : ParsedHttpSource() {
|
|||
override fun chapterFromElement(element: Element) = throw Exception("Not Used")
|
||||
|
||||
override fun chapterListParse(response: Response): List<SChapter> {
|
||||
val jsondata = response.body!!.string()
|
||||
val json = JsonParser().parse(jsondata).asJsonArray
|
||||
val chapters = mutableListOf<SChapter>()
|
||||
json.forEach {
|
||||
chapters.add(createChapter(it))
|
||||
}
|
||||
return chapters
|
||||
val jsonResult = json.parseToJsonElement(response.body!!.string()).jsonArray
|
||||
|
||||
return jsonResult.map { jsonEl -> createChapter(jsonEl.jsonObject) }
|
||||
}
|
||||
|
||||
private fun createChapter(json: JsonElement) = SChapter.create().apply {
|
||||
name = json["title"].string
|
||||
url = "/book/${json["bookid"].int}/${json["chapterid"].int}"
|
||||
date_upload = parseDate(json["timestamp"].string)
|
||||
chapter_number = json["chapterid"].float
|
||||
private fun createChapter(jsonObj: JsonObject) = SChapter.create().apply {
|
||||
name = jsonObj["title"]!!.jsonPrimitive.content
|
||||
url = "/book/${jsonObj["bookid"]!!.jsonPrimitive.int}/${jsonObj["chapterid"]!!.jsonPrimitive.int}"
|
||||
date_upload = parseDate(jsonObj["timestamp"]!!.jsonPrimitive.content)
|
||||
chapter_number = jsonObj["chapterid"]!!.jsonPrimitive.float
|
||||
}
|
||||
|
||||
private fun parseDate(date: String): Long {
|
||||
return SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US).parse(date)?.time ?: 0L
|
||||
}
|
||||
|
||||
override fun mangaDetailsParse(document: Document): SManga {
|
||||
val manga = SManga.create()
|
||||
manga.thumbnail_url = document.select("img.cover").attr("abs:src")
|
||||
manga.description = document.select("div.detail_info1").text().trim()
|
||||
manga.title = document.select("div.title").text().trim()
|
||||
return manga
|
||||
override fun mangaDetailsParse(document: Document): SManga = SManga.create().apply {
|
||||
thumbnail_url = document.select("img.cover").attr("abs:src")
|
||||
description = document.select("div.detail_info1").text().trim()
|
||||
title = document.select("div.title").text().trim()
|
||||
}
|
||||
|
||||
override fun pageListParse(response: Response): List<Page> = mutableListOf<Page>().apply {
|
||||
val body = response.asJsoup()
|
||||
body.select("img.lazy.comic_img")?.forEach {
|
||||
add(Page(size, "", it.attr("data-original")))
|
||||
override fun pageListParse(document: Document): List<Page> {
|
||||
return document.select("img.lazy.comic_img").mapIndexed { i, el ->
|
||||
Page(i, "", el.attr("data-original"))
|
||||
}
|
||||
}
|
||||
|
||||
override fun pageListParse(document: Document) = throw Exception("Not Used")
|
||||
override fun imageUrlParse(document: Document) = throw Exception("Not Used")
|
||||
override fun imageUrlParse(document: Document) = ""
|
||||
}
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlinx-serialization'
|
||||
|
||||
ext {
|
||||
extName = 'Qimiaomh'
|
||||
pkgNameSuffix = 'zh.qimiaomh'
|
||||
extClass = '.Qimiaomh'
|
||||
extVersionCode = 1
|
||||
extVersionCode = 2
|
||||
libVersion = '1.2'
|
||||
}
|
||||
|
||||
|
|
|
@ -1,40 +1,53 @@
|
|||
package eu.kanade.tachiyomi.extension.zh.qimiaomh
|
||||
|
||||
import com.github.salomonbrys.kotson.string
|
||||
import com.google.gson.JsonParser
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
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 kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.jsonArray
|
||||
import kotlinx.serialization.json.jsonObject
|
||||
import kotlinx.serialization.json.jsonPrimitive
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
import java.util.Random
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class Qimiaomh : ParsedHttpSource() {
|
||||
|
||||
override val name: String = "奇妙漫画"
|
||||
|
||||
override val lang: String = "zh"
|
||||
|
||||
override val baseUrl: String = "https://www.qimiaomh.com"
|
||||
|
||||
override val supportsLatest: Boolean = true
|
||||
|
||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
.connectTimeout(1, TimeUnit.MINUTES)
|
||||
.readTimeout(1, TimeUnit.MINUTES)
|
||||
.retryOnConnectionFailure(true)
|
||||
.followRedirects(true)
|
||||
.build()!!
|
||||
.build()
|
||||
|
||||
private val json: Json by injectLazy()
|
||||
|
||||
// Popular
|
||||
override fun popularMangaRequest(page: Int): Request {
|
||||
return GET("$baseUrl/list-1------hits--$page.html", headers)
|
||||
}
|
||||
|
||||
override fun popularMangaNextPageSelector(): String? = "a:contains(下一页)"
|
||||
|
||||
override fun popularMangaSelector(): String = "div.classification"
|
||||
|
||||
override fun popularMangaFromElement(element: Element): SManga = SManga.create().apply {
|
||||
url = element.select("a").first().attr("href")
|
||||
thumbnail_url = element.select("img.lazyload").attr("abs:data-src")
|
||||
|
@ -45,8 +58,11 @@ class Qimiaomh : ParsedHttpSource() {
|
|||
override fun latestUpdatesRequest(page: Int): Request {
|
||||
return GET("$baseUrl/list-1------updatetime--$page.html", headers)
|
||||
}
|
||||
|
||||
override fun latestUpdatesNextPageSelector(): String? = popularMangaNextPageSelector()
|
||||
|
||||
override fun latestUpdatesSelector(): String = popularMangaSelector()
|
||||
|
||||
override fun latestUpdatesFromElement(element: Element): SManga = popularMangaFromElement(element)
|
||||
|
||||
// Search
|
||||
|
@ -54,8 +70,11 @@ class Qimiaomh : ParsedHttpSource() {
|
|||
throw Exception("不管用 (T_T)")
|
||||
// Todo Filters
|
||||
}
|
||||
|
||||
override fun searchMangaNextPageSelector(): String? = popularMangaNextPageSelector()
|
||||
|
||||
override fun searchMangaSelector(): String = popularMangaSelector()
|
||||
|
||||
override fun searchMangaFromElement(element: Element): SManga = popularMangaFromElement(element)
|
||||
|
||||
// Details
|
||||
|
@ -78,31 +97,31 @@ class Qimiaomh : ParsedHttpSource() {
|
|||
// Chapters
|
||||
|
||||
override fun chapterListSelector(): String = "div.comic-content-list ul.comic-content-c"
|
||||
|
||||
override fun chapterFromElement(element: Element): SChapter = SChapter.create().apply {
|
||||
url = element.select("a").first().attr("href")
|
||||
name = element.select("li.tit").text().trim()
|
||||
}
|
||||
|
||||
private fun parseDate(date: String): Long {
|
||||
return SimpleDateFormat("dd/MM/yyyy", Locale.US).parse(date)?.time ?: 0L
|
||||
}
|
||||
|
||||
// Pages
|
||||
|
||||
override fun pageListParse(document: Document): List<Page> = mutableListOf<Page>().apply {
|
||||
override fun pageListParse(document: Document): List<Page> {
|
||||
val script = document.select("script:containsData(var did =)").html()
|
||||
val did = script.substringAfter("var did = ").substringBefore(";")
|
||||
val sid = script.substringAfter("var sid = ").substringBefore(";")
|
||||
|
||||
val url = "$baseUrl/Action/Play/AjaxLoadImgUrl?did=$did&sid=$sid&tmp=${Random().nextFloat()}"
|
||||
val body = client.newCall(GET(url, headers)).execute().body!!.string()
|
||||
val json = JsonParser().parse(body).asJsonObject
|
||||
val images = json["listImg"].asJsonArray
|
||||
images.forEachIndexed { index, jsonElement ->
|
||||
add(Page(index, "", jsonElement.string))
|
||||
val response = client.newCall(GET(url, headers)).execute()
|
||||
val result = json.parseToJsonElement(response.body!!.string()).jsonObject
|
||||
|
||||
return result["listImg"]!!.jsonArray.mapIndexed { i, jsonEl ->
|
||||
Page(i, "", jsonEl.jsonPrimitive.content)
|
||||
}
|
||||
}
|
||||
override fun imageUrlParse(document: Document): String {
|
||||
throw Exception("Not Used")
|
||||
}
|
||||
|
||||
// Not Used
|
||||
override fun imageUrlParse(document: Document): String = ""
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue