Add SadScans and make APairOf2 a multisrc (#1046)

* Add SadScans and make APairOf2 a multisrc

* Formatting

* Trailing comma

* optimize icons

* newline

---------

Co-authored-by: AwkwardPeak7 <48650614+AwkwardPeak7@users.noreply.github.com>
This commit is contained in:
beerpsi 2024-02-07 15:15:50 +07:00 committed by GitHub
parent 7efe6cefc8
commit df859e3604
22 changed files with 98 additions and 96 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

View File

@ -0,0 +1,12 @@
package eu.kanade.tachiyomi.extension.en.apairof2
import eu.kanade.tachiyomi.multisrc.po2scans.PO2Scans
import eu.kanade.tachiyomi.network.interceptor.rateLimit
class APairOf2 : PO2Scans("A Pair Of 2+", "https://po2scans.com", "en") {
override val versionId = 2
override val client = super.client.newBuilder()
.rateLimit(4)
.build()
}

View File

@ -3,7 +3,7 @@
<application>
<activity
android:name=".en.apairof2.APairOf2UrlActivity"
android:name="eu.kanade.tachiyomi.multisrc.po2scans.PO2ScansUrlActivity"
android:excludeFromRecents="true"
android:exported="true"
android:theme="@android:style/Theme.NoDisplay">
@ -14,9 +14,9 @@
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="po2scans.com"
android:host="${SOURCEHOST}"
android:pathPattern="/series/..*"
android:scheme="https" />
android:scheme="${SOURCESCHEME}" />
</intent-filter>
</activity>
</application>

View File

@ -0,0 +1,3 @@
dependencies {
implementation(project(":lib:dataimage"))
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 816 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

View File

@ -1,80 +1,64 @@
package eu.kanade.tachiyomi.extension.en.apairof2
package eu.kanade.tachiyomi.multisrc.po2scans
import eu.kanade.tachiyomi.lib.dataimage.DataImageInterceptor
import eu.kanade.tachiyomi.lib.dataimage.dataImageAsUrl
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.interceptor.rateLimit
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"
abstract class PO2Scans(
override val name: String,
override val baseUrl: String,
override val lang: String,
private val dateFormat: SimpleDateFormat = SimpleDateFormat("dd MMMM, yy", Locale.ENGLISH),
) : ParsedHttpSource() {
override val supportsLatest = true
override val versionId = 2
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
override val client = network.cloudflareClient.newBuilder()
.addInterceptor(DataImageInterceptor())
.rateLimit(4)
.build()
override fun headersBuilder(): Headers.Builder = super.headersBuilder()
override fun headersBuilder() = super.headersBuilder()
.add("Referer", "$baseUrl/")
// popular
override fun popularMangaRequest(page: Int): Request {
return GET("$baseUrl/series", headers)
}
override fun popularMangaRequest(page: Int) = 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("abs:data-src")
}
override fun popularMangaFromElement(element: Element) = SManga.create().apply {
setUrlWithoutDomain(element.selectFirst("div > a")!!.absUrl("href"))
title = element.selectFirst("div > h2")!!.text()
thumbnail_url = element.selectFirst("img")?.absUrl("data-src")
}
// 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 latestUpdatesRequest(page: Int) = 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("abs:data-src")
override fun latestUpdatesFromElement(element: Element) = SManga.create().apply {
element.selectFirst("div.chap-title a")!!.let {
setUrlWithoutDomain(it.absUrl("href"))
title = it.text()
}
thumbnail_url = element.selectFirst("img")?.absUrl("data-src")
}
override fun latestUpdatesNextPageSelector() = popularMangaSelector()
override fun latestUpdatesNextPageSelector() = popularMangaNextPageSelector()
// search
override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> {
@ -83,15 +67,15 @@ class APairOf2 : ParsedHttpSource() {
}
val url = "/series/${query.substringAfter(SLUG_SEARCH_PREFIX)}"
return fetchMangaDetails(SManga.create().apply { this.url = url }).map {
it.url = url
MangasPage(listOf(it), false)
}
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 searchMangaRequest(page: Int, query: String, filters: FilterList) =
GET("$baseUrl/series?search=$query", headers)
override fun searchMangaSelector() = popularMangaSelector()
@ -111,39 +95,33 @@ class APairOf2 : ParsedHttpSource() {
}
}
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())
override fun chapterFromElement(element: Element) = SChapter.create().apply {
element.selectFirst("a")!!.let {
setUrlWithoutDomain(it.absUrl("href"))
name = it.text()
}
}
private fun parseDate(dateStr: String): Long {
return runCatching { DATE_FORMATTER.parse(dateStr)?.time }
.getOrNull() ?: 0L
date_upload = parseDate(element.select("div > div > span:nth-child(2)").text())
}
// page list
override fun pageListParse(document: Document): List<Page> {
return document.select(".swiper-slide img").mapIndexed { index, img ->
Page(
index = index,
imageUrl = img.imgAttr(),
)
override fun pageListParse(document: Document) =
document.select(".swiper-slide img").mapIndexed { index, img ->
Page(index, imageUrl = img.imgAttr())
}
override fun imageUrlParse(document: Document) = throw UnsupportedOperationException()
private val statusOngoing = listOf("ongoing", "devam ediyor")
private val statusCompleted = listOf("complete", "tamamlandı", "bitti")
private fun String.parseStatus(): Int {
return when (this.lowercase()) {
in statusOngoing -> SManga.ONGOING
in statusCompleted -> SManga.COMPLETED
else -> SManga.UNKNOWN
}
}
@ -153,15 +131,11 @@ class APairOf2 : ParsedHttpSource() {
else -> dataImageAsUrl("src")
}
override fun imageUrlParse(document: Document): String {
throw UnsupportedOperationException()
}
private fun parseDate(dateStr: String) =
runCatching { dateFormat.parse(dateStr)!!.time }
.getOrDefault(0L)
companion object {
private val DATE_FORMATTER by lazy {
SimpleDateFormat("dd MMMM, yy", Locale.ENGLISH)
}
const val SLUG_SEARCH_PREFIX = "slug:"
}
}

View File

@ -0,0 +1,24 @@
package eu.kanade.tachiyomi.multisrc.po2scans
import generator.ThemeSourceData.SingleLang
import generator.ThemeSourceGenerator
class PO2ScansGenerator : ThemeSourceGenerator {
override val themePkg = "po2scans"
override val themeClass = "PO2Scans"
override val baseVersionCode = 1
override val sources = listOf(
SingleLang("A Pair Of 2+", "https://po2scans.com", "en", className = "APairOf2", overrideVersionCode = 31),
SingleLang("Sadscans", "https://sadscans.com", "tr"),
)
companion object {
@JvmStatic
fun main(args: Array<String>) {
PO2ScansGenerator().createAll()
}
}
}

View File

@ -1,4 +1,4 @@
package eu.kanade.tachiyomi.extension.en.apairof2
package eu.kanade.tachiyomi.multisrc.po2scans
import android.app.Activity
import android.content.ActivityNotFoundException
@ -7,7 +7,7 @@ import android.os.Bundle
import android.util.Log
import kotlin.system.exitProcess
class APairOf2UrlActivity : Activity() {
class PO2ScansUrlActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val pathSegments = intent?.data?.pathSegments
@ -15,17 +15,17 @@ class APairOf2UrlActivity : Activity() {
val slug = pathSegments[1]
val mainIntent = Intent().apply {
action = "eu.kanade.tachiyomi.SEARCH"
putExtra("query", "${APairOf2.SLUG_SEARCH_PREFIX}$slug")
putExtra("query", "${PO2Scans.SLUG_SEARCH_PREFIX}$slug")
putExtra("filter", packageName)
}
try {
startActivity(mainIntent)
} catch (e: ActivityNotFoundException) {
Log.e("APairOf2UrlActivity", e.toString())
Log.e("PO2ScansUrlActivity", "Could not start activity", e)
}
} else {
Log.e("APairOf2UrlActivity", "could not parse uri from intent $intent")
Log.e("PO2ScansUrlActivity", "could not parse URI from intent $intent")
}
finish()

View File

@ -1,11 +0,0 @@
ext {
extName = 'A Pair of 2+'
extClass = '.APairOf2'
extVersionCode = 31
}
apply from: "$rootDir/common.gradle"
dependencies {
implementation project(':lib:dataimage')
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB