From 47d888e1202dbf67a578c15df1f97a4493fa4d19 Mon Sep 17 00:00:00 2001 From: mobi2002 <48650614+mobi2002@users.noreply.github.com> Date: Sun, 19 Mar 2023 02:01:16 +0500 Subject: [PATCH] A Pair Of 2+ : move to individual extension (#15757) * Remove from Madara * APairOf2: rewrite for new site --- .../multisrc/madara/MadaraGenerator.kt | 1 - src/en/apairof2/AndroidManifest.xml | 24 +++ src/en/apairof2/build.gradle | 11 ++ .../apairof2/res/mipmap-hdpi/ic_launcher.png | Bin .../apairof2/res/mipmap-mdpi/ic_launcher.png | Bin .../apairof2/res/mipmap-xhdpi/ic_launcher.png | Bin .../res/mipmap-xxhdpi/ic_launcher.png | Bin .../res/mipmap-xxxhdpi/ic_launcher.png | Bin .../en}/apairof2/res/web_hi_res_512.png | Bin .../extension/en/apairof2/APairOf2.kt | 155 ++++++++++++++++++ .../en/apairof2/APairOf2UrlActivity.kt | 34 ++++ 11 files changed, 224 insertions(+), 1 deletion(-) create mode 100644 src/en/apairof2/AndroidManifest.xml create mode 100644 src/en/apairof2/build.gradle rename {multisrc/overrides/madara => src/en}/apairof2/res/mipmap-hdpi/ic_launcher.png (100%) rename {multisrc/overrides/madara => src/en}/apairof2/res/mipmap-mdpi/ic_launcher.png (100%) rename {multisrc/overrides/madara => src/en}/apairof2/res/mipmap-xhdpi/ic_launcher.png (100%) rename {multisrc/overrides/madara => src/en}/apairof2/res/mipmap-xxhdpi/ic_launcher.png (100%) rename {multisrc/overrides/madara => src/en}/apairof2/res/mipmap-xxxhdpi/ic_launcher.png (100%) rename {multisrc/overrides/madara => src/en}/apairof2/res/web_hi_res_512.png (100%) create mode 100644 src/en/apairof2/src/eu/kanade/tachiyomi/extension/en/apairof2/APairOf2.kt create mode 100644 src/en/apairof2/src/eu/kanade/tachiyomi/extension/en/apairof2/APairOf2UrlActivity.kt diff --git a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/madara/MadaraGenerator.kt b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/madara/MadaraGenerator.kt index 23e2e6d94..34da225b2 100644 --- a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/madara/MadaraGenerator.kt +++ b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/madara/MadaraGenerator.kt @@ -38,7 +38,6 @@ class MadaraGenerator : ThemeSourceGenerator { SingleLang("Anikiga", "https://anikiga.com", "tr"), SingleLang("Anisa Manga", "https://anisamanga.com", "tr"), SingleLang("Ansh Scans", "https://anshscans.org", "en"), - SingleLang("A Pair of 2+", "https://po2scans.com", "en", className = "APairOf2"), SingleLang("ApollComics", "https://apollcomics.xyz", "es", isNsfw = true, overrideVersionCode = 2), SingleLang("Apolltoons", "https://apolltoons.xyz", "es", isNsfw = true), SingleLang("Aqua Manga", "https://aquamanga.com", "en", overrideVersionCode = 3), diff --git a/src/en/apairof2/AndroidManifest.xml b/src/en/apairof2/AndroidManifest.xml new file mode 100644 index 000000000..92fcba232 --- /dev/null +++ b/src/en/apairof2/AndroidManifest.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + diff --git a/src/en/apairof2/build.gradle b/src/en/apairof2/build.gradle new file mode 100644 index 000000000..f620fcadb --- /dev/null +++ b/src/en/apairof2/build.gradle @@ -0,0 +1,11 @@ +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' + +ext { + extName = 'A Pair of 2+' + pkgNameSuffix = 'en.apairof2' + extClass = '.APairOf2' + extVersionCode = 29 +} + +apply from: "$rootDir/common.gradle" diff --git a/multisrc/overrides/madara/apairof2/res/mipmap-hdpi/ic_launcher.png b/src/en/apairof2/res/mipmap-hdpi/ic_launcher.png similarity index 100% rename from multisrc/overrides/madara/apairof2/res/mipmap-hdpi/ic_launcher.png rename to src/en/apairof2/res/mipmap-hdpi/ic_launcher.png diff --git a/multisrc/overrides/madara/apairof2/res/mipmap-mdpi/ic_launcher.png b/src/en/apairof2/res/mipmap-mdpi/ic_launcher.png similarity index 100% rename from multisrc/overrides/madara/apairof2/res/mipmap-mdpi/ic_launcher.png rename to src/en/apairof2/res/mipmap-mdpi/ic_launcher.png diff --git a/multisrc/overrides/madara/apairof2/res/mipmap-xhdpi/ic_launcher.png b/src/en/apairof2/res/mipmap-xhdpi/ic_launcher.png similarity index 100% rename from multisrc/overrides/madara/apairof2/res/mipmap-xhdpi/ic_launcher.png rename to src/en/apairof2/res/mipmap-xhdpi/ic_launcher.png diff --git a/multisrc/overrides/madara/apairof2/res/mipmap-xxhdpi/ic_launcher.png b/src/en/apairof2/res/mipmap-xxhdpi/ic_launcher.png similarity index 100% rename from multisrc/overrides/madara/apairof2/res/mipmap-xxhdpi/ic_launcher.png rename to src/en/apairof2/res/mipmap-xxhdpi/ic_launcher.png diff --git a/multisrc/overrides/madara/apairof2/res/mipmap-xxxhdpi/ic_launcher.png b/src/en/apairof2/res/mipmap-xxxhdpi/ic_launcher.png similarity index 100% rename from multisrc/overrides/madara/apairof2/res/mipmap-xxxhdpi/ic_launcher.png rename to src/en/apairof2/res/mipmap-xxxhdpi/ic_launcher.png diff --git a/multisrc/overrides/madara/apairof2/res/web_hi_res_512.png b/src/en/apairof2/res/web_hi_res_512.png similarity index 100% rename from multisrc/overrides/madara/apairof2/res/web_hi_res_512.png rename to src/en/apairof2/res/web_hi_res_512.png diff --git a/src/en/apairof2/src/eu/kanade/tachiyomi/extension/en/apairof2/APairOf2.kt b/src/en/apairof2/src/eu/kanade/tachiyomi/extension/en/apairof2/APairOf2.kt new file mode 100644 index 000000000..8e8991dc5 --- /dev/null +++ b/src/en/apairof2/src/eu/kanade/tachiyomi/extension/en/apairof2/APairOf2.kt @@ -0,0 +1,155 @@ +package eu.kanade.tachiyomi.extension.en.apairof2 + +import eu.kanade.tachiyomi.network.GET +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 okhttp3.Headers +import okhttp3.OkHttpClient +import okhttp3.Request +import org.jsoup.nodes.Document +import org.jsoup.nodes.Element +import rx.Observable +import java.text.SimpleDateFormat +import java.util.Locale + +class APairOf2 : ParsedHttpSource() { + + override val name = "A Pair of 2+" + + override val baseUrl = "https://po2scans.com" + + override val lang = "en" + + override val supportsLatest = true + + override val versionId = 2 + + override val client: OkHttpClient = network.cloudflareClient + + override fun headersBuilder(): Headers.Builder = super.headersBuilder() + .add("Referer", "$baseUrl/") + + // popular + override fun popularMangaRequest(page: Int): Request { + return GET("$baseUrl/series", headers) + } + + override fun popularMangaSelector() = "div.series-list" + + override fun popularMangaFromElement(element: Element): SManga { + return SManga.create().apply { + title = element.select("div > h2").text() + url = element.select("div > a").attr("href").let { "/$it" } + thumbnail_url = element.select("img").attr("data-src").let { "$baseUrl/$it" } + } + } + + // TODO: add page selectors & url parameters when site have enough series for pagination + override fun popularMangaNextPageSelector() = null + + // latest + override fun latestUpdatesRequest(page: Int): Request { + return GET(baseUrl, headers) + } + + override fun latestUpdatesSelector() = "div.chap" + + override fun latestUpdatesFromElement(element: Element): SManga { + return SManga.create().apply { + element.select("div.chap-title a").let { it -> + url = it.attr("href").let { "/$it" } + title = it.text() + } + thumbnail_url = element.select("img").attr("data-src").let { "$baseUrl/$it" } + } + } + + override fun latestUpdatesNextPageSelector() = popularMangaSelector() + + // search + override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable { + if (!query.startsWith(SLUG_SEARCH_PREFIX)) { + return super.fetchSearchManga(page, query, filters) + } + + val url = "/series/${query.substringAfter(SLUG_SEARCH_PREFIX)}" + return fetchMangaDetails(SManga.create().apply { this.url = url }).map { + it.url = url + MangasPage(listOf(it), false) + } + } + + override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { + return GET("$baseUrl/series?search=$query", headers) + } + + override fun searchMangaSelector() = popularMangaSelector() + + override fun searchMangaFromElement(element: Element) = popularMangaFromElement(element) + + override fun searchMangaNextPageSelector() = popularMangaNextPageSelector() + + // manga details + override fun mangaDetailsParse(document: Document): SManga { + return SManga.create().apply { + title = document.selectFirst(".title")!!.text() + author = document.select(".author > span:nth-child(2)").text() + artist = author + status = document.select(".status > span:nth-child(2)").text().parseStatus() + description = document.select(".summary p").text() + thumbnail_url = document.select("div.series-image img").attr("src").let { "$baseUrl/$it" } + } + } + + private fun String.parseStatus(): Int { + return when { + this.contains("ongoing", true) -> SManga.ONGOING + this.contains("complete", true) -> SManga.COMPLETED + else -> SManga.UNKNOWN + } + } + + // chapter list + override fun chapterListSelector() = "div.chap" + + override fun chapterFromElement(element: Element): SChapter { + return SChapter.create().apply { + element.select("a").let { a -> + url = a.attr("href").let { "/$it" } + name = a.text() + } + date_upload = parseDate(element.select("div > div > span:nth-child(2)").text()) + } + } + + private fun parseDate(dateStr: String): Long { + return runCatching { DATE_FORMATTER.parse(dateStr)?.time } + .getOrNull() ?: 0L + } + + // page list + override fun pageListParse(document: Document): List { + return document.select(".swiper-slide img").mapIndexed { index, img -> + Page( + index = index, + imageUrl = img.attr("src").let { "$baseUrl/$it" }, + ) + } + } + + override fun imageUrlParse(document: Document): String { + throw UnsupportedOperationException("not used") + } + + companion object { + private val DATE_FORMATTER by lazy { + SimpleDateFormat("dd MMMM, yy", Locale.ENGLISH) + } + + const val SLUG_SEARCH_PREFIX = "slug:" + } +} diff --git a/src/en/apairof2/src/eu/kanade/tachiyomi/extension/en/apairof2/APairOf2UrlActivity.kt b/src/en/apairof2/src/eu/kanade/tachiyomi/extension/en/apairof2/APairOf2UrlActivity.kt new file mode 100644 index 000000000..8ba124982 --- /dev/null +++ b/src/en/apairof2/src/eu/kanade/tachiyomi/extension/en/apairof2/APairOf2UrlActivity.kt @@ -0,0 +1,34 @@ +package eu.kanade.tachiyomi.extension.en.apairof2 + +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 APairOf2UrlActivity : Activity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + val pathSegments = intent?.data?.pathSegments + if (pathSegments != null && pathSegments.size > 1) { + val slug = pathSegments[1] + val mainIntent = Intent().apply { + action = "eu.kanade.tachiyomi.SEARCH" + putExtra("query", "${APairOf2.SLUG_SEARCH_PREFIX}$slug") + putExtra("filter", packageName) + } + + try { + startActivity(mainIntent) + } catch (e: ActivityNotFoundException) { + Log.e("APairOf2UrlActivity", e.toString()) + } + } else { + Log.e("APairOf2UrlActivity", "could not parse uri from intent $intent") + } + + finish() + exitProcess(0) + } +}