Replace org.json in PizzaReader. (#8645)

This commit is contained in:
Alessandro Jean 2021-08-19 06:57:58 -03:00 committed by GitHub
parent e5d55d91b5
commit 38f2f4a767
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 152 additions and 148 deletions

View File

@ -8,23 +8,31 @@ 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.decodeFromString
import kotlinx.serialization.json.Json
import okhttp3.Headers
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.Request
import okhttp3.Response
import org.json.JSONObject
import rx.Observable
import uy.kohesive.injekt.injectLazy
import java.text.SimpleDateFormat
import java.util.Locale
abstract class PizzaReader(
override val name: String,
override val baseUrl: String,
override val lang: String,
private val apiPath: String = "/api"
private val apiPath: String = "/api",
private val dateParser: SimpleDateFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSSSS", Locale.ITALY)
) : HttpSource() {
override val supportsLatest = true
open val apiUrl by lazy { "$baseUrl$apiPath" }
protected open val json: Json by injectLazy()
override fun headersBuilder() = Headers.Builder().apply {
add("Referer", baseUrl)
}
@ -32,72 +40,106 @@ abstract class PizzaReader(
override fun popularMangaRequest(page: Int) =
GET("$apiUrl/comics", headers)
override fun popularMangaParse(response: Response) =
MangasPage(
JSONObject(response.asString()).run {
val arr = getJSONArray("comics")
(0 until arr.length()).map {
SManga.create().fromJSON(arr.getJSONObject(it))
}
},
false
)
override fun popularMangaParse(response: Response): MangasPage {
val result = json.decodeFromString<PizzaResultsDto>(response.body!!.string())
override fun searchMangaRequest(page: Int, query: String, filters: FilterList) =
GET("$apiUrl/search/$query", headers)
val comicList = result.comics
.map(::popularMangaFromObject)
override fun searchMangaParse(response: Response) =
MangasPage(
JSONObject(response.asString()).run {
val arr = getJSONArray("comics")
(0 until arr.length()).map {
SManga.create().fromJSON(arr.getJSONObject(it))
}
},
false
)
return MangasPage(comicList, hasNextPage = false)
}
// TODO
override fun latestUpdatesRequest(page: Int): Request =
throw UnsupportedOperationException("Not used")
protected open fun popularMangaFromObject(comic: PizzaComicDto): SManga = SManga.create().apply {
title = comic.title
thumbnail_url = comic.thumbnail
url = comic.url
}
override fun latestUpdatesParse(response: Response): MangasPage =
throw UnsupportedOperationException("Not used")
override fun latestUpdatesRequest(page: Int): Request = popularMangaRequest(page)
override fun latestUpdatesParse(response: Response): MangasPage {
val result = json.decodeFromString<PizzaResultsDto>(response.body!!.string())
val comicList = result.comics
.filter { comic -> comic.lastChapter != null }
.sortedByDescending { comic -> comic.lastChapter!!.publishedOn }
.map(::popularMangaFromObject)
.take(10)
return MangasPage(comicList, hasNextPage = false)
}
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
val searchUrl = "$apiUrl/search/".toHttpUrl().newBuilder()
.addPathSegment(query)
.toString()
return GET(searchUrl, headers)
}
override fun searchMangaParse(response: Response) = popularMangaParse(response)
// Workaround to allow "Open in browser" to use the real URL
override fun fetchMangaDetails(manga: SManga): Observable<SManga> =
client.newCall(chapterListRequest(manga)).asObservableSuccess()
.map { mangaDetailsParse(it).apply { initialized = true } }
// Return the real URL for "Open in browser"
override fun mangaDetailsRequest(manga: SManga) =
GET("$baseUrl${manga.url}", headers)
override fun mangaDetailsParse(response: Response): SManga = SManga.create().apply {
val result = json.decodeFromString<PizzaResultDto>(response.body!!.string())
val comic = result.comic!!
override fun mangaDetailsParse(response: Response): SManga =
SManga.create().fromJSON(JSONObject(response.asString()).getJSONObject("comic"))
title = comic.title
author = comic.author
artist = comic.artist
description = comic.description
genre = comic.genres.joinToString(", ") { it.name }
status = comic.status.toStatus()
thumbnail_url = comic.thumbnail
}
override fun chapterListRequest(manga: SManga) = GET("$apiUrl${manga.url}", headers)
override fun chapterListRequest(manga: SManga) = GET(apiUrl + manga.url, headers)
override fun chapterListParse(response: Response) =
JSONObject(response.asString()).getJSONObject("comic").run {
val arr = getJSONArray("chapters")
(0 until arr.length()).map {
SChapter.create().fromJSON(arr.getJSONObject(it))
}
}
override fun chapterListParse(response: Response): List<SChapter> {
val result = json.decodeFromString<PizzaResultDto>(response.body!!.string())
val comic = result.comic!!
override fun pageListRequest(chapter: SChapter) =
GET("$apiUrl${chapter.url}", headers)
return comic.chapters
.map(::chapterFromObject)
}
override fun pageListParse(response: Response) =
JSONObject(response.asString()).getJSONObject("chapter").run {
val arr = getJSONArray("pages")
(0 until arr.length()).map {
Page(it, "", arr.getString(it))
}
}
protected open fun chapterFromObject(chapter: PizzaChapterDto): SChapter = SChapter.create().apply {
name = chapter.fullTitle
chapter_number = (chapter.chapter ?: -1).toFloat() +
("0." + (chapter.subchapter?.toString() ?: "0")).toFloat()
date_upload = chapter.publishedOn.toDate()
scanlator = chapter.teams.filterNotNull()
.joinToString(" & ") { it.name }
url = chapter.url
}
override fun imageUrlParse(response: Response): String =
throw UnsupportedOperationException("Not used")
override fun pageListRequest(chapter: SChapter) = GET(apiUrl + chapter.url, headers)
override fun pageListParse(response: Response): List<Page> {
val result = json.decodeFromString<PizzaReaderDto>(response.body!!.string())
return result.chapter!!.pages.mapIndexed { i, page -> Page(i, "", page) }
}
override fun imageUrlParse(response: Response): String = ""
protected open fun String.toDate(): Long {
return runCatching { dateParser.parse(this)?.time }
.getOrNull() ?: 0L
}
protected open fun String.toStatus(): Int = when (substring(0, 7)) {
"In cors" -> SManga.ONGOING
"On goin" -> SManga.ONGOING
"Complet" -> SManga.COMPLETED
"Conclus" -> SManga.COMPLETED
"Conclud" -> SManga.COMPLETED
"Licenzi" -> SManga.LICENSED
"License" -> SManga.LICENSED
else -> SManga.UNKNOWN
}
}

View File

@ -0,0 +1,56 @@
package eu.kanade.tachiyomi.multisrc.pizzareader
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
data class PizzaResultsDto(
val comics: List<PizzaComicDto> = emptyList()
)
@Serializable
data class PizzaResultDto(
val comic: PizzaComicDto? = null
)
@Serializable
data class PizzaReaderDto(
val chapter: PizzaChapterDto? = null,
val comic: PizzaComicDto? = null
)
@Serializable
data class PizzaComicDto(
val artist: String = "",
val author: String = "",
val chapters: List<PizzaChapterDto> = emptyList(),
val description: String = "",
val genres: List<PizzaGenreDto> = emptyList(),
@SerialName("last_chapter") val lastChapter: PizzaChapterDto? = null,
val status: String = "",
val title: String = "",
val thumbnail: String = "",
val url: String = ""
)
@Serializable
data class PizzaGenreDto(
val name: String = ""
)
@Serializable
data class PizzaChapterDto(
val chapter: Int? = null,
@SerialName("full_title") val fullTitle: String = "",
val pages: List<String> = emptyList(),
@SerialName("published_on") val publishedOn: String = "",
val subchapter: Int? = null,
val teams: List<PizzaTeamDto?> = emptyList(),
val url: String = ""
)
@Serializable
data class PizzaTeamDto(
val name: String = ""
)

View File

@ -1,94 +0,0 @@
package eu.kanade.tachiyomi.multisrc.pizzareader
import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga
import okhttp3.Response
import org.json.JSONArray
import org.json.JSONObject
import java.text.DecimalFormat
// import java.time.OffsetDateTime
import java.text.SimpleDateFormat
import java.util.Locale
/** Returns the body of a response as a `String`. */
fun Response.asString(): String = body!!.string()
/**
* Formats the number according to [fmt].
*
* @param fmt A [DecimalFormat] string.
* @return A string representation of the number.
*/
fun Number.format(fmt: String): String = DecimalFormat(fmt).format(this)
/**
* Joins each value of a given [field] of the array using [sep].
*
* @param field The index of a [JSONArray].
* When its type is [String], it is treated as the key of a [JSONObject].
* @param sep The separator used to join the array.
* @return The joined string, or `null` if the array is empty.
*/
fun JSONArray.joinField(field: Int, sep: String = ", ") =
length().takeIf { it != 0 }?.run {
(0 until this).mapNotNull {
val obj = get(it)
if (obj != null && obj.toString() != "null") getJSONArray(it).getString(field)
else null
}.joinToString(sep)
}
/**
* Joins each value of a given [field] of the array using [sep].
*
* @param field The key of a [JSONObject].
* @param sep The separator used to join the array.
* @return The joined string, or `null` if the array is empty.
*/
fun JSONArray.joinField(field: String, sep: String = ", ") =
length().takeIf { it != 0 }?.run {
(0 until this).mapNotNull {
val obj = get(it)
if (obj != null && obj.toString() != "null") getJSONObject(it).getString(field)
else null
}.joinToString(sep)
}
/**
* Creates a [SManga] by parsing a [JSONObject].
*
* @param obj The object containing the manga info.
*/
fun SManga.fromJSON(obj: JSONObject) = apply {
url = obj.getString("url")
title = obj.getString("title")
description = obj.getString("description")
thumbnail_url = obj.getString("thumbnail")
author = obj.getString("author")
artist = obj.getString("artist")
genre = obj.getJSONArray("genres").joinField("slug")
status = when (obj.getString("status").substring(0, 7)) {
"In cors" -> SManga.ONGOING
"On goin" -> SManga.ONGOING
"Complet" -> SManga.COMPLETED
"Conclus" -> SManga.COMPLETED
"Conclud" -> SManga.COMPLETED
"Licenzi" -> SManga.LICENSED
"License" -> SManga.LICENSED
else -> SManga.UNKNOWN
}
}
/**
* Creates a [SChapter] by parsing a [JSONObject].
*
* @param obj The object containing the chapter info.
*/
fun SChapter.fromJSON(obj: JSONObject) = apply {
url = obj.getString("url")
chapter_number = obj.optString("chapter", "-1").toFloat() + "0.${obj.optInt("subchapter", 0)}".toFloat()
// date_upload = OffsetDateTime.parse(obj.getString("published_on")).toEpochSecond() // API 26
date_upload = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSSSS", Locale.ITALY).parse(obj.getString("published_on"))?.time ?: 0L
scanlator = obj.getJSONArray("teams").joinField("name", " & ")
name = obj.getString("full_title")
}

View File

@ -10,7 +10,7 @@ class PizzaReaderGenerator : ThemeSourceGenerator {
override val themeClass = "PizzaReader"
override val baseVersionCode: Int = 0
override val baseVersionCode: Int = 1
override val sources = listOf(
SingleLang("Phoenix Scans", "https://www.phoenixscans.com", "it", className = "PhoenixScans", overrideVersionCode = 4),