diff --git a/lib-multisrc/greenshit/src/eu/kanade/tachiyomi/multisrc/greenshit/GreenShit.kt b/lib-multisrc/greenshit/src/eu/kanade/tachiyomi/multisrc/greenshit/GreenShit.kt index 12c72020c..fae5ae5fa 100644 --- a/lib-multisrc/greenshit/src/eu/kanade/tachiyomi/multisrc/greenshit/GreenShit.kt +++ b/lib-multisrc/greenshit/src/eu/kanade/tachiyomi/multisrc/greenshit/GreenShit.kt @@ -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>().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>().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 { 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 { return try { - jsonContent.parseAs>().results + jsonContent.parseAs>() } 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) } } diff --git a/lib-multisrc/greenshit/src/eu/kanade/tachiyomi/multisrc/greenshit/GreenShitDto.kt b/lib-multisrc/greenshit/src/eu/kanade/tachiyomi/multisrc/greenshit/GreenShitDto.kt index b3d6e4843..5e534d698 100644 --- a/lib-multisrc/greenshit/src/eu/kanade/tachiyomi/multisrc/greenshit/GreenShitDto.kt +++ b/lib-multisrc/greenshit/src/eu/kanade/tachiyomi/multisrc/greenshit/GreenShitDto.kt @@ -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( @@ -25,6 +32,38 @@ class ResultDto( .map { it.apply { slug = it.slug ?: name.createSlug() } } .map(MangaDto::toSManga) + fun toSChapterList(): List = (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 { + 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( .replace("\\s+".toRegex(), "-") .lowercase() } -} -@Serializable -class WrapperDto( - @SerialName("dataTop") - val popular: ResultDto>?, - @JsonNames("atualizacoesInicial") - private val dataLatest: ResultDto>?, - -) { - val latest: ResultDto> 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("/") diff --git a/src/pt/sussyscan/build.gradle b/src/pt/sussyscan/build.gradle index 37b93f942..ac5132eed 100644 --- a/src/pt/sussyscan/build.gradle +++ b/src/pt/sussyscan/build.gradle @@ -3,7 +3,7 @@ ext { extClass = '.SussyToons' themePkg = 'greenshit' baseUrl = 'https://www.sussytoons.wtf' - overrideVersionCode = 54 + overrideVersionCode = 55 isNsfw = true } diff --git a/src/pt/sussyscan/src/eu/kanade/tachiyomi/extension/pt/sussyscan/SussyToons.kt b/src/pt/sussyscan/src/eu/kanade/tachiyomi/extension/pt/sussyscan/SussyToons.kt index f3165a846..b8f166a11 100644 --- a/src/pt/sussyscan/src/eu/kanade/tachiyomi/extension/pt/sussyscan/SussyToons.kt +++ b/src/pt/sussyscan/src/eu/kanade/tachiyomi/extension/pt/sussyscan/SussyToons.kt @@ -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>>().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 = + response.parseAs>().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 = + response.parseAs>().toPageList() }