SussyToons: Fix chapters and pages (#8804)

* Fix chapters and pages

* Bump version

* Fix chapter in webview
This commit is contained in:
Chopper 2025-05-10 16:29:45 -03:00 committed by Draff
parent db840dd353
commit 2905e17a9a
No known key found for this signature in database
GPG Key ID: E8A89F3211677653
4 changed files with 95 additions and 59 deletions

View File

@ -1,6 +1,5 @@
package eu.kanade.tachiyomi.multisrc.greenshit
import android.annotation.SuppressLint
import android.content.SharedPreferences
import android.widget.Toast
import androidx.preference.EditTextPreference
@ -18,7 +17,6 @@ import eu.kanade.tachiyomi.source.online.HttpSource
import eu.kanade.tachiyomi.util.asJsoup
import keiyoushi.utils.getPreferences
import keiyoushi.utils.parseAs
import keiyoushi.utils.tryParse
import okhttp3.HttpUrl
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.Interceptor
@ -27,8 +25,6 @@ import okhttp3.Response
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import java.io.IOException
import java.text.SimpleDateFormat
import java.util.Locale
abstract class GreenShit(
override val name: String,
@ -43,9 +39,9 @@ abstract class GreenShit(
private val preferences: SharedPreferences = getPreferences()
private var apiUrl: String
protected var apiUrl: String
get() = preferences.getString(API_BASE_URL_PREF, defaultApiUrl)!!
set(value) = preferences.edit().putString(API_BASE_URL_PREF, value).apply()
private set(value) = preferences.edit().putString(API_BASE_URL_PREF, value).apply()
private var restoreDefaultEnable: Boolean
get() = preferences.getBoolean(DEFAULT_PREF, false)
@ -152,16 +148,7 @@ abstract class GreenShit(
val json = response.parseScriptToJson().let(DETAILS_CHAPTER_REGEX::find)
?.groups?.get(0)?.value
?: return emptyList()
return json.parseAs<ResultDto<WrapperChapterDto>>().results.chapters.map {
SChapter.create().apply {
name = it.name
it.chapterNumber?.let {
chapter_number = it
}
setUrlWithoutDomain("$baseUrl/capitulo/${it.id}")
date_upload = dateFormat.tryParse(it.updateAt)
}
}.sortedByDescending(SChapter::chapter_number)
return json.parseAs<ResultDto<WrapperChapterDto>>().toSChapterList()
}
// ============================= Pages ====================================
@ -176,22 +163,7 @@ abstract class GreenShit(
val dto = extractScriptData(document)
.let(::extractJsonContent)
.let(::parseJsonToChapterPageDto)
return dto.pages.mapIndexed { index, image ->
val imageUrl = when {
image.isWordPressContent() -> {
CDN_URL.toHttpUrl().newBuilder()
.addPathSegments("wp-content/uploads/WP-manga/data")
.addPathSegments(image.src.toPathSegment())
.build()
}
else -> {
"$CDN_URL/scans/${dto.manga.scanId}/obras/${dto.manga.id}/capitulos/${dto.chapterNumber}/${image.src}"
.toHttpUrl()
}
}
Page(index, imageUrl = imageUrl.toString())
}
return dto.toPageList()
}
private fun pageListParse(document: Document): List<Page> {
return document.select(pageUrlSelector).mapIndexed { index, element ->
@ -211,9 +183,9 @@ abstract class GreenShit(
?: throw Exception("Failed to extract JSON from script")
}
private fun parseJsonToChapterPageDto(jsonContent: String): ChapterPageDto {
private fun parseJsonToChapterPageDto(jsonContent: String): ResultDto<ChapterPageDto> {
return try {
jsonContent.parseAs<ResultDto<ChapterPageDto>>().results
jsonContent.parseAs<ResultDto<ChapterPageDto>>()
} catch (e: Exception) {
throw Exception("Failed to load pages: ${e.message}")
}
@ -327,15 +299,6 @@ abstract class GreenShit(
return this
}
/**
* Normalizes path segments:
* Ex: [ "/a/b/", "/a/b", "a/b/", "a/b" ]
* Result: "a/b"
*/
private fun String.toPathSegment() = this.trim().split("/")
.filter(String::isNotEmpty)
.joinToString("/")
companion object {
const val CDN_URL = "https://cdn.sussytoons.site"
@ -355,8 +318,5 @@ abstract class GreenShit(
private const val API_DEFAULT_BASE_URL_PREF = "defaultApiUrl"
private const val DEFAULT_PREF = "defaultPref"
@SuppressLint("SimpleDateFormat")
val dateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.ROOT)
}
}

View File

@ -1,12 +1,19 @@
package eu.kanade.tachiyomi.multisrc.greenshit
import android.annotation.SuppressLint
import eu.kanade.tachiyomi.multisrc.greenshit.GreenShit.Companion.CDN_URL
import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga
import keiyoushi.utils.tryParse
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonNames
import okhttp3.HttpUrl.Companion.toHttpUrl
import org.jsoup.Jsoup
import java.text.Normalizer
import java.text.SimpleDateFormat
import java.util.Locale
@Serializable
class ResultDto<T>(
@ -25,6 +32,38 @@ class ResultDto<T>(
.map { it.apply { slug = it.slug ?: name.createSlug() } }
.map(MangaDto::toSManga)
fun toSChapterList(): List<SChapter> = (results as WrapperChapterDto)
.chapters.map {
SChapter.create().apply {
name = it.name
it.chapterNumber?.let {
chapter_number = it
}
url = "/capitulo/${it.id}"
date_upload = dateFormat.tryParse(it.updateAt)
}
}.sortedByDescending(SChapter::chapter_number)
fun toPageList(): List<Page> {
val dto = (results as ChapterPageDto)
return dto.pages.mapIndexed { index, image ->
val imageUrl = when {
image.isWordPressContent() -> {
CDN_URL.toHttpUrl().newBuilder()
.addPathSegments("wp-content/uploads/WP-manga/data")
.addPathSegments(image.src.toPathSegment())
.build()
}
else -> {
"$CDN_URL/scans/${dto.manga.scanId}/obras/${dto.manga.id}/capitulos/${dto.chapterNumber}/${image.src}"
.toHttpUrl()
}
}
Page(index, imageUrl = imageUrl.toString())
}
}
private fun String.createSlug(): String {
return Normalizer.normalize(this, Normalizer.Form.NFD)
.trim()
@ -33,17 +72,11 @@ class ResultDto<T>(
.replace("\\s+".toRegex(), "-")
.lowercase()
}
}
@Serializable
class WrapperDto(
@SerialName("dataTop")
val popular: ResultDto<List<MangaDto>>?,
@JsonNames("atualizacoesInicial")
private val dataLatest: ResultDto<List<MangaDto>>?,
) {
val latest: ResultDto<List<MangaDto>> get() = dataLatest!!
companion object {
@SuppressLint("SimpleDateFormat")
val dateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.ROOT)
}
}
@Serializable
@ -154,3 +187,12 @@ class PageDto(
) {
fun isWordPressContent(): Boolean = number == null
}
/**
* Normalizes path segments:
* Ex: [ "/a/b/", "/a/b", "a/b/", "a/b" ]
* Result: "a/b"
*/
private fun String.toPathSegment() = this.trim().split("/")
.filter(String::isNotEmpty)
.joinToString("/")

View File

@ -3,7 +3,7 @@ ext {
extClass = '.SussyToons'
themePkg = 'greenshit'
baseUrl = 'https://www.sussytoons.wtf'
overrideVersionCode = 54
overrideVersionCode = 55
isNsfw = true
}

View File

@ -1,6 +1,18 @@
package eu.kanade.tachiyomi.extension.pt.sussyscan
import eu.kanade.tachiyomi.multisrc.greenshit.ChapterPageDto
import eu.kanade.tachiyomi.multisrc.greenshit.GreenShit
import eu.kanade.tachiyomi.multisrc.greenshit.MangaDto
import eu.kanade.tachiyomi.multisrc.greenshit.ResultDto
import eu.kanade.tachiyomi.multisrc.greenshit.WrapperChapterDto
import eu.kanade.tachiyomi.network.GET
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 keiyoushi.utils.parseAs
import okhttp3.Request
import okhttp3.Response
class SussyToons : GreenShit(
"Sussy Toons",
@ -11,7 +23,29 @@ class SussyToons : GreenShit(
override val versionId = 2
override val supportsLatest = false
override fun popularMangaRequest(page: Int): Request =
GET("$apiUrl/obras/top5", headers)
override fun fetchPopularManga(page: Int) = fetchLatestUpdates(page)
override fun popularMangaParse(response: Response): MangasPage {
val mangas = response.parseAs<ResultDto<List<MangaDto>>>().toSMangaList()
return MangasPage(mangas, hasNextPage = false)
}
override fun getChapterUrl(chapter: SChapter) = "$baseUrl${chapter.url}"
override fun chapterListRequest(manga: SManga): Request {
val pathSegment = manga.url.substringBeforeLast("/").replace("obra", "obras")
return GET("$apiUrl$pathSegment", headers)
}
override fun chapterListParse(response: Response): List<SChapter> =
response.parseAs<ResultDto<WrapperChapterDto>>().toSChapterList()
override fun pageListRequest(chapter: SChapter): Request {
val pathSegment = chapter.url.replace("capitulo", "capitulo-app")
return GET("$apiUrl$pathSegment", headers)
}
override fun pageListParse(response: Response): List<Page> =
response.parseAs<ResultDto<ChapterPageDto>>().toPageList()
}