From ac077880f9a714ffffe5c7900c7062cbe1240a21 Mon Sep 17 00:00:00 2001 From: Buhbbl <93195775+buhbbl@users.noreply.github.com> Date: Mon, 20 Nov 2023 17:41:41 +0100 Subject: [PATCH] HeanCMS: Added paid chapter preference (#19006) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Added paid chapter preference * Added requested changes and fixed a warning * Paid chapters now have a 🔒 next to it * Added Spanish translations * Converted protected into private functions * Improved the error message for unavailable paid chapters. * Revert "Converted protected into private functions" This reverts commit 864186d7b1f96b867c2d26e4410a6578e53223d5. * Added spanish translation for error message * Fixed: paidStatus would be set if price was 0 * Fixed: paidStatus would be set if price was null * Fixed: chapterId retrieval from url in pageListRequest --- .../tachiyomi/multisrc/heancms/HeanCms.kt | 68 +++++++++++++++---- .../tachiyomi/multisrc/heancms/HeanCmsDto.kt | 10 ++- .../multisrc/heancms/HeanCmsGenerator.kt | 2 +- .../tachiyomi/multisrc/heancms/HeanCmsIntl.kt | 20 ++++++ 4 files changed, 84 insertions(+), 16 deletions(-) diff --git a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/heancms/HeanCms.kt b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/heancms/HeanCms.kt index b11b1d3d5..9cf9660d3 100644 --- a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/heancms/HeanCms.kt +++ b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/heancms/HeanCms.kt @@ -2,8 +2,11 @@ package eu.kanade.tachiyomi.multisrc.heancms import android.app.Application import android.content.SharedPreferences +import androidx.preference.PreferenceScreen +import androidx.preference.SwitchPreferenceCompat import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.POST +import eu.kanade.tachiyomi.source.ConfigurableSource import eu.kanade.tachiyomi.source.model.Filter import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.MangasPage @@ -25,6 +28,7 @@ import okhttp3.Response import rx.Observable import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get +import java.io.IOException import java.text.SimpleDateFormat import java.util.Locale @@ -33,12 +37,28 @@ abstract class HeanCms( override val baseUrl: String, override val lang: String, protected val apiUrl: String = baseUrl.replace("://", "://api."), -) : HttpSource() { +) : ConfigurableSource, HttpSource() { private val preferences: SharedPreferences by lazy { Injekt.get().getSharedPreferences("source_$id", 0x0000) } + override fun setupPreferenceScreen(screen: PreferenceScreen) { + SwitchPreferenceCompat(screen.context).apply { + key = SHOW_PAID_CHAPTERS_PREF + title = intl.prefShowPaidChapterTitle + summaryOn = intl.prefShowPaidChapterSummaryOn + summaryOff = intl.prefShowPaidChapterSummaryOff + setDefaultValue(SHOW_PAID_CHAPTERS_DEFAULT) + + setOnPreferenceChangeListener { _, newValue -> + preferences.edit() + .putBoolean(SHOW_PAID_CHAPTERS_PREF, newValue as Boolean) + .commit() + } + }.also(screen::addPreference) + } + override val supportsLatest = true override val client: OkHttpClient = network.cloudflareClient @@ -402,16 +422,18 @@ abstract class HeanCms( val currentTimestamp = System.currentTimeMillis() + val showPaidChapters = preferences.showPaidChapters + if (useNewQueryEndpoint) { return result.seasons.orEmpty() .flatMap { it.chapters.orEmpty() } - .filter { it.price == 0 } + .filter { it.price == 0 || showPaidChapters } .map { it.toSChapter(result.slug, mangaSubDirectory, dateFormat, slugStrategy) } .filter { it.date_upload <= currentTimestamp } } return result.chapters.orEmpty() - .filter { it.price == 0 } + .filter { it.price == 0 || showPaidChapters } .map { it.toSChapter(result.slug, mangaSubDirectory, dateFormat, slugStrategy) } .filter { it.date_upload <= currentTimestamp } .reversed() @@ -442,7 +464,7 @@ abstract class HeanCms( return GET(baseUrl + chapter.url, headers) } - val chapterId = chapter.url.substringAfterLast("#") + val chapterId = chapter.url.substringAfterLast("#").substringBefore("-paid") val apiHeaders = headersBuilder() .add("Accept", ACCEPT_JSON) @@ -453,25 +475,37 @@ abstract class HeanCms( override fun pageListParse(response: Response): List { if (useNewQueryEndpoint) { + val paidChapter = response.request.url.fragment?.contains("-paid") + val document = response.asJsoup() val images = document.selectFirst("div.min-h-screen > div.container > p.items-center") + if (images == null && paidChapter == true) { + throw IOException(intl.paidChapterError) + } + return images?.select("img").orEmpty().mapIndexed { i, img -> val imageUrl = if (img.hasClass("lazy")) img.absUrl("data-src") else img.absUrl("src") Page(i, "", imageUrl) } } - return response.parseAs().content?.images.orEmpty() - .filterNot { imageUrl -> - // Their image server returns HTTP 403 for hidden files that starts - // with a dot in the file name. To avoid download errors, these are removed. - imageUrl - .removeSuffix("/") - .substringAfterLast("/") - .startsWith(".") - } + val images = response.parseAs().content?.images.orEmpty() + val paidChapter = response.request.url.fragment?.contains("-paid") + + if (images.isEmpty() && paidChapter == true) { + throw IOException(intl.paidChapterError) + } + + return images.filterNot { imageUrl -> + // Their image server returns HTTP 403 for hidden files that starts + // with a dot in the file name. To avoid download errors, these are removed. + imageUrl + .removeSuffix("/") + .substringAfterLast("/") + .startsWith(".") + } .mapIndexed { i, url -> Page(i, imageUrl = if (url.startsWith("http")) url else "$apiUrl/$url") } @@ -639,9 +673,12 @@ abstract class HeanCms( set(newSlugMap) { edit() .putString(PREF_URL_MAP_SLUG, json.encodeToString(newSlugMap)) - .commit() + .apply() } + private val SharedPreferences.showPaidChapters: Boolean + get() = getBoolean(SHOW_PAID_CHAPTERS_PREF, SHOW_PAID_CHAPTERS_DEFAULT) + companion object { private const val ACCEPT_IMAGE = "image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8" private const val ACCEPT_JSON = "application/json, text/plain, */*" @@ -655,5 +692,8 @@ abstract class HeanCms( const val SEARCH_PREFIX = "slug:" private const val PREF_URL_MAP_SLUG = "pref_url_map" + + private const val SHOW_PAID_CHAPTERS_PREF = "pref_show_paid_chap" + private const val SHOW_PAID_CHAPTERS_DEFAULT = false } } diff --git a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/heancms/HeanCmsDto.kt b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/heancms/HeanCmsDto.kt index 50d045caa..9a400cc6f 100644 --- a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/heancms/HeanCmsDto.kt +++ b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/heancms/HeanCmsDto.kt @@ -120,9 +120,17 @@ data class HeanCmsChapterDto( ): SChapter = SChapter.create().apply { val seriesSlugOnly = seriesSlug.toPermSlugIfNeeded(slugStrategy) name = this@HeanCmsChapterDto.name.trim() + + if (price != 0) { + name += " \uD83D\uDD12" + } + date_upload = runCatching { dateFormat.parse(createdAt)?.time } .getOrNull() ?: 0L - url = "/$mangaSubDirectory/$seriesSlugOnly/$slug#$id" + + val paidStatus = if (price != 0 && price != null) "-paid" else "" + + url = "/$mangaSubDirectory/$seriesSlugOnly/$slug#$id$paidStatus" } } diff --git a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/heancms/HeanCmsGenerator.kt b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/heancms/HeanCmsGenerator.kt index bceb128ba..dd1893ab9 100644 --- a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/heancms/HeanCmsGenerator.kt +++ b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/heancms/HeanCmsGenerator.kt @@ -9,7 +9,7 @@ class HeanCmsGenerator : ThemeSourceGenerator { override val themeClass = "HeanCms" - override val baseVersionCode: Int = 19 + override val baseVersionCode: Int = 20 override val sources = listOf( SingleLang("Glorious Scan", "https://gloriousscan.com", "pt-BR", overrideVersionCode = 17), diff --git a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/heancms/HeanCmsIntl.kt b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/heancms/HeanCmsIntl.kt index c4cd4798c..520eec381 100644 --- a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/heancms/HeanCmsIntl.kt +++ b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/heancms/HeanCmsIntl.kt @@ -76,6 +76,26 @@ class HeanCmsIntl(lang: String) { else -> "Filters will be ignored if the search is not empty." } + val prefShowPaidChapterTitle: String = when (availableLang) { + SPANISH -> "Mostrar capítulos de pago" + else -> "Display paid chapters" + } + + val prefShowPaidChapterSummaryOn: String = when (availableLang) { + SPANISH -> "Se mostrarán capítulos de pago. Deberá iniciar sesión" + else -> "Paid chapters will appear. A login might be needed!" + } + + val prefShowPaidChapterSummaryOff: String = when (availableLang) { + SPANISH -> "Solo se mostrarán los capítulos gratuitos" + else -> "Only free chapters will be displayed." + } + + val paidChapterError: String = when (availableLang) { + SPANISH -> "Capítulo no disponible. Debe iniciar sesión en Webview y tener el capítulo comprado." + else -> "Paid chapter unavailable.\nA login/purchase might be needed (using webview)." + } + fun urlChangedError(sourceName: String): String = when (availableLang) { BRAZILIAN_PORTUGUESE -> "A URL da série mudou. Migre de $sourceName " +