From d11495d8a18bbfa48ea0ae67bf906a32522ef1f6 Mon Sep 17 00:00:00 2001 From: AwkwardPeak7 <48650614+AwkwardPeak7@users.noreply.github.com> Date: Sat, 13 Jul 2024 11:12:21 +0500 Subject: [PATCH] Mangapark: duplicate chapters & unblock site blocked genres (#3979) * fetch duplicate chapters + small refactor => data class -> class * site settings to not block "Hentai" genre * user name as scanlator for first choice * forgor * try not to make duplicate calls concurrency my beloved * move fetch genre call to `getFilterList` --- src/all/mangapark/build.gradle | 2 +- .../extension/all/mangapark/MangaPark.kt | 60 +++++++++++++++++- .../extension/all/mangapark/MangaParkDto.kt | 61 +++++++++++-------- .../all/mangapark/MangaParkPayloadDto.kt | 34 +++++------ .../all/mangapark/MangaParkQueries.kt | 22 +++++++ 5 files changed, 131 insertions(+), 48 deletions(-) diff --git a/src/all/mangapark/build.gradle b/src/all/mangapark/build.gradle index 95db165dc..634bffda5 100644 --- a/src/all/mangapark/build.gradle +++ b/src/all/mangapark/build.gradle @@ -1,7 +1,7 @@ ext { extName = 'MangaPark' extClass = '.MangaParkFactory' - extVersionCode = 19 + extVersionCode = 20 isNsfw = true } diff --git a/src/all/mangapark/src/eu/kanade/tachiyomi/extension/all/mangapark/MangaPark.kt b/src/all/mangapark/src/eu/kanade/tachiyomi/extension/all/mangapark/MangaPark.kt index c9c1de551..e05a70719 100644 --- a/src/all/mangapark/src/eu/kanade/tachiyomi/extension/all/mangapark/MangaPark.kt +++ b/src/all/mangapark/src/eu/kanade/tachiyomi/extension/all/mangapark/MangaPark.kt @@ -4,6 +4,7 @@ import android.app.Application import android.widget.Toast import androidx.preference.ListPreference import androidx.preference.PreferenceScreen +import androidx.preference.SwitchPreferenceCompat import eu.kanade.tachiyomi.lib.cookieinterceptor.CookieInterceptor import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.POST @@ -17,10 +18,14 @@ 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.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch import kotlinx.serialization.decodeFromString import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import okhttp3.HttpUrl.Companion.toHttpUrl +import okhttp3.Interceptor import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.Request import okhttp3.RequestBody.Companion.toRequestBody @@ -28,6 +33,8 @@ import okhttp3.Response import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get import uy.kohesive.injekt.injectLazy +import java.util.concurrent.CountDownLatch +import java.util.concurrent.atomic.AtomicBoolean class MangaPark( override val lang: String, @@ -53,6 +60,7 @@ class MangaPark( private val json: Json by injectLazy() override val client = network.cloudflareClient.newBuilder() + .addInterceptor(::siteSettingsInterceptor) .addNetworkInterceptor(CookieInterceptor(domain, "nsfw" to "2")) .rateLimitHost(apiUrl.toHttpUrl(), 1) .build() @@ -90,8 +98,6 @@ class MangaPark( } override fun searchMangaParse(response: Response): MangasPage { - runCatching(::getGenres) - val result = response.parseAs() val entries = result.data.searchComics.items.map { it.data.toSManga() } @@ -126,6 +132,10 @@ class MangaPark( } override fun getFilterList(): FilterList { + CoroutineScope(Dispatchers.IO).launch { + runCatching(::getGenres) + } + val filters = mutableListOf>( SortFilter(), OriginalLanguageFilter(), @@ -175,7 +185,13 @@ class MangaPark( override fun chapterListParse(response: Response): List { val result = response.parseAs() - return result.data.chapterList.map { it.data.toSChapter() }.reversed() + return if (preference.getBoolean(DUPLICATE_CHAPTER_PREF_KEY, false)) { + result.data.chapterList.flatMap { + it.data.dupChapters.map { it.data.toSChapter() } + }.reversed() + } else { + result.data.chapterList.map { it.data.toSChapter() }.reversed() + } } override fun getChapterUrl(chapter: SChapter) = baseUrl + chapter.url.substringBeforeLast("#") @@ -211,6 +227,13 @@ class MangaPark( true } }.also(screen::addPreference) + + SwitchPreferenceCompat(screen.context).apply { + key = DUPLICATE_CHAPTER_PREF_KEY + title = "Fetch Duplicate Chapters" + summary = "Refresh chapter list to apply changes" + setDefaultValue(false) + }.also(screen::addPreference) } private inline fun Response.parseAs(): T = @@ -222,6 +245,35 @@ class MangaPark( private inline fun T.toJsonRequestBody() = json.encodeToString(this).toRequestBody(JSON_MEDIA_TYPE) + private val cookiesNotSet = AtomicBoolean(true) + private val latch = CountDownLatch(1) + + // sets necessary cookies to not block genres like `Hentai` + private fun siteSettingsInterceptor(chain: Interceptor.Chain): Response { + val request = chain.request() + + val settingsUrl = "$baseUrl/aok/settings-save" + + if ( + request.url.toString() != settingsUrl && + request.url.host == domain + ) { + if (cookiesNotSet.getAndSet(false)) { + val payload = + """{"data":{"general_autoLangs":[],"general_userLangs":[],"general_excGenres":[],"general_prefLangs":[]}}""" + .toRequestBody(JSON_MEDIA_TYPE) + + client.newCall(POST(settingsUrl, headers, payload)).execute().close() + + latch.countDown() + } else { + latch.await() + } + } + + return chain.proceed(request) + } + override fun imageUrlParse(response: Response): String { throw UnsupportedOperationException() } @@ -248,5 +300,7 @@ class MangaPark( "parkmanga.org", "mpark.to", ) + + private const val DUPLICATE_CHAPTER_PREF_KEY = "pref_dup_chapters" } } diff --git a/src/all/mangapark/src/eu/kanade/tachiyomi/extension/all/mangapark/MangaParkDto.kt b/src/all/mangapark/src/eu/kanade/tachiyomi/extension/all/mangapark/MangaParkDto.kt index 6293244c0..5ef81ada2 100644 --- a/src/all/mangapark/src/eu/kanade/tachiyomi/extension/all/mangapark/MangaParkDto.kt +++ b/src/all/mangapark/src/eu/kanade/tachiyomi/extension/all/mangapark/MangaParkDto.kt @@ -12,34 +12,34 @@ typealias ChapterListResponse = Data typealias PageListResponse = Data @Serializable -data class Data(val data: T) +class Data(val data: T) @Serializable -data class Items(val items: List) +class Items(val items: List) @Serializable -data class SearchComics( +class SearchComics( @SerialName("get_searchComic") val searchComics: Items>, ) @Serializable -data class ComicNode( +class ComicNode( @SerialName("get_comicNode") val comic: Data, ) @Serializable -data class MangaParkComic( - val id: String, - val name: String, - val altNames: List? = null, - val authors: List? = null, - val artists: List? = null, - val genres: List? = null, - val originalStatus: String? = null, - val uploadStatus: String? = null, - val summary: String? = null, - @SerialName("urlCoverOri") val cover: String? = null, - val urlPath: String, +class MangaParkComic( + private val id: String, + private val name: String, + private val altNames: List? = null, + private val authors: List? = null, + private val artists: List? = null, + private val genres: List? = null, + private val originalStatus: String? = null, + private val uploadStatus: String? = null, + private val summary: String? = null, + @SerialName("urlCoverOri") private val cover: String? = null, + private val urlPath: String, ) { fun toSManga() = SManga.create().apply { url = "$urlPath#$id" @@ -100,18 +100,21 @@ data class MangaParkComic( } @Serializable -data class ChapterList( +class ChapterList( @SerialName("get_comicChapterList") val chapterList: List>, ) @Serializable -data class MangaParkChapter( - val id: String, - @SerialName("dname") val displayName: String, - val title: String? = null, - val dateCreate: Long? = null, - val dateModify: Long? = null, - val urlPath: String, +class MangaParkChapter( + private val id: String, + @SerialName("dname") private val displayName: String, + private val title: String? = null, + private val dateCreate: Long? = null, + private val dateModify: Long? = null, + private val urlPath: String, + private val srcTitle: String? = null, + private val userNode: Data? = null, + val dupChapters: List> = emptyList(), ) { fun toSChapter() = SChapter.create().apply { url = "$urlPath#$id" @@ -120,20 +123,24 @@ data class MangaParkChapter( title?.let { append(": ", it) } } date_upload = dateModify ?: dateCreate ?: 0L + scanlator = userNode?.data?.name ?: srcTitle ?: "Unknown" } } @Serializable -data class ChapterPages( +class Name(val name: String) + +@Serializable +class ChapterPages( @SerialName("get_chapterNode") val chapterPages: Data, ) @Serializable -data class ImageFiles( +class ImageFiles( val imageFile: UrlList, ) @Serializable -data class UrlList( +class UrlList( val urlList: List, ) diff --git a/src/all/mangapark/src/eu/kanade/tachiyomi/extension/all/mangapark/MangaParkPayloadDto.kt b/src/all/mangapark/src/eu/kanade/tachiyomi/extension/all/mangapark/MangaParkPayloadDto.kt index 397f3f44f..df0323f35 100644 --- a/src/all/mangapark/src/eu/kanade/tachiyomi/extension/all/mangapark/MangaParkPayloadDto.kt +++ b/src/all/mangapark/src/eu/kanade/tachiyomi/extension/all/mangapark/MangaParkPayloadDto.kt @@ -4,28 +4,28 @@ import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @Serializable -data class GraphQL( - val variables: T, - val query: String, +class GraphQL( + private val variables: T, + private val query: String, ) @Serializable -data class SearchVariables(val select: SearchPayload) +class SearchVariables(private val select: SearchPayload) @Serializable -data class SearchPayload( - @SerialName("word") val query: String? = null, - val incGenres: List? = null, - val excGenres: List? = null, - val incTLangs: List? = null, - val incOLangs: List? = null, - val sortby: String? = null, - val chapCount: String? = null, - val origStatus: String? = null, - val siteStatus: String? = null, - val page: Int, - val size: Int, +class SearchPayload( + @SerialName("word") private val query: String? = null, + private val incGenres: List? = null, + private val excGenres: List? = null, + private val incTLangs: List? = null, + private val incOLangs: List? = null, + private val sortby: String? = null, + private val chapCount: String? = null, + private val origStatus: String? = null, + private val siteStatus: String? = null, + private val page: Int, + private val size: Int, ) @Serializable -data class IdVariables(val id: String) +class IdVariables(private val id: String) diff --git a/src/all/mangapark/src/eu/kanade/tachiyomi/extension/all/mangapark/MangaParkQueries.kt b/src/all/mangapark/src/eu/kanade/tachiyomi/extension/all/mangapark/MangaParkQueries.kt index 68d2bdb41..d303e9fc6 100644 --- a/src/all/mangapark/src/eu/kanade/tachiyomi/extension/all/mangapark/MangaParkQueries.kt +++ b/src/all/mangapark/src/eu/kanade/tachiyomi/extension/all/mangapark/MangaParkQueries.kt @@ -75,6 +75,28 @@ val CHAPTERS_QUERY = buildQuery { dateModify dateCreate urlPath + srcTitle + userNode { + data { + name + } + } + dupChapters { + data { + id + dname + title + dateModify + dateCreate + urlPath + srcTitle + userNode { + data { + name + } + } + } + } } } }