Compare commits
No commits in common. "5ecf338be0dd21937706e3284fc9d0edc5950e62" and "ac57f5e3dde6197b96a3ae66e311c3dfeac4ec1d" have entirely different histories.
5ecf338be0
...
ac57f5e3dd
|
@ -2,4 +2,4 @@ plugins {
|
||||||
id("lib-multisrc")
|
id("lib-multisrc")
|
||||||
}
|
}
|
||||||
|
|
||||||
baseVersionCode = 2
|
baseVersionCode = 1
|
||||||
|
|
|
@ -291,7 +291,7 @@ abstract class BlogTruyen(
|
||||||
override fun pageListParse(document: Document): List<Page> {
|
override fun pageListParse(document: Document): List<Page> {
|
||||||
val pages = mutableListOf<Page>()
|
val pages = mutableListOf<Page>()
|
||||||
|
|
||||||
document.select(".content > img, #content > img").forEachIndexed { i, e ->
|
document.select("#content > img").forEachIndexed { i, e ->
|
||||||
pages.add(Page(i, imageUrl = e.absUrl("src")))
|
pages.add(Page(i, imageUrl = e.absUrl("src")))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ import android.os.Bundle
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import kotlin.system.exitProcess
|
import kotlin.system.exitProcess
|
||||||
/**
|
/**
|
||||||
* Springboard that accepts https://1.readmanga.io/xxx intents and redirects them to
|
* Springboard that accepts https://readmanga.live/xxx intents and redirects them to
|
||||||
* the main tachiyomi process. The idea is to not install the intent filter unless
|
* the main tachiyomi process. The idea is to not install the intent filter unless
|
||||||
* you have this extension installed, but still let the main tachiyomi app control
|
* you have this extension installed, but still let the main tachiyomi app control
|
||||||
* things.
|
* things.
|
||||||
|
|
|
@ -2,7 +2,7 @@ plugins {
|
||||||
id("lib-multisrc")
|
id("lib-multisrc")
|
||||||
}
|
}
|
||||||
|
|
||||||
baseVersionCode = 27
|
baseVersionCode = 25
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
api(project(":lib:i18n"))
|
api(project(":lib:i18n"))
|
||||||
|
|
|
@ -72,8 +72,6 @@ abstract class HeanCms(
|
||||||
|
|
||||||
protected open val coverPath: String = ""
|
protected open val coverPath: String = ""
|
||||||
|
|
||||||
protected open val cdnUrl = apiUrl
|
|
||||||
|
|
||||||
protected open val mangaSubDirectory: String = "series"
|
protected open val mangaSubDirectory: String = "series"
|
||||||
|
|
||||||
protected open val dateFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ", Locale.US)
|
protected open val dateFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ", Locale.US)
|
||||||
|
@ -208,7 +206,7 @@ abstract class HeanCms(
|
||||||
|
|
||||||
val result = json.parseAs<HeanCmsQuerySearchDto>()
|
val result = json.parseAs<HeanCmsQuerySearchDto>()
|
||||||
val mangaList = result.data.map {
|
val mangaList = result.data.map {
|
||||||
it.toSManga(cdnUrl, coverPath, mangaSubDirectory)
|
it.toSManga(apiUrl, coverPath, mangaSubDirectory)
|
||||||
}
|
}
|
||||||
|
|
||||||
return MangasPage(mangaList, result.meta?.hasNextPage() ?: false)
|
return MangasPage(mangaList, result.meta?.hasNextPage() ?: false)
|
||||||
|
@ -244,7 +242,7 @@ abstract class HeanCms(
|
||||||
val seriesResult = result.getOrNull()
|
val seriesResult = result.getOrNull()
|
||||||
?: throw Exception(intl.format("url_changed_error", name, name))
|
?: throw Exception(intl.format("url_changed_error", name, name))
|
||||||
|
|
||||||
val seriesDetails = seriesResult.toSManga(cdnUrl, coverPath, mangaSubDirectory)
|
val seriesDetails = seriesResult.toSManga(apiUrl, coverPath, mangaSubDirectory)
|
||||||
|
|
||||||
return seriesDetails.apply {
|
return seriesDetails.apply {
|
||||||
status = status.takeUnless { it == SManga.UNKNOWN }
|
status = status.takeUnless { it == SManga.UNKNOWN }
|
||||||
|
@ -347,8 +345,8 @@ abstract class HeanCms(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun String.toAbsoluteUrl(): String {
|
private fun String.toAbsoluteUrl(): String {
|
||||||
return if (startsWith("https://") || startsWith("http://")) this else "$cdnUrl/$coverPath$this"
|
return if (startsWith("https://") || startsWith("http://")) this else "$apiUrl/$coverPath$this"
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun fetchImageUrl(page: Page): Observable<String> = Observable.just(page.imageUrl!!)
|
override fun fetchImageUrl(page: Page): Observable<String> = Observable.just(page.imageUrl!!)
|
||||||
|
|
|
@ -63,7 +63,7 @@ class HeanCmsSeriesDto(
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun toSManga(
|
fun toSManga(
|
||||||
cdnUrl: String,
|
apiUrl: String,
|
||||||
coverPath: String,
|
coverPath: String,
|
||||||
mangaSubDirectory: String,
|
mangaSubDirectory: String,
|
||||||
): SManga = SManga.create().apply {
|
): SManga = SManga.create().apply {
|
||||||
|
@ -79,7 +79,7 @@ class HeanCmsSeriesDto(
|
||||||
.sortedBy(HeanCmsTagDto::name)
|
.sortedBy(HeanCmsTagDto::name)
|
||||||
.joinToString { it.name }
|
.joinToString { it.name }
|
||||||
thumbnail_url = thumbnail.ifEmpty { null }
|
thumbnail_url = thumbnail.ifEmpty { null }
|
||||||
?.toAbsoluteThumbnailUrl(cdnUrl, coverPath)
|
?.toAbsoluteThumbnailUrl(apiUrl, coverPath)
|
||||||
status = this@HeanCmsSeriesDto.status?.toStatus() ?: SManga.UNKNOWN
|
status = this@HeanCmsSeriesDto.status?.toStatus() ?: SManga.UNKNOWN
|
||||||
url = "/$mangaSubDirectory/$slug#$id"
|
url = "/$mangaSubDirectory/$slug#$id"
|
||||||
}
|
}
|
||||||
|
@ -103,7 +103,6 @@ class HeanCmsChapterPayloadDto(
|
||||||
class HeanCmsChapterDto(
|
class HeanCmsChapterDto(
|
||||||
private val id: Int,
|
private val id: Int,
|
||||||
@SerialName("chapter_name") private val name: String,
|
@SerialName("chapter_name") private val name: String,
|
||||||
@SerialName("chapter_title") private val title: String? = null,
|
|
||||||
@SerialName("chapter_slug") private val slug: String,
|
@SerialName("chapter_slug") private val slug: String,
|
||||||
@SerialName("created_at") private val createdAt: String,
|
@SerialName("created_at") private val createdAt: String,
|
||||||
val price: Int? = null,
|
val price: Int? = null,
|
||||||
|
@ -115,10 +114,6 @@ class HeanCmsChapterDto(
|
||||||
): SChapter = SChapter.create().apply {
|
): SChapter = SChapter.create().apply {
|
||||||
name = this@HeanCmsChapterDto.name.trim()
|
name = this@HeanCmsChapterDto.name.trim()
|
||||||
|
|
||||||
if (title != null) {
|
|
||||||
name += " - ${title.trim()}"
|
|
||||||
}
|
|
||||||
|
|
||||||
if (price != 0) {
|
if (price != 0) {
|
||||||
name += " \uD83D\uDD12"
|
name += " \uD83D\uDD12"
|
||||||
}
|
}
|
||||||
|
@ -166,8 +161,8 @@ class HeanCmsGenreDto(
|
||||||
val name: String,
|
val name: String,
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun String.toAbsoluteThumbnailUrl(cdnUrl: String, coverPath: String): String {
|
private fun String.toAbsoluteThumbnailUrl(apiUrl: String, coverPath: String): String {
|
||||||
return if (startsWith("https://") || startsWith("http://")) this else "$cdnUrl/$coverPath$this"
|
return if (startsWith("https://") || startsWith("http://")) this else "$apiUrl/$coverPath$this"
|
||||||
}
|
}
|
||||||
|
|
||||||
fun String.toStatus(): Int = when (this) {
|
fun String.toStatus(): Int = when (this) {
|
||||||
|
|
|
@ -2,4 +2,4 @@ plugins {
|
||||||
id("lib-multisrc")
|
id("lib-multisrc")
|
||||||
}
|
}
|
||||||
|
|
||||||
baseVersionCode = 3
|
baseVersionCode = 1
|
||||||
|
|
|
@ -4,6 +4,7 @@ import eu.kanade.tachiyomi.source.model.SChapter
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.json.JsonPrimitive
|
import kotlinx.serialization.json.JsonPrimitive
|
||||||
|
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||||
import org.jsoup.Jsoup
|
import org.jsoup.Jsoup
|
||||||
import java.text.ParseException
|
import java.text.ParseException
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
|
@ -30,10 +31,14 @@ class Manga(
|
||||||
private val seriesStatus: String? = null,
|
private val seriesStatus: String? = null,
|
||||||
val genres: List<Genre> = emptyList(),
|
val genres: List<Genre> = emptyList(),
|
||||||
) {
|
) {
|
||||||
fun toSManga() = SManga.create().apply {
|
fun toSManga(baseUrl: String) = SManga.create().apply {
|
||||||
url = "$slug#$id"
|
url = "$slug#$id"
|
||||||
title = postTitle
|
title = postTitle
|
||||||
thumbnail_url = featuredImage
|
thumbnail_url = "$baseUrl/_next/image".toHttpUrl().newBuilder().apply {
|
||||||
|
addQueryParameter("url", featuredImage)
|
||||||
|
addQueryParameter("w", "828")
|
||||||
|
addQueryParameter("q", "75")
|
||||||
|
}.toString()
|
||||||
author = this@Manga.author?.takeUnless { it.isEmpty() }
|
author = this@Manga.author?.takeUnless { it.isEmpty() }
|
||||||
artist = this@Manga.artist?.takeUnless { it.isEmpty() }
|
artist = this@Manga.artist?.takeUnless { it.isEmpty() }
|
||||||
description = buildString {
|
description = buildString {
|
||||||
|
|
|
@ -14,7 +14,6 @@ import kotlinx.serialization.json.Json
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
import rx.Observable
|
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
|
||||||
abstract class Iken(
|
abstract class Iken(
|
||||||
|
@ -44,7 +43,7 @@ abstract class Iken(
|
||||||
it.genres.map { genre ->
|
it.genres.map { genre ->
|
||||||
genre.name to genre.id.toString()
|
genre.name to genre.id.toString()
|
||||||
}
|
}
|
||||||
}.distinct()
|
}
|
||||||
}
|
}
|
||||||
.associateBy { it.slug }
|
.associateBy { it.slug }
|
||||||
}
|
}
|
||||||
|
@ -57,7 +56,7 @@ abstract class Iken(
|
||||||
.map { it.absUrl("href").substringAfterLast("/series/") }
|
.map { it.absUrl("href").substringAfterLast("/series/") }
|
||||||
|
|
||||||
val entries = slugs.mapNotNull {
|
val entries = slugs.mapNotNull {
|
||||||
titleCache[it]?.toSManga()
|
titleCache[it]?.toSManga(baseUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
return MangasPage(entries, false)
|
return MangasPage(entries, false)
|
||||||
|
@ -85,7 +84,7 @@ abstract class Iken(
|
||||||
|
|
||||||
val entries = data.posts
|
val entries = data.posts
|
||||||
.filterNot { it.isNovel }
|
.filterNot { it.isNovel }
|
||||||
.map { it.toSManga() }
|
.map { it.toSManga(baseUrl) }
|
||||||
|
|
||||||
val hasNextPage = data.totalCount > (page * perPage)
|
val hasNextPage = data.totalCount > (page * perPage)
|
||||||
|
|
||||||
|
@ -99,28 +98,32 @@ abstract class Iken(
|
||||||
Filter.Header("Open popular mangas if genre filter is empty"),
|
Filter.Header("Open popular mangas if genre filter is empty"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
override fun mangaDetailsRequest(manga: SManga): Request {
|
||||||
|
val id = manga.url.substringAfterLast("#")
|
||||||
|
val url = "$baseUrl/api/chapters?postId=$id&skip=0&take=1000&order=desc&userid="
|
||||||
|
|
||||||
|
return GET(url, headers)
|
||||||
|
}
|
||||||
|
|
||||||
override fun getMangaUrl(manga: SManga): String {
|
override fun getMangaUrl(manga: SManga): String {
|
||||||
val slug = manga.url.substringBeforeLast("#")
|
val slug = manga.url.substringBeforeLast("#")
|
||||||
|
|
||||||
return "$baseUrl/series/$slug"
|
return "$baseUrl/series/$slug"
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun fetchMangaDetails(manga: SManga): Observable<SManga> {
|
override fun mangaDetailsParse(response: Response): SManga {
|
||||||
val slug = manga.url.substringBeforeLast("#")
|
val data = response.parseAs<Post<Manga>>()
|
||||||
val update = titleCache[slug]?.toSManga() ?: manga
|
|
||||||
|
|
||||||
return Observable.just(update)
|
assert(!data.post.isNovel) { "Novels are unsupported" }
|
||||||
|
|
||||||
|
// genres are only returned in search call
|
||||||
|
// and not when fetching details
|
||||||
|
return data.post.toSManga(baseUrl).apply {
|
||||||
|
genre = titleCache[data.post.slug]?.getGenres()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun mangaDetailsParse(response: Response) =
|
override fun chapterListRequest(manga: SManga) = mangaDetailsRequest(manga)
|
||||||
throw UnsupportedOperationException()
|
|
||||||
|
|
||||||
override fun chapterListRequest(manga: SManga): Request {
|
|
||||||
val id = manga.url.substringAfterLast("#")
|
|
||||||
val url = "$baseUrl/api/chapters?postId=$id&skip=0&take=1000&order=desc&userid="
|
|
||||||
|
|
||||||
return GET(url, headers)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun chapterListParse(response: Response): List<SChapter> {
|
override fun chapterListParse(response: Response): List<SChapter> {
|
||||||
val data = response.parseAs<Post<ChapterListResponse>>()
|
val data = response.parseAs<Post<ChapterListResponse>>()
|
||||||
|
@ -135,7 +138,7 @@ abstract class Iken(
|
||||||
override fun pageListParse(response: Response): List<Page> {
|
override fun pageListParse(response: Response): List<Page> {
|
||||||
val document = response.asJsoup()
|
val document = response.asJsoup()
|
||||||
|
|
||||||
return document.select("main section img").mapIndexed { idx, img ->
|
return document.select("main section > img").mapIndexed { idx, img ->
|
||||||
Page(idx, imageUrl = img.absUrl("src"))
|
Page(idx, imageUrl = img.absUrl("src"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
<application>
|
<application>
|
||||||
<activity
|
<activity
|
||||||
android:name=".pt.exhentainetbr.ExHentaiNetBRUrlActivity"
|
android:name="eu.kanade.tachiyomi.multisrc.lectortmo.LectorTmoUrlActivity"
|
||||||
android:excludeFromRecents="true"
|
android:excludeFromRecents="true"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:theme="@android:style/Theme.NoDisplay">
|
android:theme="@android:style/Theme.NoDisplay">
|
||||||
|
@ -11,11 +12,10 @@
|
||||||
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
|
||||||
<data
|
<data
|
||||||
android:host="exhentai.net.br"
|
android:host="${SOURCEHOST}"
|
||||||
android:pathPattern="/manga/..*"
|
android:pathPattern="/library/..*/..*/..*"
|
||||||
android:scheme="https" />
|
android:scheme="${SOURCESCHEME}" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
</application>
|
</application>
|
|
@ -0,0 +1,5 @@
|
||||||
|
plugins {
|
||||||
|
id("lib-multisrc")
|
||||||
|
}
|
||||||
|
|
||||||
|
baseVersionCode = 6
|
|
@ -1,4 +1,4 @@
|
||||||
package eu.kanade.tachiyomi.extension.es.lectortmo
|
package eu.kanade.tachiyomi.multisrc.lectortmo
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
|
@ -42,7 +42,6 @@ abstract class LectorTmo(
|
||||||
override val name: String,
|
override val name: String,
|
||||||
override val baseUrl: String,
|
override val baseUrl: String,
|
||||||
override val lang: String,
|
override val lang: String,
|
||||||
private val rateLimitClient: OkHttpClient,
|
|
||||||
) : ParsedHttpSource(), ConfigurableSource {
|
) : ParsedHttpSource(), ConfigurableSource {
|
||||||
|
|
||||||
private val preferences: SharedPreferences by lazy {
|
private val preferences: SharedPreferences by lazy {
|
||||||
|
@ -92,7 +91,7 @@ abstract class LectorTmo(
|
||||||
}
|
}
|
||||||
|
|
||||||
private val ignoreSslClient: OkHttpClient by lazy {
|
private val ignoreSslClient: OkHttpClient by lazy {
|
||||||
rateLimitClient.newBuilder()
|
network.cloudflareClient.newBuilder()
|
||||||
.ignoreAllSSLErrors()
|
.ignoreAllSSLErrors()
|
||||||
.followRedirects(false)
|
.followRedirects(false)
|
||||||
.rateLimit(
|
.rateLimit(
|
||||||
|
@ -104,7 +103,7 @@ abstract class LectorTmo(
|
||||||
|
|
||||||
private var lastCFDomain: String = ""
|
private var lastCFDomain: String = ""
|
||||||
override val client: OkHttpClient by lazy {
|
override val client: OkHttpClient by lazy {
|
||||||
rateLimitClient.newBuilder()
|
network.cloudflareClient.newBuilder()
|
||||||
.addInterceptor { chain ->
|
.addInterceptor { chain ->
|
||||||
val request = chain.request()
|
val request = chain.request()
|
||||||
val url = request.url
|
val url = request.url
|
||||||
|
@ -245,8 +244,6 @@ abstract class LectorTmo(
|
||||||
return super.getMangaUrl(manga)
|
return super.getMangaUrl(manga)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun mangaDetailsRequest(manga: SManga) = GET(baseUrl + manga.url, tmoHeaders)
|
|
||||||
|
|
||||||
override fun mangaDetailsParse(document: Document) = SManga.create().apply {
|
override fun mangaDetailsParse(document: Document) = SManga.create().apply {
|
||||||
title = document.select("h2.element-subtitle").text()
|
title = document.select("h2.element-subtitle").text()
|
||||||
document.select("h5.card-title").let {
|
document.select("h5.card-title").let {
|
||||||
|
@ -274,8 +271,6 @@ abstract class LectorTmo(
|
||||||
return super.getChapterUrl(chapter)
|
return super.getChapterUrl(chapter)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun chapterListRequest(manga: SManga) = mangaDetailsRequest(manga)
|
|
||||||
|
|
||||||
override fun chapterListParse(response: Response): List<SChapter> {
|
override fun chapterListParse(response: Response): List<SChapter> {
|
||||||
val document = response.asJsoup()
|
val document = response.asJsoup()
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package eu.kanade.tachiyomi.extension.es.lectortmo
|
package eu.kanade.tachiyomi.multisrc.lectortmo
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.source.model.Filter
|
import eu.kanade.tachiyomi.source.model.Filter
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package eu.kanade.tachiyomi.extension.es.lectortmo
|
package eu.kanade.tachiyomi.multisrc.lectortmo
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.ActivityNotFoundException
|
import android.content.ActivityNotFoundException
|
||||||
|
@ -19,7 +19,7 @@ class LectorTmoUrlActivity : Activity() {
|
||||||
|
|
||||||
val mainIntent = Intent().apply {
|
val mainIntent = Intent().apply {
|
||||||
action = "eu.kanade.tachiyomi.SEARCH"
|
action = "eu.kanade.tachiyomi.SEARCH"
|
||||||
putExtra("query", "slug:$type/$id/$slug")
|
putExtra("query", "${LectorTmo.PREFIX_SLUG_SEARCH}$type/$id/$slug")
|
||||||
putExtra("filter", packageName)
|
putExtra("filter", packageName)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import android.content.SharedPreferences
|
||||||
import androidx.preference.PreferenceScreen
|
import androidx.preference.PreferenceScreen
|
||||||
import androidx.preference.SwitchPreferenceCompat
|
import androidx.preference.SwitchPreferenceCompat
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
|
import eu.kanade.tachiyomi.network.await
|
||||||
import eu.kanade.tachiyomi.source.ConfigurableSource
|
import eu.kanade.tachiyomi.source.ConfigurableSource
|
||||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
|
@ -31,18 +32,8 @@ abstract class MangaThemesiaAlt(
|
||||||
private val randomUrlPrefKey: String = "pref_auto_random_url",
|
private val randomUrlPrefKey: String = "pref_auto_random_url",
|
||||||
) : MangaThemesia(name, baseUrl, lang, mangaUrlDirectory, dateFormat), ConfigurableSource {
|
) : MangaThemesia(name, baseUrl, lang, mangaUrlDirectory, dateFormat), ConfigurableSource {
|
||||||
|
|
||||||
protected open val listUrl = "$mangaUrlDirectory/list-mode/"
|
|
||||||
protected open val listSelector = "div#content div.soralist ul li a.series"
|
|
||||||
|
|
||||||
protected val preferences: SharedPreferences by lazy {
|
protected val preferences: SharedPreferences by lazy {
|
||||||
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000).also {
|
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
||||||
if (it.contains("__random_part_cache")) {
|
|
||||||
it.edit().remove("__random_part_cache").apply()
|
|
||||||
}
|
|
||||||
if (it.contains("titles_without_random_part")) {
|
|
||||||
it.edit().remove("titles_without_random_part").apply()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
||||||
|
@ -56,11 +47,183 @@ abstract class MangaThemesiaAlt(
|
||||||
|
|
||||||
private fun getRandomUrlPref() = preferences.getBoolean(randomUrlPrefKey, true)
|
private fun getRandomUrlPref() = preferences.getBoolean(randomUrlPrefKey, true)
|
||||||
|
|
||||||
|
private var randomPartCache = SuspendLazy(::getUpdatedRandomPart) { preferences.randomPartCache = it }
|
||||||
|
|
||||||
|
// cache in preference for webview urls
|
||||||
|
private var SharedPreferences.randomPartCache: String
|
||||||
|
get() = getString("__random_part_cache", "")!!
|
||||||
|
set(newValue) = edit().putString("__random_part_cache", newValue).apply()
|
||||||
|
|
||||||
|
// some new titles don't have random part
|
||||||
|
// se we save their slug and when they
|
||||||
|
// finally add it, we remove the slug in the interceptor
|
||||||
|
private var SharedPreferences.titlesWithoutRandomPart: MutableSet<String>
|
||||||
|
get() {
|
||||||
|
val value = getString("titles_without_random_part", null)
|
||||||
|
?: return mutableSetOf()
|
||||||
|
|
||||||
|
return json.decodeFromString(value)
|
||||||
|
}
|
||||||
|
set(newValue) {
|
||||||
|
val encodedValue = json.encodeToString(newValue)
|
||||||
|
|
||||||
|
edit().putString("titles_without_random_part", encodedValue).apply()
|
||||||
|
}
|
||||||
|
|
||||||
|
protected open fun getRandomPartFromUrl(url: String): String {
|
||||||
|
val slug = url
|
||||||
|
.removeSuffix("/")
|
||||||
|
.substringAfterLast("/")
|
||||||
|
|
||||||
|
return slugRegex.find(slug)?.groupValues?.get(1) ?: ""
|
||||||
|
}
|
||||||
|
|
||||||
|
protected open fun getRandomPartFromResponse(response: Response): String {
|
||||||
|
return response.asJsoup()
|
||||||
|
.selectFirst(searchMangaSelector())!!
|
||||||
|
.select("a").attr("href")
|
||||||
|
.let(::getRandomPartFromUrl)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected suspend fun getUpdatedRandomPart(): String =
|
||||||
|
client.newCall(GET("$baseUrl$mangaUrlDirectory/", headers))
|
||||||
|
.await()
|
||||||
|
.use(::getRandomPartFromResponse)
|
||||||
|
|
||||||
|
override fun searchMangaParse(response: Response): MangasPage {
|
||||||
|
val mp = super.searchMangaParse(response)
|
||||||
|
|
||||||
|
if (!getRandomUrlPref()) return mp
|
||||||
|
|
||||||
|
// extract random part during browsing to avoid extra call
|
||||||
|
mp.mangas.firstOrNull()?.run {
|
||||||
|
val randomPart = getRandomPartFromUrl(url)
|
||||||
|
|
||||||
|
if (randomPart.isNotEmpty()) {
|
||||||
|
randomPartCache.set(randomPart)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val mangas = mp.mangas.toPermanentMangaUrls()
|
||||||
|
|
||||||
|
return MangasPage(mangas, mp.hasNextPage)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun List<SManga>.toPermanentMangaUrls(): List<SManga> {
|
||||||
|
// some absolutely new titles don't have the random part yet
|
||||||
|
// save them so we know where to not apply it
|
||||||
|
val foundTitlesWithoutRandomPart = mutableSetOf<String>()
|
||||||
|
|
||||||
|
for (i in indices) {
|
||||||
|
val slug = this[i].url
|
||||||
|
.removeSuffix("/")
|
||||||
|
.substringAfterLast("/")
|
||||||
|
|
||||||
|
if (slugRegex.find(slug)?.groupValues?.get(1) == null) {
|
||||||
|
foundTitlesWithoutRandomPart.add(slug)
|
||||||
|
}
|
||||||
|
|
||||||
|
val permaSlug = slug
|
||||||
|
.replaceFirst(slugRegex, "")
|
||||||
|
|
||||||
|
this[i].url = "$mangaUrlDirectory/$permaSlug/"
|
||||||
|
}
|
||||||
|
|
||||||
|
if (foundTitlesWithoutRandomPart.isNotEmpty()) {
|
||||||
|
foundTitlesWithoutRandomPart.addAll(preferences.titlesWithoutRandomPart)
|
||||||
|
|
||||||
|
preferences.titlesWithoutRandomPart = foundTitlesWithoutRandomPart
|
||||||
|
}
|
||||||
|
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
protected open val slugRegex = Regex("""^(\d+-)""")
|
||||||
|
|
||||||
|
override val client = super.client.newBuilder()
|
||||||
|
.addInterceptor { chain ->
|
||||||
|
val request = chain.request()
|
||||||
|
val response = chain.proceed(request)
|
||||||
|
|
||||||
|
if (request.url.fragment != "titlesWithoutRandomPart") {
|
||||||
|
return@addInterceptor response
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!response.isSuccessful && response.code == 404) {
|
||||||
|
response.close()
|
||||||
|
|
||||||
|
val slug = request.url.toString()
|
||||||
|
.substringBefore("#")
|
||||||
|
.removeSuffix("/")
|
||||||
|
.substringAfterLast("/")
|
||||||
|
|
||||||
|
preferences.titlesWithoutRandomPart.run {
|
||||||
|
remove(slug)
|
||||||
|
|
||||||
|
preferences.titlesWithoutRandomPart = this
|
||||||
|
}
|
||||||
|
|
||||||
|
val randomPart = randomPartCache.blockingGet()
|
||||||
|
val newRequest = request.newBuilder()
|
||||||
|
.url("$baseUrl$mangaUrlDirectory/$randomPart$slug/")
|
||||||
|
.build()
|
||||||
|
|
||||||
|
return@addInterceptor chain.proceed(newRequest)
|
||||||
|
}
|
||||||
|
|
||||||
|
return@addInterceptor response
|
||||||
|
}
|
||||||
|
.build()
|
||||||
|
|
||||||
|
override fun mangaDetailsRequest(manga: SManga): Request {
|
||||||
|
if (!getRandomUrlPref()) return super.mangaDetailsRequest(manga)
|
||||||
|
|
||||||
|
val slug = manga.url
|
||||||
|
.substringBefore("#")
|
||||||
|
.removeSuffix("/")
|
||||||
|
.substringAfterLast("/")
|
||||||
|
.replaceFirst(slugRegex, "")
|
||||||
|
|
||||||
|
if (preferences.titlesWithoutRandomPart.contains(slug)) {
|
||||||
|
return GET("$baseUrl${manga.url}#titlesWithoutRandomPart")
|
||||||
|
}
|
||||||
|
|
||||||
|
val randomPart = randomPartCache.blockingGet()
|
||||||
|
|
||||||
|
return GET("$baseUrl$mangaUrlDirectory/$randomPart$slug/", headers)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getMangaUrl(manga: SManga): String {
|
||||||
|
if (!getRandomUrlPref()) return super.getMangaUrl(manga)
|
||||||
|
|
||||||
|
val slug = manga.url
|
||||||
|
.substringBefore("#")
|
||||||
|
.removeSuffix("/")
|
||||||
|
.substringAfterLast("/")
|
||||||
|
.replaceFirst(slugRegex, "")
|
||||||
|
|
||||||
|
if (preferences.titlesWithoutRandomPart.contains(slug)) {
|
||||||
|
return "$baseUrl${manga.url}"
|
||||||
|
}
|
||||||
|
|
||||||
|
val randomPart = randomPartCache.peek() ?: preferences.randomPartCache
|
||||||
|
|
||||||
|
return "$baseUrl$mangaUrlDirectory/$randomPart$slug/"
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun chapterListRequest(manga: SManga) = mangaDetailsRequest(manga)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class SuspendLazy(
|
||||||
|
private val initializer: suspend () -> String,
|
||||||
|
private val saveCache: (String) -> Unit,
|
||||||
|
) {
|
||||||
|
|
||||||
private val mutex = Mutex()
|
private val mutex = Mutex()
|
||||||
private var cachedValue: SoftReference<Map<String, String>>? = null
|
private var cachedValue: SoftReference<String>? = null
|
||||||
private var fetchTime = 0L
|
private var fetchTime = 0L
|
||||||
|
|
||||||
private suspend fun getUrlMapInternal(): Map<String, String> {
|
suspend fun get(): String {
|
||||||
if (fetchTime + 3600000 < System.currentTimeMillis()) {
|
if (fetchTime + 3600000 < System.currentTimeMillis()) {
|
||||||
// reset cache
|
// reset cache
|
||||||
cachedValue = null
|
cachedValue = null
|
||||||
|
@ -75,104 +238,22 @@ abstract class MangaThemesiaAlt(
|
||||||
return it
|
return it
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchUrlMap().also {
|
initializer().also { set(it) }
|
||||||
cachedValue = SoftReference(it)
|
|
||||||
fetchTime = System.currentTimeMillis()
|
|
||||||
preferences.urlMapCache = it
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun fetchUrlMap(): Map<String, String> {
|
fun set(newVal: String) {
|
||||||
client.newCall(GET("$baseUrl$listUrl", headers)).execute().use { response ->
|
cachedValue = SoftReference(newVal)
|
||||||
val document = response.asJsoup()
|
fetchTime = System.currentTimeMillis()
|
||||||
|
|
||||||
return document.select(listSelector).associate {
|
saveCache(newVal)
|
||||||
val url = it.absUrl("href")
|
|
||||||
|
|
||||||
val slug = url.removeSuffix("/")
|
|
||||||
.substringAfterLast("/")
|
|
||||||
|
|
||||||
val permaSlug = slug
|
|
||||||
.replaceFirst(slugRegex, "")
|
|
||||||
|
|
||||||
permaSlug to slug
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun getUrlMap(cached: Boolean = false): Map<String, String> {
|
fun peek(): String? {
|
||||||
return if (cached && cachedValue == null) {
|
return cachedValue?.get()
|
||||||
preferences.urlMapCache
|
|
||||||
} else {
|
|
||||||
runBlocking { getUrlMapInternal() }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// cache in preference for webview urls
|
fun blockingGet(): String {
|
||||||
private var SharedPreferences.urlMapCache: Map<String, String>
|
return runBlocking { get() }
|
||||||
get(): Map<String, String> {
|
|
||||||
val value = getString("url_map_cache", "{}")!!
|
|
||||||
return try {
|
|
||||||
json.decodeFromString(value)
|
|
||||||
} catch (_: Exception) {
|
|
||||||
emptyMap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
set(newMap) = edit().putString("url_map_cache", json.encodeToString(newMap)).apply()
|
|
||||||
|
|
||||||
override fun searchMangaParse(response: Response): MangasPage {
|
|
||||||
val mp = super.searchMangaParse(response)
|
|
||||||
|
|
||||||
if (!getRandomUrlPref()) return mp
|
|
||||||
|
|
||||||
val mangas = mp.mangas.toPermanentMangaUrls()
|
|
||||||
|
|
||||||
return MangasPage(mangas, mp.hasNextPage)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun List<SManga>.toPermanentMangaUrls(): List<SManga> {
|
|
||||||
return onEach {
|
|
||||||
val slug = it.url
|
|
||||||
.removeSuffix("/")
|
|
||||||
.substringAfterLast("/")
|
|
||||||
|
|
||||||
val permaSlug = slug
|
|
||||||
.replaceFirst(slugRegex, "")
|
|
||||||
|
|
||||||
it.url = "$mangaUrlDirectory/$permaSlug/"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected open val slugRegex = Regex("""^(\d+-)""")
|
|
||||||
|
|
||||||
override fun mangaDetailsRequest(manga: SManga): Request {
|
|
||||||
if (!getRandomUrlPref()) return super.mangaDetailsRequest(manga)
|
|
||||||
|
|
||||||
val slug = manga.url
|
|
||||||
.substringBefore("#")
|
|
||||||
.removeSuffix("/")
|
|
||||||
.substringAfterLast("/")
|
|
||||||
.replaceFirst(slugRegex, "")
|
|
||||||
|
|
||||||
val randomSlug = getUrlMap()[slug] ?: slug
|
|
||||||
|
|
||||||
return GET("$baseUrl$mangaUrlDirectory/$randomSlug/", headers)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getMangaUrl(manga: SManga): String {
|
|
||||||
if (!getRandomUrlPref()) return super.getMangaUrl(manga)
|
|
||||||
|
|
||||||
val slug = manga.url
|
|
||||||
.substringBefore("#")
|
|
||||||
.removeSuffix("/")
|
|
||||||
.substringAfterLast("/")
|
|
||||||
.replaceFirst(slugRegex, "")
|
|
||||||
|
|
||||||
val randomSlug = getUrlMap(true)[slug] ?: slug
|
|
||||||
|
|
||||||
return "$baseUrl$mangaUrlDirectory/$randomSlug/"
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun chapterListRequest(manga: SManga) = mangaDetailsRequest(manga)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
ext {
|
ext {
|
||||||
extName = 'Bato.to'
|
extName = 'Bato.to'
|
||||||
extClass = '.BatoToFactory'
|
extClass = '.BatoToFactory'
|
||||||
extVersionCode = 37
|
extVersionCode = 36
|
||||||
isNsfw = true
|
isNsfw = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -384,14 +384,11 @@ open class BatoTo(
|
||||||
val chapter = SChapter.create()
|
val chapter = SChapter.create()
|
||||||
val urlElement = element.select("a.chapt")
|
val urlElement = element.select("a.chapt")
|
||||||
val group = element.select("div.extra > a:not(.ps-3)").text()
|
val group = element.select("div.extra > a:not(.ps-3)").text()
|
||||||
val user = element.select("div.extra > a.ps-3").text()
|
|
||||||
val time = element.select("div.extra > i.ps-3").text()
|
val time = element.select("div.extra > i.ps-3").text()
|
||||||
chapter.setUrlWithoutDomain(urlElement.attr("href"))
|
chapter.setUrlWithoutDomain(urlElement.attr("href"))
|
||||||
chapter.name = urlElement.text()
|
chapter.name = urlElement.text()
|
||||||
chapter.scanlator = when {
|
if (group != "") {
|
||||||
group.isNotBlank() -> group
|
chapter.scanlator = group
|
||||||
user.isNotBlank() -> user
|
|
||||||
else -> "Unknown"
|
|
||||||
}
|
}
|
||||||
if (time != "") {
|
if (time != "") {
|
||||||
chapter.date_upload = parseChapterDate(time)
|
chapter.date_upload = parseChapterDate(time)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
ext {
|
ext {
|
||||||
extName = 'Comick'
|
extName = 'Comick'
|
||||||
extClass = '.ComickFactory'
|
extClass = '.ComickFactory'
|
||||||
extVersionCode = 47
|
extVersionCode = 46
|
||||||
isNsfw = true
|
isNsfw = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -463,16 +463,7 @@ abstract class Comick(
|
||||||
|
|
||||||
override fun pageListParse(response: Response): List<Page> {
|
override fun pageListParse(response: Response): List<Page> {
|
||||||
val result = response.parseAs<PageList>()
|
val result = response.parseAs<PageList>()
|
||||||
val images = result.chapter.images.ifEmpty {
|
return result.chapter.images.mapIndexedNotNull { index, data ->
|
||||||
// cache busting
|
|
||||||
val url = response.request.url.newBuilder()
|
|
||||||
.addQueryParameter("_", System.currentTimeMillis().toString())
|
|
||||||
.build()
|
|
||||||
|
|
||||||
client.newCall(GET(url, headers)).execute()
|
|
||||||
.parseAs<PageList>().chapter.images
|
|
||||||
}
|
|
||||||
return images.mapIndexedNotNull { index, data ->
|
|
||||||
if (data.url == null) null else Page(index = index, imageUrl = data.url)
|
if (data.url == null) null else Page(index = index, imageUrl = data.url)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Before Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 4.8 KiB |
Before Width: | Height: | Size: 9.6 KiB |
Before Width: | Height: | Size: 14 KiB |
|
@ -1,127 +0,0 @@
|
||||||
package eu.kanade.tachiyomi.extension.all.foamgirl
|
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.network.GET
|
|
||||||
import eu.kanade.tachiyomi.source.model.FilterList
|
|
||||||
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.HttpUrl.Companion.toHttpUrl
|
|
||||||
import okhttp3.Request
|
|
||||||
import org.jsoup.nodes.Document
|
|
||||||
import org.jsoup.nodes.Element
|
|
||||||
import rx.Observable
|
|
||||||
import java.text.ParseException
|
|
||||||
import java.text.SimpleDateFormat
|
|
||||||
import java.util.Locale
|
|
||||||
|
|
||||||
class FoamGirl() : ParsedHttpSource() {
|
|
||||||
override val baseUrl = "https://foamgirl.net"
|
|
||||||
override val lang = "all"
|
|
||||||
override val name = "FoamGirl"
|
|
||||||
override val supportsLatest = false
|
|
||||||
|
|
||||||
override fun headersBuilder() = super.headersBuilder()
|
|
||||||
.add("Referer", "$baseUrl/")
|
|
||||||
|
|
||||||
// Popular
|
|
||||||
override fun popularMangaFromElement(element: Element) = SManga.create().apply {
|
|
||||||
thumbnail_url = element.select("img").attr("data-original")
|
|
||||||
title = element.select("a.meta-title").text()
|
|
||||||
setUrlWithoutDomain(element.select("a").attr("href"))
|
|
||||||
initialized = true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun fetchMangaDetails(manga: SManga): Observable<SManga> {
|
|
||||||
return Observable.just(manga)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun mangaDetailsParse(document: Document): SManga {
|
|
||||||
throw UnsupportedOperationException()
|
|
||||||
}
|
|
||||||
override fun popularMangaNextPageSelector() = "a.next"
|
|
||||||
override fun popularMangaRequest(page: Int): Request {
|
|
||||||
return GET("$baseUrl/page/$page", headers)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun popularMangaSelector() = ".update_area .i_list"
|
|
||||||
|
|
||||||
// Search
|
|
||||||
|
|
||||||
override fun searchMangaFromElement(element: Element) = popularMangaFromElement(element)
|
|
||||||
override fun searchMangaNextPageSelector() = popularMangaNextPageSelector()
|
|
||||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
|
||||||
return GET(
|
|
||||||
baseUrl.toHttpUrl().newBuilder().apply {
|
|
||||||
addPathSegment("page")
|
|
||||||
addPathSegment("$page")
|
|
||||||
addQueryParameter("post_type", "post")
|
|
||||||
addQueryParameter("s", query)
|
|
||||||
}.build(),
|
|
||||||
headers,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun searchMangaSelector() = popularMangaSelector()
|
|
||||||
|
|
||||||
override fun pageListParse(document: Document): List<Page> {
|
|
||||||
val pages = mutableListOf<Page>()
|
|
||||||
val imageCount = document.select(".post_title_topimg").text().substringAfter("(").substringBefore("P").toInt()
|
|
||||||
val imageUrl = document.select(".imageclick-imgbox").attr("href").toHttpUrl()
|
|
||||||
val imagePrefix = imageUrl.pathSegments.last().substringBefore(".").toLong() / 10
|
|
||||||
for (i in 0 until imageCount) {
|
|
||||||
pages.add(
|
|
||||||
Page(
|
|
||||||
i,
|
|
||||||
imageUrl = imageUrl.newBuilder().apply {
|
|
||||||
removePathSegment(imageUrl.pathSize - 1)
|
|
||||||
addPathSegment("${imagePrefix}${i + 2}.jpg")
|
|
||||||
}.build().toString(),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return pages
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun chapterFromElement(element: Element) = SChapter.create().apply {
|
|
||||||
setUrlWithoutDomain(element.select("link[rel=canonical]").attr("abs:href"))
|
|
||||||
chapter_number = 0F
|
|
||||||
name = "GALLERY"
|
|
||||||
date_upload = getDate(element.select("span.image-info-time").text().substring(1))
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun chapterListSelector() = "html"
|
|
||||||
|
|
||||||
// Pages
|
|
||||||
override fun imageUrlParse(document: Document): String = throw UnsupportedOperationException()
|
|
||||||
|
|
||||||
override fun latestUpdatesFromElement(element: Element): SManga {
|
|
||||||
throw UnsupportedOperationException()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun latestUpdatesNextPageSelector(): String? {
|
|
||||||
throw UnsupportedOperationException()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun latestUpdatesRequest(page: Int): Request {
|
|
||||||
throw UnsupportedOperationException()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun latestUpdatesSelector(): String {
|
|
||||||
throw UnsupportedOperationException()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getDate(str: String): Long {
|
|
||||||
return try {
|
|
||||||
DATE_FORMAT.parse(str)?.time ?: 0L
|
|
||||||
} catch (e: ParseException) {
|
|
||||||
0L
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private val DATE_FORMAT by lazy {
|
|
||||||
SimpleDateFormat("yyyy.M.d", Locale.ENGLISH)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +1,7 @@
|
||||||
ext {
|
ext {
|
||||||
extName = 'Hentai Cosplay'
|
extName = 'Hentai Cosplay'
|
||||||
extClass = '.HentaiCosplay'
|
extClass = '.HentaiCosplay'
|
||||||
extVersionCode = 4
|
extVersionCode = 3
|
||||||
isNsfw = true
|
isNsfw = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ class HentaiCosplay : HttpSource() {
|
||||||
|
|
||||||
override val name = "Hentai Cosplay"
|
override val name = "Hentai Cosplay"
|
||||||
|
|
||||||
override val baseUrl = "https://hentai-cosplay-xxx.com"
|
override val baseUrl = "https://hentai-cosplays.com"
|
||||||
|
|
||||||
override val lang = "all"
|
override val lang = "all"
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
ext {
|
ext {
|
||||||
extName = 'Xmanhwa'
|
extName = 'MangaTop.site'
|
||||||
extClass = '.Xmanhwa'
|
extClass = '.MangaTopSite'
|
||||||
themePkg = 'madara'
|
themePkg = 'madara'
|
||||||
baseUrl = 'https://www.xmanhwa.me'
|
baseUrl = 'https://mangatop.site'
|
||||||
overrideVersionCode = 0
|
overrideVersionCode = 0
|
||||||
isNsfw = true
|
isNsfw = true
|
||||||
}
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
package eu.kanade.tachiyomi.extension.all.mangatopsite
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
|
class MangaTopSite : Madara(
|
||||||
|
"MangaTop.site",
|
||||||
|
"https://mangatop.site",
|
||||||
|
"all",
|
||||||
|
dateFormat = SimpleDateFormat("d MMM yyyy", Locale.ENGLISH),
|
||||||
|
) {
|
||||||
|
override val useNewChapterEndpoint = false
|
||||||
|
override val chapterUrlSuffix = ""
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
ext {
|
ext {
|
||||||
extName = 'NHentai'
|
extName = 'NHentai'
|
||||||
extClass = '.NHFactory'
|
extClass = '.NHFactory'
|
||||||
extVersionCode = 41
|
extVersionCode = 40
|
||||||
isNsfw = true
|
isNsfw = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -220,7 +220,7 @@ open class NHentai(
|
||||||
thumbnail_url = document.select("#cover > a > img").attr("data-src")
|
thumbnail_url = document.select("#cover > a > img").attr("data-src")
|
||||||
status = SManga.COMPLETED
|
status = SManga.COMPLETED
|
||||||
artist = getArtists(document)
|
artist = getArtists(document)
|
||||||
author = getGroups(document)
|
author = artist
|
||||||
// Some people want these additional details in description
|
// Some people want these additional details in description
|
||||||
description = "Full English and Japanese titles:\n"
|
description = "Full English and Japanese titles:\n"
|
||||||
.plus("$fullTitle\n")
|
.plus("$fullTitle\n")
|
||||||
|
|
|
@ -2,8 +2,8 @@ ext {
|
||||||
extName = 'Thunder Scans'
|
extName = 'Thunder Scans'
|
||||||
extClass = '.ThunderScansFactory'
|
extClass = '.ThunderScansFactory'
|
||||||
themePkg = 'mangathemesia'
|
themePkg = 'mangathemesia'
|
||||||
baseUrl = 'https://en-thunderscans.com'
|
baseUrl = 'https://en-thunderepic.com'
|
||||||
overrideVersionCode = 4
|
overrideVersionCode = 2
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: "$rootDir/common.gradle"
|
apply from: "$rootDir/common.gradle"
|
||||||
|
|
|
@ -14,14 +14,14 @@ class ThunderScansFactory : SourceFactory {
|
||||||
|
|
||||||
class ThunderScansAR : MangaThemesiaAlt(
|
class ThunderScansAR : MangaThemesiaAlt(
|
||||||
"Thunder Scans",
|
"Thunder Scans",
|
||||||
"https://thunderscans.com",
|
"https://ar-thunderepic.com",
|
||||||
"ar",
|
"ar",
|
||||||
dateFormat = SimpleDateFormat("MMM d, yyy", Locale("ar")),
|
dateFormat = SimpleDateFormat("MMM d, yyy", Locale("ar")),
|
||||||
)
|
)
|
||||||
|
|
||||||
class ThunderScansEN : MangaThemesiaAlt(
|
class ThunderScansEN : MangaThemesiaAlt(
|
||||||
"Thunder Scans",
|
"Thunder Scans",
|
||||||
"https://en-thunderscans.com",
|
"https://en-thunderepic.com",
|
||||||
"en",
|
"en",
|
||||||
mangaUrlDirectory = "/comics",
|
mangaUrlDirectory = "/comics",
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
ext {
|
|
||||||
extName = 'MangaHub'
|
|
||||||
extClass = '.MangaHub'
|
|
||||||
themePkg = 'zeistmanga'
|
|
||||||
baseUrl = 'https://www.mangahub.link'
|
|
||||||
overrideVersionCode = 0
|
|
||||||
isNsfw = true
|
|
||||||
}
|
|
||||||
|
|
||||||
apply from: "$rootDir/common.gradle"
|
|
Before Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 5.3 KiB |
Before Width: | Height: | Size: 9.4 KiB |
Before Width: | Height: | Size: 13 KiB |
|
@ -1,23 +0,0 @@
|
||||||
package eu.kanade.tachiyomi.extension.ar.mangahub
|
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.multisrc.zeistmanga.ZeistManga
|
|
||||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
|
||||||
|
|
||||||
class MangaHub : ZeistManga(
|
|
||||||
"MangaHub",
|
|
||||||
"https://www.mangahub.link",
|
|
||||||
"ar",
|
|
||||||
) {
|
|
||||||
override val client = super.client.newBuilder()
|
|
||||||
.rateLimit(3)
|
|
||||||
.build()
|
|
||||||
|
|
||||||
override val popularMangaSelector = "div#PopularPosts2 article"
|
|
||||||
override val popularMangaSelectorTitle = "h3"
|
|
||||||
override val popularMangaSelectorUrl = "a"
|
|
||||||
|
|
||||||
override val mangaDetailsSelector = ".grid.gap-5.gta-series"
|
|
||||||
override val mangaDetailsSelectorGenres = "dt:contains(التصنيف) + dd a[rel=tag]"
|
|
||||||
|
|
||||||
override val pageListSelector = "article#reader .separator, div.image-container"
|
|
||||||
}
|
|
|
@ -2,8 +2,8 @@ ext {
|
||||||
extName = 'MangaNoon'
|
extName = 'MangaNoon'
|
||||||
extClass = '.MangaNoon'
|
extClass = '.MangaNoon'
|
||||||
themePkg = 'mangathemesia'
|
themePkg = 'mangathemesia'
|
||||||
baseUrl = 'https://noonscan.net'
|
baseUrl = 'https://manjanoon.co'
|
||||||
overrideVersionCode = 4
|
overrideVersionCode = 3
|
||||||
isNsfw = false
|
isNsfw = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ import java.util.Calendar
|
||||||
|
|
||||||
class MangaNoon : MangaThemesia(
|
class MangaNoon : MangaThemesia(
|
||||||
"مانجا نون",
|
"مانجا نون",
|
||||||
"https://noonscan.net",
|
"https://manjanoon.co",
|
||||||
"ar",
|
"ar",
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ ext {
|
||||||
extClass = '.MangaPro'
|
extClass = '.MangaPro'
|
||||||
themePkg = 'mangathemesia'
|
themePkg = 'mangathemesia'
|
||||||
baseUrl = 'https://promanga.pro'
|
baseUrl = 'https://promanga.pro'
|
||||||
overrideVersionCode = 3
|
overrideVersionCode = 2
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: "$rootDir/common.gradle"
|
apply from: "$rootDir/common.gradle"
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
package eu.kanade.tachiyomi.extension.ar.mangapro
|
package eu.kanade.tachiyomi.extension.ar.mangapro
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia
|
import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia
|
||||||
import eu.kanade.tachiyomi.source.model.Page
|
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
|
||||||
import org.jsoup.nodes.Document
|
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
|
@ -14,30 +11,4 @@ class MangaPro : MangaThemesia(
|
||||||
dateFormat = SimpleDateFormat("MMMM dd, yyyy", Locale("ar")),
|
dateFormat = SimpleDateFormat("MMMM dd, yyyy", Locale("ar")),
|
||||||
) {
|
) {
|
||||||
override val versionId = 3
|
override val versionId = 3
|
||||||
|
|
||||||
override fun pageListParse(document: Document): List<Page> {
|
|
||||||
return super.pageListParse(document).onEach {
|
|
||||||
val httpUrl = it.imageUrl!!.toHttpUrl()
|
|
||||||
|
|
||||||
if (wpImgRegex.containsMatchIn(httpUrl.host)) {
|
|
||||||
it.imageUrl = StringBuilder().apply {
|
|
||||||
val ssl = httpUrl.queryParameter("ssl")
|
|
||||||
when (ssl) {
|
|
||||||
null -> append(httpUrl.scheme)
|
|
||||||
"0" -> append("http")
|
|
||||||
else -> append("https")
|
|
||||||
}
|
|
||||||
append("://")
|
|
||||||
append(httpUrl.pathSegments.joinToString("/"))
|
|
||||||
val search = httpUrl.queryParameter("q")
|
|
||||||
if (search != null) {
|
|
||||||
append("?q=")
|
|
||||||
append(search)
|
|
||||||
}
|
|
||||||
}.toString()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private val wpImgRegex = Regex("""i\d+\.wp\.com""")
|
|
||||||
|
|
|
@ -2,8 +2,8 @@ ext {
|
||||||
extName = 'MangaSwat'
|
extName = 'MangaSwat'
|
||||||
extClass = '.MangaSwat'
|
extClass = '.MangaSwat'
|
||||||
themePkg = 'mangathemesia'
|
themePkg = 'mangathemesia'
|
||||||
baseUrl = 'https://tatwt.com'
|
baseUrl = 'https://maxlevelteam.com'
|
||||||
overrideVersionCode = 21
|
overrideVersionCode = 20
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: "$rootDir/common.gradle"
|
apply from: "$rootDir/common.gradle"
|
||||||
|
|
|
@ -24,7 +24,7 @@ import java.util.Locale
|
||||||
class MangaSwat :
|
class MangaSwat :
|
||||||
MangaThemesia(
|
MangaThemesia(
|
||||||
"MangaSwat",
|
"MangaSwat",
|
||||||
"https://tatwt.com",
|
"https://maxlevelteam.com",
|
||||||
"ar",
|
"ar",
|
||||||
dateFormat = SimpleDateFormat("MMMM dd, yyyy", Locale("ar")),
|
dateFormat = SimpleDateFormat("MMMM dd, yyyy", Locale("ar")),
|
||||||
),
|
),
|
||||||
|
|
|
@ -2,8 +2,8 @@ ext {
|
||||||
extName = 'Rocks Manga'
|
extName = 'Rocks Manga'
|
||||||
extClass = '.RocksManga'
|
extClass = '.RocksManga'
|
||||||
themePkg = 'madara'
|
themePkg = 'madara'
|
||||||
baseUrl = 'https://rocksmanga.com'
|
baseUrl = 'https://rocks-manga.com'
|
||||||
overrideVersionCode = 1
|
overrideVersionCode = 0
|
||||||
isNsfw = false
|
isNsfw = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,65 +2,39 @@ package eu.kanade.tachiyomi.extension.ar.rocksmanga
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.multisrc.madara.Madara
|
import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||||
import eu.kanade.tachiyomi.source.model.SChapter
|
import eu.kanade.tachiyomi.source.model.SChapter
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
|
||||||
import org.jsoup.nodes.Element
|
import org.jsoup.nodes.Element
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
class RocksManga : Madara(
|
class RocksManga : Madara(
|
||||||
"Rocks Manga",
|
"Rocks Manga",
|
||||||
"https://rocksmanga.com",
|
"https://rocks-manga.com",
|
||||||
"ar",
|
"ar",
|
||||||
dateFormat = SimpleDateFormat("MMMM d, yyyy", Locale("ar")),
|
dateFormat = SimpleDateFormat("MMMM d, yyyy", Locale("ar")),
|
||||||
) {
|
) {
|
||||||
|
|
||||||
override fun popularMangaSelector() = "div.page-content-listing > .manga"
|
override fun popularMangaSelector() = ".shido-manga"
|
||||||
override val popularMangaUrlSelector = "div.manga-poster a"
|
override val popularMangaUrlSelector = "a.s-manga-title"
|
||||||
|
override val mangaDetailsSelectorTitle = ".title"
|
||||||
override fun popularMangaFromElement(element: Element): SManga {
|
override val mangaDetailsSelectorAuthor = ".heading:contains(المؤلف:) + .content a"
|
||||||
return super.popularMangaFromElement(element).apply {
|
override val mangaDetailsSelectorArtist = ".heading:contains(الرسام:) + .content a"
|
||||||
title = element.selectFirst(popularMangaUrlSelector)!!.attr("title")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun searchMangaSelector() = "#manga-search-results .manga-item"
|
|
||||||
|
|
||||||
override fun searchMangaFromElement(element: Element): SManga {
|
|
||||||
val manga = SManga.create()
|
|
||||||
|
|
||||||
with(element) {
|
|
||||||
selectFirst("a.cover")!!.let {
|
|
||||||
manga.setUrlWithoutDomain(it.attr("abs:href"))
|
|
||||||
manga.title = it.attr("title")
|
|
||||||
}
|
|
||||||
selectFirst("img")?.let {
|
|
||||||
manga.thumbnail_url = imageFromElement(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return manga
|
|
||||||
}
|
|
||||||
|
|
||||||
override val mangaDetailsSelectorTitle = ".manga-title"
|
|
||||||
override val mangaDetailsSelectorAuthor = "div.meta span:contains(المؤلف:) + span a"
|
|
||||||
override val mangaDetailsSelectorArtist = "div.meta span:contains(الرسام:) + span a"
|
|
||||||
override val mangaDetailsSelectorStatus = ".status"
|
override val mangaDetailsSelectorStatus = ".status"
|
||||||
override val mangaDetailsSelectorDescription = "div.description"
|
override val mangaDetailsSelectorDescription = ".story"
|
||||||
override val mangaDetailsSelectorThumbnail = ".manga-poster img"
|
override val mangaDetailsSelectorThumbnail = ".profile-manga .poster img"
|
||||||
override val mangaDetailsSelectorGenre = "div.meta span:contains(التصنيف:) + span a"
|
override val mangaDetailsSelectorGenre = ".heading:contains(التصنيف:) + .content a"
|
||||||
override val altNameSelector = "div.alternative"
|
override val altNameSelector = ".other-name"
|
||||||
override fun chapterListSelector() = ".chapters-list li.chapter-item"
|
override fun chapterListSelector() = "#chapter-list li.chapter-item"
|
||||||
override fun chapterDateSelector() = ".chapter-release-date"
|
override fun chapterDateSelector() = ".ch-post-time"
|
||||||
override val pageListParseSelector = ".chapter-reading-page img"
|
override val pageListParseSelector = ".reading-content img"
|
||||||
|
|
||||||
override val useLoadMoreRequest = LoadMoreStrategy.Never
|
override val useLoadMoreRequest = LoadMoreStrategy.Never
|
||||||
override val useNewChapterEndpoint = false
|
override val useNewChapterEndpoint = false
|
||||||
override val fetchGenres = false
|
|
||||||
override val filterNonMangaItems = false
|
override val filterNonMangaItems = false
|
||||||
|
|
||||||
override fun chapterFromElement(element: Element): SChapter {
|
override fun chapterFromElement(element: Element): SChapter {
|
||||||
val chapter = super.chapterFromElement(element)
|
val chapter = super.chapterFromElement(element)
|
||||||
chapter.name = element.selectFirst(".num")!!.text()
|
chapter.name = element.selectFirst(".detail-ch")!!.text()
|
||||||
return chapter
|
return chapter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
ext {
|
ext {
|
||||||
extName = 'Team X'
|
extName = 'Team X'
|
||||||
extClass = '.TeamX'
|
extClass = '.TeamX'
|
||||||
extVersionCode = 18
|
extVersionCode = 17
|
||||||
isNsfw = false
|
isNsfw = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,7 @@
|
||||||
package eu.kanade.tachiyomi.extension.ar.teamx
|
package eu.kanade.tachiyomi.extension.ar.teamx
|
||||||
|
|
||||||
import android.app.Application
|
|
||||||
import android.content.SharedPreferences
|
|
||||||
import android.widget.Toast
|
|
||||||
import androidx.preference.PreferenceScreen
|
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
||||||
import eu.kanade.tachiyomi.source.ConfigurableSource
|
|
||||||
import eu.kanade.tachiyomi.source.model.FilterList
|
import eu.kanade.tachiyomi.source.model.FilterList
|
||||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||||
import eu.kanade.tachiyomi.source.model.Page
|
import eu.kanade.tachiyomi.source.model.Page
|
||||||
|
@ -19,19 +14,15 @@ import okhttp3.Request
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
import org.jsoup.nodes.Document
|
import org.jsoup.nodes.Document
|
||||||
import org.jsoup.nodes.Element
|
import org.jsoup.nodes.Element
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
class TeamX : ParsedHttpSource(), ConfigurableSource {
|
class TeamX : ParsedHttpSource() {
|
||||||
|
|
||||||
override val name = "Team X"
|
override val name = "Team X"
|
||||||
|
|
||||||
private val defaultBaseUrl = "https://teamoney.site"
|
override val baseUrl = "https://teamxnovel.com"
|
||||||
|
|
||||||
override val baseUrl by lazy { getPrefBaseUrl() }
|
|
||||||
|
|
||||||
override val lang = "ar"
|
override val lang = "ar"
|
||||||
|
|
||||||
|
@ -43,10 +34,6 @@ class TeamX : ParsedHttpSource(), ConfigurableSource {
|
||||||
.rateLimit(10, 1, TimeUnit.SECONDS)
|
.rateLimit(10, 1, TimeUnit.SECONDS)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
private val preferences: SharedPreferences by lazy {
|
|
||||||
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Popular
|
// Popular
|
||||||
|
|
||||||
override fun popularMangaRequest(page: Int): Request {
|
override fun popularMangaRequest(page: Int): Request {
|
||||||
|
@ -143,14 +130,6 @@ class TeamX : ParsedHttpSource(), ConfigurableSource {
|
||||||
}
|
}
|
||||||
genre = document.select("div.review-author-info a").joinToString { it.text() }
|
genre = document.select("div.review-author-info a").joinToString { it.text() }
|
||||||
thumbnail_url = document.select("div.text-right img").first()!!.absUrl("src")
|
thumbnail_url = document.select("div.text-right img").first()!!.absUrl("src")
|
||||||
status = document
|
|
||||||
.selectFirst(".full-list-info > small:first-child:contains(الحالة) + small")
|
|
||||||
?.text()
|
|
||||||
.toStatus()
|
|
||||||
author = document
|
|
||||||
.selectFirst(".full-list-info > small:first-child:contains(الرسام) + small")
|
|
||||||
?.text()
|
|
||||||
?.takeIf { it != "غير معروف" }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,14 +187,6 @@ class TeamX : ParsedHttpSource(), ConfigurableSource {
|
||||||
}.getOrNull() ?: 0
|
}.getOrNull() ?: 0
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun String?.toStatus() = when (this) {
|
|
||||||
"مستمرة" -> SManga.ONGOING
|
|
||||||
"قادم قريبًا" -> SManga.ONGOING // "coming soon"
|
|
||||||
"مكتمل" -> SManga.COMPLETED
|
|
||||||
"متوقف" -> SManga.ON_HIATUS
|
|
||||||
else -> SManga.UNKNOWN
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pages
|
// Pages
|
||||||
|
|
||||||
override fun pageListParse(document: Document): List<Page> {
|
override fun pageListParse(document: Document): List<Page> {
|
||||||
|
@ -225,41 +196,4 @@ class TeamX : ParsedHttpSource(), ConfigurableSource {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun imageUrlParse(document: Document): String = throw UnsupportedOperationException()
|
override fun imageUrlParse(document: Document): String = throw UnsupportedOperationException()
|
||||||
|
|
||||||
companion object {
|
|
||||||
private const val RESTART_APP = ".لتطبيق الإعدادات الجديدة أعد تشغيل التطبيق"
|
|
||||||
private const val BASE_URL_PREF_TITLE = "تعديل الرابط"
|
|
||||||
private const val BASE_URL_PREF = "overrideBaseUrl"
|
|
||||||
private const val BASE_URL_PREF_SUMMARY = ".للاستخدام المؤقت. تحديث التطبيق سيؤدي الى حذف الإعدادات"
|
|
||||||
private const val DEFAULT_BASE_URL_PREF = "defaultBaseUrl"
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
|
||||||
val baseUrlPref = androidx.preference.EditTextPreference(screen.context).apply {
|
|
||||||
key = BASE_URL_PREF
|
|
||||||
title = BASE_URL_PREF_TITLE
|
|
||||||
summary = BASE_URL_PREF_SUMMARY
|
|
||||||
this.setDefaultValue(defaultBaseUrl)
|
|
||||||
dialogTitle = BASE_URL_PREF_TITLE
|
|
||||||
dialogMessage = "Default: $defaultBaseUrl"
|
|
||||||
|
|
||||||
setOnPreferenceChangeListener { _, _ ->
|
|
||||||
Toast.makeText(screen.context, RESTART_APP, Toast.LENGTH_LONG).show()
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
screen.addPreference(baseUrlPref)
|
|
||||||
}
|
|
||||||
private fun getPrefBaseUrl(): String = preferences.getString(BASE_URL_PREF, defaultBaseUrl)!!
|
|
||||||
|
|
||||||
init {
|
|
||||||
preferences.getString(DEFAULT_BASE_URL_PREF, null).let { prefDefaultBaseUrl ->
|
|
||||||
if (prefDefaultBaseUrl != defaultBaseUrl) {
|
|
||||||
preferences.edit()
|
|
||||||
.putString(BASE_URL_PREF, defaultBaseUrl)
|
|
||||||
.putString(DEFAULT_BASE_URL_PREF, defaultBaseUrl)
|
|
||||||
.apply()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
ext {
|
|
||||||
extName = 'Altay Scans'
|
|
||||||
extClass = '.AltayScans'
|
|
||||||
themePkg = 'mangathemesia'
|
|
||||||
baseUrl = 'https://altayscans.com'
|
|
||||||
overrideVersionCode = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
apply from: "$rootDir/common.gradle"
|
|
Before Width: | Height: | Size: 4.7 KiB |
Before Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 6.6 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 17 KiB |
|
@ -1,14 +0,0 @@
|
||||||
package eu.kanade.tachiyomi.extension.en.altayscans
|
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia
|
|
||||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
|
||||||
|
|
||||||
class AltayScans : MangaThemesia(
|
|
||||||
"Altay Scans",
|
|
||||||
"https://altayscans.com",
|
|
||||||
"en",
|
|
||||||
) {
|
|
||||||
override val client = super.client.newBuilder()
|
|
||||||
.rateLimit(3)
|
|
||||||
.build()
|
|
||||||
}
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
ext {
|
||||||
|
extName = 'Ansh Scans'
|
||||||
|
extClass = '.AnshScans'
|
||||||
|
themePkg = 'madara'
|
||||||
|
baseUrl = 'https://anshscans.org'
|
||||||
|
overrideVersionCode = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
apply from: "$rootDir/common.gradle"
|
After Width: | Height: | Size: 5.0 KiB |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 7.0 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 18 KiB |
|
@ -0,0 +1,11 @@
|
||||||
|
package eu.kanade.tachiyomi.extension.en.anshscans
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||||
|
|
||||||
|
class AnshScans : Madara("Ansh Scans", "https://anshscans.org", "en") {
|
||||||
|
override val useNewChapterEndpoint = true
|
||||||
|
|
||||||
|
override val mangaDetailsSelectorStatus = "div.summary-heading:contains(Status) + div.summary-content"
|
||||||
|
|
||||||
|
override val mangaSubString = "comic"
|
||||||
|
}
|
|
@ -1,9 +0,0 @@
|
||||||
ext {
|
|
||||||
extName = 'Astra Scans'
|
|
||||||
extClass = '.AstraScans'
|
|
||||||
themePkg = 'mangathemesia'
|
|
||||||
baseUrl = 'https://astrascans.org'
|
|
||||||
overrideVersionCode = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
apply from: "$rootDir/common.gradle"
|
|
Before Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 8.2 KiB |
Before Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 23 KiB |
|
@ -1,15 +0,0 @@
|
||||||
package eu.kanade.tachiyomi.extension.en.astrascans
|
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia
|
|
||||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
|
||||||
|
|
||||||
class AstraScans : MangaThemesia(
|
|
||||||
"Astra Scans",
|
|
||||||
"https://astrascans.org",
|
|
||||||
"en",
|
|
||||||
"/series",
|
|
||||||
) {
|
|
||||||
override val client = super.client.newBuilder()
|
|
||||||
.rateLimit(3)
|
|
||||||
.build()
|
|
||||||
}
|
|
|
@ -1,7 +1,7 @@
|
||||||
ext {
|
ext {
|
||||||
extName = 'Asura Scans'
|
extName = 'Asura Scans'
|
||||||
extClass = '.AsuraScans'
|
extClass = '.AsuraScans'
|
||||||
extVersionCode = 39
|
extVersionCode = 36
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: "$rootDir/common.gradle"
|
apply from: "$rootDir/common.gradle"
|
||||||
|
|
|
@ -205,12 +205,7 @@ class AsuraScans : ParsedHttpSource(), ConfigurableSource {
|
||||||
description = document.selectFirst("span.font-medium.text-sm")?.text()
|
description = document.selectFirst("span.font-medium.text-sm")?.text()
|
||||||
author = document.selectFirst("div.grid > div:has(h3:eq(0):containsOwn(Author)) > h3:eq(1)")?.ownText()
|
author = document.selectFirst("div.grid > div:has(h3:eq(0):containsOwn(Author)) > h3:eq(1)")?.ownText()
|
||||||
artist = document.selectFirst("div.grid > div:has(h3:eq(0):containsOwn(Artist)) > h3:eq(1)")?.ownText()
|
artist = document.selectFirst("div.grid > div:has(h3:eq(0):containsOwn(Artist)) > h3:eq(1)")?.ownText()
|
||||||
genre = buildList {
|
genre = document.select("div[class^=space] > div.flex > button.text-white").joinToString { it.ownText() }
|
||||||
document.selectFirst("div.flex:has(h3:eq(0):containsOwn(type)) > h3:eq(1)")
|
|
||||||
?.ownText()?.let(::add)
|
|
||||||
document.select("div[class^=space] > div.flex > button.text-white")
|
|
||||||
.forEach { add(it.ownText()) }
|
|
||||||
}.joinToString()
|
|
||||||
status = parseStatus(document.selectFirst("div.flex:has(h3:eq(0):containsOwn(Status)) > h3:eq(1)")?.ownText())
|
status = parseStatus(document.selectFirst("div.flex:has(h3:eq(0):containsOwn(Status)) > h3:eq(1)")?.ownText())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -234,10 +229,10 @@ class AsuraScans : ParsedHttpSource(), ConfigurableSource {
|
||||||
|
|
||||||
override fun chapterListRequest(manga: SManga) = mangaDetailsRequest(manga)
|
override fun chapterListRequest(manga: SManga) = mangaDetailsRequest(manga)
|
||||||
|
|
||||||
override fun chapterListSelector() = "div.scrollbar-thumb-themecolor > div.group"
|
override fun chapterListSelector() = "div.scrollbar-thumb-themecolor > a.block"
|
||||||
|
|
||||||
override fun chapterFromElement(element: Element) = SChapter.create().apply {
|
override fun chapterFromElement(element: Element) = SChapter.create().apply {
|
||||||
setUrlWithoutDomain(element.selectFirst("a")!!.attr("abs:href").toPermSlugIfNeeded())
|
setUrlWithoutDomain(element.attr("abs:href").toPermSlugIfNeeded())
|
||||||
name = element.selectFirst("h3:eq(0)")!!.text()
|
name = element.selectFirst("h3:eq(0)")!!.text()
|
||||||
date_upload = try {
|
date_upload = try {
|
||||||
val text = element.selectFirst("h3:eq(1)")!!.ownText()
|
val text = element.selectFirst("h3:eq(1)")!!.ownText()
|
||||||
|
@ -258,7 +253,7 @@ class AsuraScans : ParsedHttpSource(), ConfigurableSource {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun pageListParse(document: Document): List<Page> {
|
override fun pageListParse(document: Document): List<Page> {
|
||||||
return document.select("div > img[alt*=chapter]").mapIndexed { i, element ->
|
return document.select("div > img[alt=chapter]").mapIndexed { i, element ->
|
||||||
Page(i, imageUrl = element.attr("abs:src"))
|
Page(i, imageUrl = element.attr("abs:src"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Before Width: | Height: | Size: 4.6 KiB |
Before Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 9.1 KiB |
Before Width: | Height: | Size: 12 KiB |
|
@ -1,156 +0,0 @@
|
||||||
package eu.kanade.tachiyomi.extension.en.atsumaru
|
|
||||||
|
|
||||||
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.HttpSource
|
|
||||||
import kotlinx.serialization.decodeFromString
|
|
||||||
import kotlinx.serialization.json.Json
|
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
|
||||||
import okhttp3.Request
|
|
||||||
import okhttp3.Response
|
|
||||||
import uy.kohesive.injekt.injectLazy
|
|
||||||
|
|
||||||
class Atsumaru : HttpSource() {
|
|
||||||
|
|
||||||
override val name = "Atsumaru"
|
|
||||||
|
|
||||||
override val baseUrl = "https://atsu.moe"
|
|
||||||
private val apiUrl = "$baseUrl/api/v1"
|
|
||||||
|
|
||||||
override val lang = "en"
|
|
||||||
|
|
||||||
override val supportsLatest = true
|
|
||||||
|
|
||||||
override val client = network.cloudflareClient.newBuilder()
|
|
||||||
.rateLimit(2)
|
|
||||||
.build()
|
|
||||||
|
|
||||||
override fun headersBuilder() = super.headersBuilder()
|
|
||||||
.add("Referer", "$baseUrl/")
|
|
||||||
|
|
||||||
private fun apiHeadersBuilder() = headersBuilder().apply {
|
|
||||||
add("Accept", "*/*")
|
|
||||||
add("Host", apiUrl.toHttpUrl().host)
|
|
||||||
}
|
|
||||||
|
|
||||||
private val apiHeaders by lazy { apiHeadersBuilder().build() }
|
|
||||||
|
|
||||||
private val json: Json by injectLazy()
|
|
||||||
|
|
||||||
// ============================== Popular ===============================
|
|
||||||
|
|
||||||
override fun popularMangaRequest(page: Int): Request {
|
|
||||||
return GET("$apiUrl/layouts/s1/sliders/hotUpdates", apiHeaders)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun popularMangaParse(response: Response): MangasPage {
|
|
||||||
val data = response.parseAs<BrowseMangaDto>().items
|
|
||||||
|
|
||||||
return MangasPage(data.map { it.manga.toSManga() }, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
// =============================== Latest ===============================
|
|
||||||
|
|
||||||
override fun latestUpdatesRequest(page: Int): Request {
|
|
||||||
return GET("$apiUrl/layouts/s1/latest-updates", apiHeaders)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun latestUpdatesParse(response: Response): MangasPage {
|
|
||||||
return popularMangaParse(response)
|
|
||||||
}
|
|
||||||
|
|
||||||
// =============================== Search ===============================
|
|
||||||
|
|
||||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
|
||||||
val url = "$apiUrl/search".toHttpUrl().newBuilder()
|
|
||||||
.addPathSegment(query)
|
|
||||||
.build()
|
|
||||||
|
|
||||||
return GET(url, apiHeaders)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun searchMangaParse(response: Response): MangasPage {
|
|
||||||
val data = response.parseAs<SearchResultsDto>().hits
|
|
||||||
|
|
||||||
return MangasPage(data.map { it.info.toSManga() }, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
// =========================== Manga Details ============================
|
|
||||||
|
|
||||||
override fun getMangaUrl(manga: SManga): String {
|
|
||||||
return baseUrl + manga.url
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun mangaDetailsRequest(manga: SManga): Request {
|
|
||||||
return GET(apiUrl + manga.url, apiHeaders)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun mangaDetailsParse(response: Response): SManga {
|
|
||||||
return response.parseAs<MangaObjectDto>().manga.toSManga()
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================== Chapters ==============================
|
|
||||||
|
|
||||||
override fun chapterListRequest(manga: SManga): Request {
|
|
||||||
return mangaDetailsRequest(manga)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun chapterListParse(response: Response): List<SChapter> {
|
|
||||||
val chapterList = response.parseAs<MangaObjectDto>().manga.chapters!!.map {
|
|
||||||
it.toSChapter(response.request.url.pathSegments.last())
|
|
||||||
}
|
|
||||||
|
|
||||||
return chapterList.sortedWith(
|
|
||||||
compareBy(
|
|
||||||
{ it.chapter_number },
|
|
||||||
{ it.scanlator },
|
|
||||||
),
|
|
||||||
).reversed()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getChapterUrl(chapter: SChapter): String {
|
|
||||||
val (slug, name) = chapter.url.split("/")
|
|
||||||
return "$baseUrl/read/s1/$slug/$name/1"
|
|
||||||
}
|
|
||||||
|
|
||||||
// =============================== Pages ================================
|
|
||||||
|
|
||||||
override fun pageListRequest(chapter: SChapter): Request {
|
|
||||||
val (slug, name) = chapter.url.split("/")
|
|
||||||
return GET("$apiUrl/manga/s1/$slug#$name", apiHeaders)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun pageListParse(response: Response): List<Page> {
|
|
||||||
val chapter = response.parseAs<MangaObjectDto>().manga.chapters!!.first {
|
|
||||||
it.name == response.request.url.fragment
|
|
||||||
}
|
|
||||||
|
|
||||||
return chapter.pages.map { page ->
|
|
||||||
Page(page.name.toInt(), imageUrl = page.pageURLs.first())
|
|
||||||
}.sortedBy { it.index }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun imageRequest(page: Page): Request {
|
|
||||||
val imgHeaders = headersBuilder().apply {
|
|
||||||
add("Accept", "image/avif,image/webp,*/*")
|
|
||||||
add("Host", page.imageUrl!!.toHttpUrl().host)
|
|
||||||
}.build()
|
|
||||||
|
|
||||||
return GET(page.imageUrl!!, imgHeaders)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun imageUrlParse(response: Response): String {
|
|
||||||
throw UnsupportedOperationException()
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================= Utilities ==============================
|
|
||||||
|
|
||||||
private inline fun <reified T> Response.parseAs(): T {
|
|
||||||
return json.decodeFromString(body.string())
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,115 +0,0 @@
|
||||||
package eu.kanade.tachiyomi.extension.en.atsumaru
|
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.source.model.SChapter
|
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
import java.text.ParseException
|
|
||||||
import java.text.SimpleDateFormat
|
|
||||||
import java.util.Locale
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
class BrowseMangaDto(
|
|
||||||
val items: List<MangaObjectDto>,
|
|
||||||
)
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
class MangaObjectDto(
|
|
||||||
val manga: MangaDto,
|
|
||||||
)
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
class SearchResultsDto(
|
|
||||||
val hits: List<SearchMangaDto>,
|
|
||||||
) {
|
|
||||||
@Serializable
|
|
||||||
class SearchMangaDto(
|
|
||||||
val info: MangaDto,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
class MangaDto(
|
|
||||||
// Common
|
|
||||||
private val title: String,
|
|
||||||
private val cover: String,
|
|
||||||
private val slug: String,
|
|
||||||
|
|
||||||
// Details
|
|
||||||
private val authors: List<String>? = null,
|
|
||||||
private val description: String? = null,
|
|
||||||
private val genres: List<String>? = null,
|
|
||||||
private val statuses: List<String>? = null,
|
|
||||||
|
|
||||||
// Chapters
|
|
||||||
val chapters: List<ChapterDto>? = null,
|
|
||||||
) {
|
|
||||||
fun toSManga(): SManga = SManga.create().apply {
|
|
||||||
title = this@MangaDto.title
|
|
||||||
thumbnail_url = cover
|
|
||||||
url = "/manga/s1/$slug"
|
|
||||||
|
|
||||||
authors?.let {
|
|
||||||
author = it.joinToString()
|
|
||||||
}
|
|
||||||
description = this@MangaDto.description
|
|
||||||
genres?.let {
|
|
||||||
genre = it.joinToString()
|
|
||||||
}
|
|
||||||
statuses?.let {
|
|
||||||
status = when (it.first().lowercase().substringBefore(" ")) {
|
|
||||||
"ongoing" -> SManga.ONGOING
|
|
||||||
"complete" -> SManga.COMPLETED
|
|
||||||
else -> SManga.UNKNOWN
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
class ChapterDto(
|
|
||||||
val pages: List<PageDto>,
|
|
||||||
val name: String,
|
|
||||||
private val type: String,
|
|
||||||
private val title: String? = null,
|
|
||||||
private val date: String? = null,
|
|
||||||
) {
|
|
||||||
fun toSChapter(slug: String): SChapter = SChapter.create().apply {
|
|
||||||
val chapterNumber = this@ChapterDto.name.replace("_", ".")
|
|
||||||
.filter { it.isDigit() || it == '.' }
|
|
||||||
|
|
||||||
name = buildString {
|
|
||||||
append("Chapter ")
|
|
||||||
append(chapterNumber)
|
|
||||||
if (title != null) {
|
|
||||||
append(" - ")
|
|
||||||
append(title)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
url = "$slug/${this@ChapterDto.name}"
|
|
||||||
chapter_number = chapterNumber.toFloat()
|
|
||||||
scanlator = type.takeUnless { it == "Chapter" }
|
|
||||||
date?.let {
|
|
||||||
date_upload = parseDate(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun parseDate(dateStr: String): Long {
|
|
||||||
return try {
|
|
||||||
DATE_FORMAT.parse(dateStr)!!.time
|
|
||||||
} catch (_: ParseException) {
|
|
||||||
0L
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private val DATE_FORMAT by lazy {
|
|
||||||
SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.ENGLISH)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
class PageDto(
|
|
||||||
val pageURLs: List<String>,
|
|
||||||
val name: String,
|
|
||||||
)
|
|
|
@ -1,7 +1,7 @@
|
||||||
ext {
|
ext {
|
||||||
extName = 'ColoredManga'
|
extName = 'ColoredManga'
|
||||||
extClass = '.ColoredManga'
|
extClass = '.ColoredManga'
|
||||||
extVersionCode = 35
|
extVersionCode = 3
|
||||||
isNsfw = true
|
isNsfw = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
ext {
|
||||||
|
extName = 'Comic Scans'
|
||||||
|
extClass = '.ComicScans'
|
||||||
|
themePkg = 'madara'
|
||||||
|
baseUrl = 'https://www.comicscans.org'
|
||||||
|
overrideVersionCode = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
apply from: "$rootDir/common.gradle"
|
|
@ -0,0 +1,7 @@
|
||||||
|
package eu.kanade.tachiyomi.extension.en.comicscans
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||||
|
|
||||||
|
class ComicScans : Madara("Comic Scans", "https://www.comicscans.org", "en") {
|
||||||
|
override val useNewChapterEndpoint = true
|
||||||
|
}
|
|
@ -2,8 +2,8 @@ ext {
|
||||||
extName = 'EnryuManga'
|
extName = 'EnryuManga'
|
||||||
extClass = '.EnryuManga'
|
extClass = '.EnryuManga'
|
||||||
themePkg = 'mangathemesia'
|
themePkg = 'mangathemesia'
|
||||||
baseUrl = 'https://enryumanga.net'
|
baseUrl = 'https://enryumanga.com'
|
||||||
overrideVersionCode = 1
|
overrideVersionCode = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: "$rootDir/common.gradle"
|
apply from: "$rootDir/common.gradle"
|
||||||
|
|
|
@ -2,4 +2,4 @@ package eu.kanade.tachiyomi.extension.en.enryumanga
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia
|
import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia
|
||||||
|
|
||||||
class EnryuManga : MangaThemesia("EnryuManga", "https://enryumanga.net", "en")
|
class EnryuManga : MangaThemesia("EnryuManga", "https://enryumanga.com", "en")
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
ext {
|
|
||||||
extName = 'Eros Scans'
|
|
||||||
extClass = '.ErosScans'
|
|
||||||
themePkg = 'mangathemesia'
|
|
||||||
baseUrl = 'https://erosscans.xyz'
|
|
||||||
overrideVersionCode = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
apply from: "$rootDir/common.gradle"
|
|
Before Width: | Height: | Size: 7.6 KiB |
Before Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 40 KiB |
|
@ -1,14 +0,0 @@
|
||||||
package eu.kanade.tachiyomi.extension.en.erosscans
|
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia
|
|
||||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
|
||||||
|
|
||||||
class ErosScans : MangaThemesia(
|
|
||||||
"Eros Scans",
|
|
||||||
"https://erosscans.xyz",
|
|
||||||
"en",
|
|
||||||
) {
|
|
||||||
override val client = super.client.newBuilder()
|
|
||||||
.rateLimit(3)
|
|
||||||
.build()
|
|
||||||
}
|
|
|
@ -1,9 +1,9 @@
|
||||||
ext {
|
ext {
|
||||||
extName = 'Firecomics'
|
extName = 'Fire Scans'
|
||||||
extClass = '.Firecomics'
|
extClass = '.FireScans'
|
||||||
themePkg = 'madara'
|
themePkg = 'madara'
|
||||||
baseUrl = 'https://firecomics.org'
|
baseUrl = 'https://firescans.xyz'
|
||||||
overrideVersionCode = 2
|
overrideVersionCode = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: "$rootDir/common.gradle"
|
apply from: "$rootDir/common.gradle"
|
||||||
|
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 6.9 KiB |
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 21 KiB |
|
@ -11,9 +11,8 @@ import kotlinx.serialization.json.jsonPrimitive
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import org.jsoup.nodes.Document
|
import org.jsoup.nodes.Document
|
||||||
|
|
||||||
class Firecomics : Madara("Firecomics", "https://firecomics.org", "en") {
|
class FireScans : Madara("Fire Scans", "https://firescans.xyz", "en") {
|
||||||
|
|
||||||
override val id: Long = 5761461704760730187
|
|
||||||
override val client: OkHttpClient = super.client.newBuilder()
|
override val client: OkHttpClient = super.client.newBuilder()
|
||||||
.rateLimit(20, 5)
|
.rateLimit(20, 5)
|
||||||
.build()
|
.build()
|
|
@ -1,7 +1,7 @@
|
||||||
ext {
|
ext {
|
||||||
extName = 'Hentai2Read'
|
extName = 'Hentai2Read'
|
||||||
extClass = '.Hentai2Read'
|
extClass = '.Hentai2Read'
|
||||||
extVersionCode = 17
|
extVersionCode = 16
|
||||||
isNsfw = true
|
isNsfw = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|