From af9b767d1bc55b91b65a57de255f7b17496eca66 Mon Sep 17 00:00:00 2001
From: AwkwardPeak7 <48650614+AwkwardPeak7@users.noreply.github.com>
Date: Sat, 6 Apr 2024 11:45:33 +0500
Subject: [PATCH] HuntersScans: move back to Madara (#2271)
---
src/pt/huntersscans/AndroidManifest.xml | 22 --
src/pt/huntersscans/build.gradle | 9 +-
.../extension/pt/huntersscans/HuntersScans.kt | 261 +-----------------
.../huntersscans/HuntersScansUrlActivity.kt | 36 ---
4 files changed, 18 insertions(+), 310 deletions(-)
delete mode 100644 src/pt/huntersscans/AndroidManifest.xml
delete mode 100644 src/pt/huntersscans/src/eu/kanade/tachiyomi/extension/pt/huntersscans/HuntersScansUrlActivity.kt
diff --git a/src/pt/huntersscans/AndroidManifest.xml b/src/pt/huntersscans/AndroidManifest.xml
deleted file mode 100644
index 3329b789a..000000000
--- a/src/pt/huntersscans/AndroidManifest.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/pt/huntersscans/build.gradle b/src/pt/huntersscans/build.gradle
index d802c6a6f..545f45b0e 100644
--- a/src/pt/huntersscans/build.gradle
+++ b/src/pt/huntersscans/build.gradle
@@ -1,11 +1,10 @@
ext {
extName = 'Hunters Scans'
extClass = '.HuntersScans'
- extVersionCode = 36
+ themePkg = 'madara'
+ baseUrl = 'https://huntersscan.xyz'
+ overrideVersionCode = 2
+ isNsfw = true
}
apply from: "$rootDir/common.gradle"
-
-dependencies {
- implementation(project(':lib:randomua'))
-}
diff --git a/src/pt/huntersscans/src/eu/kanade/tachiyomi/extension/pt/huntersscans/HuntersScans.kt b/src/pt/huntersscans/src/eu/kanade/tachiyomi/extension/pt/huntersscans/HuntersScans.kt
index 8c02a5aef..30a551255 100644
--- a/src/pt/huntersscans/src/eu/kanade/tachiyomi/extension/pt/huntersscans/HuntersScans.kt
+++ b/src/pt/huntersscans/src/eu/kanade/tachiyomi/extension/pt/huntersscans/HuntersScans.kt
@@ -1,253 +1,20 @@
package eu.kanade.tachiyomi.extension.pt.huntersscans
-import android.app.Application
-import android.content.SharedPreferences
-import android.util.Log
-import androidx.preference.PreferenceScreen
-import eu.kanade.tachiyomi.lib.randomua.addRandomUAPreferenceToScreen
-import eu.kanade.tachiyomi.lib.randomua.getPrefCustomUA
-import eu.kanade.tachiyomi.lib.randomua.getPrefUAType
-import eu.kanade.tachiyomi.lib.randomua.setRandomUserAgent
-import eu.kanade.tachiyomi.network.GET
-import eu.kanade.tachiyomi.network.asObservableSuccess
-import eu.kanade.tachiyomi.network.interceptor.rateLimitHost
-import eu.kanade.tachiyomi.source.ConfigurableSource
-import eu.kanade.tachiyomi.source.model.FilterList
-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 eu.kanade.tachiyomi.source.online.ParsedHttpSource
-import eu.kanade.tachiyomi.util.asJsoup
-import okhttp3.HttpUrl
-import okhttp3.HttpUrl.Companion.toHttpUrl
-import okhttp3.OkHttpClient
-import okhttp3.Request
-import okhttp3.Response
-import org.jsoup.nodes.Document
-import org.jsoup.nodes.Element
-import rx.Observable
-import uy.kohesive.injekt.Injekt
-import uy.kohesive.injekt.api.get
+import eu.kanade.tachiyomi.multisrc.madara.Madara
+import eu.kanade.tachiyomi.network.interceptor.rateLimit
+import java.text.SimpleDateFormat
import java.util.Locale
-import java.util.concurrent.TimeUnit
-class HuntersScans : ParsedHttpSource(), ConfigurableSource {
- override val name = "Hunters Scans"
+class HuntersScans : Madara(
+ "Hunters Scan",
+ "https://huntersscan.xyz",
+ "pt-BR",
+ SimpleDateFormat("dd/MM/yyyy", Locale("pt", "BR")),
+) {
+ override val client = super.client.newBuilder()
+ .rateLimit(1, 2)
+ .build()
- override val lang = "pt-BR"
-
- override val supportsLatest = true
-
- override val baseUrl = "https://huntersscan.xyz"
-
- override val versionId = 2
-
- private val preferences: SharedPreferences =
- Injekt.get().getSharedPreferences("source_$id", 0x0000)
-
- override val client: OkHttpClient =
- network.cloudflareClient.newBuilder()
- .setRandomUserAgent(
- preferences.getPrefUAType(),
- preferences.getPrefCustomUA(),
- )
- .rateLimitHost(baseUrl.toHttpUrl(), 1, 2, TimeUnit.SECONDS)
- .build()
-
- override fun setupPreferenceScreen(screen: PreferenceScreen) {
- addRandomUAPreferenceToScreen(screen)
- }
-
- override fun chapterFromElement(element: Element) = throw UnsupportedOperationException()
-
- private fun fetchChapterList(url: HttpUrl, page: Int): List {
- return try {
- val mangaPaged = url.newBuilder()
- .addQueryParameter("page", "$page")
- .build()
- chapterListParseFromJS(client.newCall(GET(mangaPaged, headers)).execute())
- } catch (e: Exception) {
- Log.e("HuntersScans", e.toString())
- emptyList()
- }
- }
-
- private fun chapterListParseFromJS(response: Response): List {
- val jScript = response.asJsoup().select(chapterListSelector())
- .map { element -> element.html() }
- .filter { element -> element.isNotEmpty() }
- .first { chapterRegex.find(it) != null }
-
- val chaptersLinks = chapterRegex.findAll(jScript)
- .flatMap { result -> result.groups.mapNotNull { it?.value } }
- .toSet()
-
- return chaptersLinks.map { chapterLink ->
- SChapter.create().apply {
- name = chapterLink.toChapterName()
- setUrlWithoutDomain(chapterLink.toChapterAbsUrl())
- }
- }
- }
-
- private fun containsDuplicate(chapters: List): Boolean {
- return chapters.size != chapters.distinctBy { it.name }.size
- }
-
- override fun chapterListParse(response: Response): List {
- val chapters = mutableListOf()
- val alwaysVisibleChapters = mutableSetOf()
-
- val origin = response.request.url
- var currentPage = 1
-
- do {
- val chapterList = fetchChapterList(origin, currentPage)
- if (chapterList.size <= 2) {
- chapters += chapterList
- break
- }
-
- chapters += chapterList.sortedBy { it.name.toFloat() }
- alwaysVisibleChapters += chapters.removeFirst()
- alwaysVisibleChapters += chapters.removeLast()
-
- currentPage++
- }
- while (!containsDuplicate(chapters))
-
- chapters += alwaysVisibleChapters
-
- return chapters
- .distinctBy { it.name }
- .sortedBy { it.name.toFloat() }
- .reversed()
- }
-
- override fun chapterListSelector() = "script"
-
- override fun imageUrlParse(document: Document) = ""
-
- override fun latestUpdatesFromElement(element: Element) =
- SManga.create().apply {
- val type = element.selectFirst("span")!!.ownText().toCapitalize()
- title = "${element.selectFirst("h3")!!.ownText()} - $type"
- thumbnail_url = element.selectFirst("img")?.absUrl("src")
- setUrlWithoutDomain(element.selectFirst("a")!!.absUrl("href"))
- }
-
- override fun latestUpdatesNextPageSelector() = popularMangaNextPageSelector()
-
- override fun latestUpdatesParse(response: Response) =
- super.latestUpdatesParse(response).removeNovels()
-
- override fun latestUpdatesRequest(page: Int): Request {
- val url = "$baseUrl/ultimas-atualizacoes".toHttpUrl().newBuilder()
- .addQueryParameter("page", "$page")
- .build()
- return GET(url, headers)
- }
-
- override fun latestUpdatesSelector() = "main > div div:nth-child(2) > div.relative"
-
- override fun mangaDetailsParse(document: Document) =
- SManga.create().apply {
- val container = document.selectFirst("div.container")!!
- val type = container.selectFirst("ul > li:nth-child(1) p")!!.ownText().toCapitalize()
- title = "${container.selectFirst("h2")!!.ownText()} - $type"
- thumbnail_url = container.selectFirst("img")?.absUrl("src")
- genre = container.select("ul > li:nth-child(5) p").joinToString { it.ownText() }
-
- val statusLabel = container.selectFirst("ul > li:nth-child(3) p")?.ownText()
- status = when (statusLabel) {
- "ongoing" -> SManga.ONGOING
- else -> SManga.UNKNOWN
- }
- description = document.selectFirst("main > div > div")?.text()
- }
-
- override fun pageListParse(document: Document) =
- document.select("main.container img")
- .mapIndexed { i, element -> Page(i, imageUrl = element.absUrl("src")) }
-
- override fun popularMangaFromElement(element: Element) = SManga.create().apply {
- val type = element.selectFirst("span")!!.ownText().toCapitalize()
- title = "${element.selectFirst("h2")!!.ownText()} - $type"
- thumbnail_url = element.selectFirst("img")?.absUrl("src")
- setUrlWithoutDomain(element.absUrl("href"))
- }
-
- override fun popularMangaNextPageSelector() = "li[aria-label='next page button']:not([aria-disabled])"
-
- override fun popularMangaParse(response: Response) =
- super.popularMangaParse(response).removeNovels()
-
- override fun popularMangaRequest(page: Int): Request {
- val url = "$baseUrl/manga".toHttpUrl().newBuilder()
- .addQueryParameter("page", "$page")
- .build()
- return GET(url, headers)
- }
-
- override fun popularMangaSelector() = "main > div a"
-
- override fun searchMangaFromElement(element: Element) = popularMangaFromElement(element)
-
- override fun searchMangaNextPageSelector() = popularMangaNextPageSelector()
-
- override fun searchMangaParse(response: Response) =
- super.searchMangaParse(response).removeNovels()
-
- override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
- val url = "$baseUrl/manga".toHttpUrl().newBuilder()
- .addQueryParameter("q", query)
- .addQueryParameter("page", "$page")
- .build()
- return GET(url, headers)
- }
-
- override fun searchMangaSelector() = popularMangaSelector()
-
- override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable {
- if (query.startsWith(slugPrefix)) {
- val mangaUrl = "/manga/${query.substringAfter(slugPrefix)}"
- return client.newCall(GET("$baseUrl$mangaUrl", headers))
- .asObservableSuccess().map { response ->
- val manga = mangaDetailsParse(response).apply {
- url = mangaUrl
- }
- MangasPage(listOf(manga), false)
- }
- }
-
- return super.fetchSearchManga(page, query, filters)
- }
-
- private fun MangasPage.removeNovels(): MangasPage {
- return MangasPage(
- mangas = this.mangas.filter { !it.title.lowercase(Locale.ROOT).contains("novel") },
- hasNextPage = this.hasNextPage,
- )
- }
-
- private fun String.toCapitalize() =
- trim().replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() }
-
- private fun String.toChapterName(): String {
- return try {
- val matches = chapterNameRegex.find(trim())?.groupValues ?: emptyList()
- matches.last()
- .replace(" ", "")
- .replace("-", ".")
- } catch (e: Exception) { "0" }
- }
-
- private fun String.toChapterAbsUrl() = "$baseUrl${trim()}"
-
- companion object {
- val chapterRegex = """/ler/[\w+-]+-capitulo-[\d.-]+""".toRegex()
- val chapterNameRegex = """capitulo-([\d-.]+)""".toRegex()
- val slugPrefix = "slug:"
- }
+ override val mangaSubString = "series"
+ override val useNewChapterEndpoint = true
}
diff --git a/src/pt/huntersscans/src/eu/kanade/tachiyomi/extension/pt/huntersscans/HuntersScansUrlActivity.kt b/src/pt/huntersscans/src/eu/kanade/tachiyomi/extension/pt/huntersscans/HuntersScansUrlActivity.kt
deleted file mode 100644
index e68b229ab..000000000
--- a/src/pt/huntersscans/src/eu/kanade/tachiyomi/extension/pt/huntersscans/HuntersScansUrlActivity.kt
+++ /dev/null
@@ -1,36 +0,0 @@
-package eu.kanade.tachiyomi.extension.pt.huntersscans
-
-import android.app.Activity
-import android.content.ActivityNotFoundException
-import android.content.Intent
-import android.os.Bundle
-import android.util.Log
-import kotlin.system.exitProcess
-
-class HuntersScansUrlActivity : Activity() {
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- val pathSegments = intent?.data?.pathSegments
-
- if (pathSegments != null && pathSegments.size > 2) {
- val intent = Intent().apply {
- action = "eu.kanade.tachiyomi.SEARCH"
- putExtra("query", slug(pathSegments))
- putExtra("filter", packageName)
- }
-
- try {
- startActivity(intent)
- } catch (e: ActivityNotFoundException) {
- Log.e("HuntersScansUrlActivity", e.toString())
- }
- } else {
- Log.e("HuntersScansUrlActivity", "Could not parse URI from intent $intent")
- }
-
- finish()
- exitProcess(0)
- }
-
- private fun slug(pathSegments: List) = "${HuntersScans.slugPrefix}${pathSegments.last()}"
-}