Madara refactor (#1292)
* remove randomua from madara * don't use page path for page=1 * add back `madara_load_more` * cleanup i18n and filters * load more in a new source * move back the filters not worth it * fix build * altname to i18n as well * utf-8 * Revert "utf-8" This reverts commit 1335bc1b478da54d3a5eb6333ac1a26e3ee2825b. * utf-8 * autodetect load_more_request * load genres in background * make genre classes protected remove unnecessary change * fetch genres changes * launchIO countviews * don't explicitly optin * cleanup some request overrides * make `useLoadMoreRequest` enum to be able to disable autodection where necessary * fix logic bruh * use state variables * defer countViews in overrides as well * lint * select().first -> selectFirst * `load_more` search as well * detect in search as well * remove slipped override * move detection to the function * remove fetchGenreFailed * don't use GlobalScope * tweak load_more_request parameters * remove ancient connectTimeout/readTimeout already present in the client provided by the app * small cleanup
This commit is contained in:
parent
a62d90d4aa
commit
30b13498b0
27
lib-multisrc/madara/assets/i18n/messages_en.properties
Normal file
27
lib-multisrc/madara/assets/i18n/messages_en.properties
Normal file
@ -0,0 +1,27 @@
|
||||
author_filter_title=Author
|
||||
artist_filter_title=Artist
|
||||
year_filter_title=Year of Released
|
||||
status_filter_title=Status
|
||||
status_filter_completed=Completed
|
||||
status_filter_ongoing=Ongoing
|
||||
status_filter_canceled=Canceled
|
||||
status_filter_on_hold=On Hold
|
||||
order_by_filter_title=Order By
|
||||
order_by_filter_relevance=Relevance
|
||||
order_by_filter_latest=Latest
|
||||
order_by_filter_az=A-Z
|
||||
order_by_filter_rating=Rating
|
||||
order_by_filter_trending=Trending
|
||||
order_by_filter_views=Most Views
|
||||
order_by_filter_new=New
|
||||
genre_condition_filter_title=Genre condition
|
||||
genre_condition_filter_or=OR
|
||||
genre_condition_filter_and=AND
|
||||
adult_content_filter_title=Adult Content
|
||||
adult_content_filter_all=All
|
||||
adult_content_filter_none=None
|
||||
adult_content_filter_only=Only
|
||||
genre_filter_header=Genres filter may not work for all sources
|
||||
genre_filter_title=Genres
|
||||
genre_missing_warning=Press 'Reset' to attempt to show the genres
|
||||
alt_names_heading=Alternative Names:
|
26
lib-multisrc/madara/assets/i18n/messages_pt_br.properties
Normal file
26
lib-multisrc/madara/assets/i18n/messages_pt_br.properties
Normal file
@ -0,0 +1,26 @@
|
||||
author_filter_title=Autor
|
||||
artist_filter_title=Artista
|
||||
year_filter_title=Ano de lançamento
|
||||
status_filter_title=Estado
|
||||
status_filter_completed=Completo
|
||||
status_filter_ongoing=Em andamento
|
||||
status_filter_canceled=Cancelado
|
||||
status_filter_on_hold=Pausado
|
||||
order_by_filter_title=Ordenar por
|
||||
order_by_filter_relevance=Relevância
|
||||
order_by_filter_latest=Recentes
|
||||
order_by_filter_rating=Avaliação
|
||||
order_by_filter_trending=Tendência
|
||||
order_by_filter_views=Visualizações
|
||||
order_by_filter_new=Novos
|
||||
genre_condition_filter_title=Operador dos gêneros
|
||||
genre_condition_filter_or=OU
|
||||
genre_condition_filter_and=E
|
||||
adult_content_filter_title=Conteúdo adulto
|
||||
adult_content_filter_all=Indiferente
|
||||
adult_content_filter_none=Nenhum
|
||||
adult_content_filter_only=Somente
|
||||
genre_filter_header=O filtro de gêneros pode não funcionar
|
||||
genre_filter_title=Gêneros
|
||||
genre_missing_warning=Aperte 'Redefinir' para tentar mostrar os gêneros
|
||||
alt_names_heading=Nomes alternativos:
|
@ -2,9 +2,9 @@ plugins {
|
||||
id("lib-multisrc")
|
||||
}
|
||||
|
||||
baseVersionCode = 33
|
||||
baseVersionCode = 34
|
||||
|
||||
dependencies {
|
||||
api(project(":lib:cryptoaes"))
|
||||
api(project(":lib:randomua"))
|
||||
api(project(":lib:i18n"))
|
||||
}
|
||||
|
@ -1,18 +1,11 @@
|
||||
package eu.kanade.tachiyomi.multisrc.madara
|
||||
|
||||
import android.app.Application
|
||||
import android.content.SharedPreferences
|
||||
import android.util.Base64
|
||||
import androidx.preference.PreferenceScreen
|
||||
import eu.kanade.tachiyomi.lib.cryptoaes.CryptoAES
|
||||
import eu.kanade.tachiyomi.lib.randomua.addRandomUAPreferenceToScreen
|
||||
import eu.kanade.tachiyomi.lib.randomua.getPrefCustomUA
|
||||
import eu.kanade.tachiyomi.lib.randomua.getPrefUAType
|
||||
import eu.kanade.tachiyomi.lib.randomua.setRandomUserAgent
|
||||
import eu.kanade.tachiyomi.lib.i18n.Intl
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.POST
|
||||
import eu.kanade.tachiyomi.network.asObservable
|
||||
import eu.kanade.tachiyomi.source.ConfigurableSource
|
||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
||||
import eu.kanade.tachiyomi.source.model.Filter
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||
@ -21,57 +14,55 @@ import eu.kanade.tachiyomi.source.model.SChapter
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.jsonArray
|
||||
import kotlinx.serialization.json.jsonObject
|
||||
import kotlinx.serialization.json.jsonPrimitive
|
||||
import okhttp3.CacheControl
|
||||
import okhttp3.FormBody
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
import rx.Observable
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.text.ParseException
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Calendar
|
||||
import java.util.Locale
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
abstract class Madara(
|
||||
override val name: String,
|
||||
override val baseUrl: String,
|
||||
final override val lang: String,
|
||||
private val dateFormat: SimpleDateFormat = SimpleDateFormat("MMMM dd, yyyy", Locale.US),
|
||||
) : ParsedHttpSource(), ConfigurableSource {
|
||||
|
||||
private val preferences: SharedPreferences by lazy {
|
||||
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
||||
}
|
||||
) : ParsedHttpSource() {
|
||||
|
||||
override val supportsLatest = true
|
||||
|
||||
override val client: OkHttpClient by lazy {
|
||||
network.cloudflareClient.newBuilder()
|
||||
.setRandomUserAgent(
|
||||
preferences.getPrefUAType(),
|
||||
preferences.getPrefCustomUA(),
|
||||
)
|
||||
.connectTimeout(10, TimeUnit.SECONDS)
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
.build()
|
||||
}
|
||||
override val client = network.cloudflareClient
|
||||
|
||||
override fun headersBuilder() = super.headersBuilder()
|
||||
.add("Referer", "$baseUrl/")
|
||||
|
||||
protected val xhrHeaders by lazy {
|
||||
headersBuilder()
|
||||
.set("X-Requested-With", "XMLHttpRequest")
|
||||
.build()
|
||||
}
|
||||
|
||||
protected open val json: Json by injectLazy()
|
||||
|
||||
protected val intl = Intl(
|
||||
language = lang,
|
||||
baseLanguage = "en",
|
||||
availableLanguages = setOf("en", "pt-BR"),
|
||||
classLoader = this::class.java.classLoader!!,
|
||||
)
|
||||
|
||||
/**
|
||||
* If enabled, will attempt to remove non-manga items in popular and latest.
|
||||
* The filter will not be used in search as the theme doesn't set the CSS class.
|
||||
@ -93,11 +84,6 @@ abstract class Madara(
|
||||
*/
|
||||
private var genresList: List<Genre> = emptyList()
|
||||
|
||||
/**
|
||||
* Inner variable to control the genre fetching failed state.
|
||||
*/
|
||||
private var fetchGenresFailed: Boolean = false
|
||||
|
||||
/**
|
||||
* Inner variable to control how much tries the genres request was called.
|
||||
*/
|
||||
@ -114,11 +100,58 @@ abstract class Madara(
|
||||
*/
|
||||
protected open val mangaSubString = "manga"
|
||||
|
||||
/**
|
||||
* enable if the site use "madara_load_more" to load manga on the site
|
||||
* Typically has "load More" instead of next/previous page
|
||||
*
|
||||
* with LoadMoreStrategy.AutoDetect it tries to detect if site uses `madara_load_more`
|
||||
*/
|
||||
protected open val useLoadMoreRequest = LoadMoreStrategy.AutoDetect
|
||||
|
||||
enum class LoadMoreStrategy {
|
||||
AutoDetect, Always, Never
|
||||
}
|
||||
|
||||
/**
|
||||
* internal variable to save if site uses load_more or not
|
||||
*/
|
||||
private var loadMoreRequestDetected = LoadMoreDetection.Pending
|
||||
|
||||
private enum class LoadMoreDetection {
|
||||
Pending, True, False
|
||||
}
|
||||
|
||||
protected fun detectLoadMore(document: Document) {
|
||||
if (useLoadMoreRequest == LoadMoreStrategy.AutoDetect &&
|
||||
loadMoreRequestDetected == LoadMoreDetection.Pending
|
||||
) {
|
||||
loadMoreRequestDetected = when (document.selectFirst("nav.navigation-ajax") != null) {
|
||||
true -> LoadMoreDetection.True
|
||||
false -> LoadMoreDetection.False
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected fun useLoadMoreRequest(): Boolean {
|
||||
return when (useLoadMoreRequest) {
|
||||
LoadMoreStrategy.Always -> true
|
||||
LoadMoreStrategy.Never -> false
|
||||
else -> loadMoreRequestDetected == LoadMoreDetection.True
|
||||
}
|
||||
}
|
||||
|
||||
// Popular Manga
|
||||
|
||||
override fun popularMangaParse(response: Response): MangasPage {
|
||||
runCatching { fetchGenres() }
|
||||
return super.popularMangaParse(response)
|
||||
val document = response.asJsoup()
|
||||
|
||||
val entries = document.select(popularMangaSelector())
|
||||
.map(::popularMangaFromElement)
|
||||
val hasNextPage = popularMangaNextPageSelector()?.let { document.selectFirst(it) } != null
|
||||
|
||||
detectLoadMore(document)
|
||||
|
||||
return MangasPage(entries, hasNextPage)
|
||||
}
|
||||
|
||||
// exclude/filter bilibili manga from list
|
||||
@ -130,12 +163,12 @@ abstract class Madara(
|
||||
val manga = SManga.create()
|
||||
|
||||
with(element) {
|
||||
select(popularMangaUrlSelector).first()?.let {
|
||||
selectFirst(popularMangaUrlSelector)!!.let {
|
||||
manga.setUrlWithoutDomain(it.attr("abs:href"))
|
||||
manga.title = it.ownText()
|
||||
}
|
||||
|
||||
select("img").first()?.let {
|
||||
selectFirst("img")?.let {
|
||||
manga.thumbnail_url = imageFromElement(it)
|
||||
}
|
||||
}
|
||||
@ -143,15 +176,19 @@ abstract class Madara(
|
||||
return manga
|
||||
}
|
||||
|
||||
override fun popularMangaRequest(page: Int): Request {
|
||||
return GET(
|
||||
url = "$baseUrl/$mangaSubString/${searchPage(page)}?m_orderby=views",
|
||||
headers = headers,
|
||||
cache = CacheControl.FORCE_NETWORK,
|
||||
)
|
||||
override fun popularMangaRequest(page: Int): Request =
|
||||
if (useLoadMoreRequest()) {
|
||||
loadMoreRequest(page, popular = true)
|
||||
} else {
|
||||
GET("$baseUrl/$mangaSubString/${searchPage(page)}?m_orderby=views", headers)
|
||||
}
|
||||
|
||||
override fun popularMangaNextPageSelector(): String? = searchMangaNextPageSelector()
|
||||
override fun popularMangaNextPageSelector(): String? =
|
||||
if (useLoadMoreRequest()) {
|
||||
"body:not(:has(.no-posts))"
|
||||
} else {
|
||||
"div.nav-previous, nav.navigation-ajax, a.nextpostslink"
|
||||
}
|
||||
|
||||
// Latest Updates
|
||||
|
||||
@ -162,53 +199,75 @@ abstract class Madara(
|
||||
return popularMangaFromElement(element)
|
||||
}
|
||||
|
||||
override fun latestUpdatesRequest(page: Int): Request {
|
||||
return GET(
|
||||
url = "$baseUrl/$mangaSubString/${searchPage(page)}?m_orderby=latest",
|
||||
headers = headers,
|
||||
cache = CacheControl.FORCE_NETWORK,
|
||||
)
|
||||
override fun latestUpdatesRequest(page: Int): Request =
|
||||
if (useLoadMoreRequest()) {
|
||||
loadMoreRequest(page, popular = false)
|
||||
} else {
|
||||
GET("$baseUrl/$mangaSubString/${searchPage(page)}?m_orderby=latest", headers)
|
||||
}
|
||||
|
||||
override fun latestUpdatesNextPageSelector(): String? = popularMangaNextPageSelector()
|
||||
|
||||
override fun latestUpdatesParse(response: Response): MangasPage {
|
||||
val mp = super.latestUpdatesParse(response)
|
||||
val mp = popularMangaParse(response)
|
||||
val mangas = mp.mangas.distinctBy { it.url }
|
||||
return MangasPage(mangas, mp.hasNextPage)
|
||||
}
|
||||
|
||||
// load more
|
||||
protected fun loadMoreRequest(page: Int, popular: Boolean): Request {
|
||||
val formBody = FormBody.Builder().apply {
|
||||
add("action", "madara_load_more")
|
||||
add("page", (page - 1).toString())
|
||||
add("template", "madara-core/content/content-archive")
|
||||
add("vars[orderby]", "meta_value_num")
|
||||
add("vars[paged]", "1")
|
||||
add("vars[post_type]", "wp-manga")
|
||||
add("vars[post_status]", "publish")
|
||||
add("vars[meta_key]", if (popular) "_wp_manga_views" else "_latest_update")
|
||||
add("vars[order]", "desc")
|
||||
add("vars[sidebar]", "right")
|
||||
add("vars[manga_archives_item_layout]", "big_thumbnail")
|
||||
}.build()
|
||||
|
||||
return POST("$baseUrl/wp-admin/admin-ajax.php", xhrHeaders, formBody)
|
||||
}
|
||||
|
||||
// Search Manga
|
||||
|
||||
override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> {
|
||||
if (query.startsWith(URL_SEARCH_PREFIX)) {
|
||||
val mangaUrl = "$baseUrl/$mangaSubString/${query.substringAfter(URL_SEARCH_PREFIX)}"
|
||||
return client.newCall(GET(mangaUrl, headers))
|
||||
.asObservable().map { response ->
|
||||
MangasPage(listOf(mangaDetailsParse(response.asJsoup()).apply { url = "/$mangaSubString/${query.substringAfter(URL_SEARCH_PREFIX)}/" }), false)
|
||||
val mangaUrl = "/$mangaSubString/${query.substringAfter(URL_SEARCH_PREFIX)}"
|
||||
return client.newCall(GET("$baseUrl$mangaUrl", headers))
|
||||
.asObservableSuccess().map { response ->
|
||||
val manga = mangaDetailsParse(response).apply {
|
||||
url = mangaUrl
|
||||
}
|
||||
|
||||
MangasPage(listOf(manga), false)
|
||||
}
|
||||
}
|
||||
|
||||
return client.newCall(searchMangaRequest(page, query, filters))
|
||||
.asObservable().doOnNext { response ->
|
||||
if (!response.isSuccessful) {
|
||||
response.close()
|
||||
// Error message for exceeding last page
|
||||
if (response.code == 404) {
|
||||
error("Already on the Last Page!")
|
||||
return super.fetchSearchManga(page, query, filters)
|
||||
}
|
||||
|
||||
protected open fun searchPage(page: Int): String {
|
||||
return if (page == 1) {
|
||||
""
|
||||
} else {
|
||||
throw Exception("HTTP error ${response.code}")
|
||||
"page/$page/"
|
||||
}
|
||||
}
|
||||
}
|
||||
.map { response ->
|
||||
searchMangaParse(response)
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun searchPage(page: Int): String = "page/$page/"
|
||||
|
||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
||||
return if (useLoadMoreRequest()) {
|
||||
searchLoadMoreRequest(page, query, filters)
|
||||
} else {
|
||||
searchRequest(page, query, filters)
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun searchRequest(page: Int, query: String, filters: FilterList): Request {
|
||||
val url = "$baseUrl/${searchPage(page)}".toHttpUrl().newBuilder()
|
||||
url.addQueryParameter("s", query)
|
||||
url.addQueryParameter("post_type", "wp-manga")
|
||||
@ -260,108 +319,182 @@ abstract class Madara(
|
||||
return GET(url.build(), headers)
|
||||
}
|
||||
|
||||
protected open val authorFilterTitle: String = when (lang) {
|
||||
"pt-BR" -> "Autor"
|
||||
else -> "Author"
|
||||
protected open fun searchLoadMoreRequest(page: Int, query: String, filters: FilterList): Request {
|
||||
val formBody = FormBody.Builder().apply {
|
||||
add("action", "madara_load_more")
|
||||
add("page", (page - 1).toString())
|
||||
add("template", "madara-core/content/content-search")
|
||||
add("vars[paged]", "1")
|
||||
add("vars[template]", "archive")
|
||||
add("vars[sidebar]", "right")
|
||||
add("vars[post_type]", "wp-manga")
|
||||
add("vars[post_status]", "publish")
|
||||
add("vars[manga_archives_item_layout]", "big_thumbnail")
|
||||
|
||||
if (filterNonMangaItems) {
|
||||
add("vars[meta_query][0][key]", "_wp_manga_chapter_type")
|
||||
add("vars[meta_query][0][value]", "manga")
|
||||
}
|
||||
|
||||
protected open val artistFilterTitle: String = when (lang) {
|
||||
"pt-BR" -> "Artista"
|
||||
else -> "Artist"
|
||||
add("vars[s]", query)
|
||||
|
||||
var metaQueryIdx = if (filterNonMangaItems) 1 else 0
|
||||
var taxQueryIdx = 0
|
||||
val genres = filters.filterIsInstance<GenreList>().firstOrNull()?.state
|
||||
?.filter { it.state }
|
||||
?.map { it.id }
|
||||
.orEmpty()
|
||||
|
||||
filters.forEach { filter ->
|
||||
when (filter) {
|
||||
is AuthorFilter -> {
|
||||
if (filter.state.isNotBlank()) {
|
||||
add("vars[tax_query][$taxQueryIdx][taxonomy]", "wp-manga-author")
|
||||
add("vars[tax_query][$taxQueryIdx][field]", "name")
|
||||
add("vars[tax_query][$taxQueryIdx][terms]", filter.state)
|
||||
|
||||
taxQueryIdx++
|
||||
}
|
||||
}
|
||||
is ArtistFilter -> {
|
||||
if (filter.state.isNotBlank()) {
|
||||
add("vars[tax_query][$taxQueryIdx][taxonomy]", "wp-manga-artist")
|
||||
add("vars[tax_query][$taxQueryIdx][field]", "name")
|
||||
add("vars[tax_query][$taxQueryIdx][terms]", filter.state)
|
||||
|
||||
taxQueryIdx++
|
||||
}
|
||||
}
|
||||
is YearFilter -> {
|
||||
if (filter.state.isNotBlank()) {
|
||||
add("vars[tax_query][$taxQueryIdx][taxonomy]", "wp-manga-release")
|
||||
add("vars[tax_query][$taxQueryIdx][field]", "name")
|
||||
add("vars[tax_query][$taxQueryIdx][terms]", filter.state)
|
||||
|
||||
taxQueryIdx++
|
||||
}
|
||||
}
|
||||
is StatusFilter -> {
|
||||
val statuses = filter.state
|
||||
.filter { it.state }
|
||||
.map { it.id }
|
||||
|
||||
if (statuses.isNotEmpty()) {
|
||||
add("vars[meta_query][$metaQueryIdx][key]", "_wp_manga_status")
|
||||
|
||||
statuses.forEachIndexed { i, slug ->
|
||||
add("vars[meta_query][$metaQueryIdx][value][$i]", slug)
|
||||
}
|
||||
|
||||
protected open val yearFilterTitle: String = when (lang) {
|
||||
"pt-BR" -> "Ano de lançamento"
|
||||
else -> "Year of Released"
|
||||
metaQueryIdx++
|
||||
}
|
||||
|
||||
protected open val statusFilterTitle: String = when (lang) {
|
||||
"pt-BR" -> "Estado"
|
||||
else -> "Status"
|
||||
}
|
||||
|
||||
protected open val statusFilterOptions: Array<String> = when (lang) {
|
||||
"pt-BR" -> arrayOf("Completo", "Em andamento", "Cancelado", "Pausado")
|
||||
else -> arrayOf("Completed", "Ongoing", "Canceled", "On Hold")
|
||||
is OrderByFilter -> {
|
||||
if (filter.state != 0) {
|
||||
when (filter.toUriPart()) {
|
||||
"latest" -> {
|
||||
add("vars[orderby]", "meta_value_num")
|
||||
add("vars[order]", "DESC")
|
||||
add("vars[meta_key]", "_latest_update")
|
||||
}
|
||||
|
||||
protected open val statusFilterOptionsValues: Array<String> = arrayOf(
|
||||
"end",
|
||||
"on-going",
|
||||
"canceled",
|
||||
"on-hold",
|
||||
"alphabet" -> {
|
||||
add("vars[orderby]", "post_title")
|
||||
add("vars[order]", "ASC")
|
||||
}
|
||||
"rating" -> {
|
||||
add("vars[orderby][query_average_reviews]", "DESC")
|
||||
add("vars[orderby][query_total_reviews]", "DESC")
|
||||
}
|
||||
"trending" -> {
|
||||
add("vars[orderby]", "meta_value_num")
|
||||
add("vars[meta_key]", "_wp_manga_week_views_value")
|
||||
add("vars[order]", "DESC")
|
||||
}
|
||||
"views" -> {
|
||||
add("vars[orderby]", "meta_value_num")
|
||||
add("vars[meta_key]", "_wp_manga_views")
|
||||
add("vars[order]", "DESC")
|
||||
}
|
||||
else -> {
|
||||
add("vars[orderby]", "date")
|
||||
add("vars[order]", "DESC")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
is AdultContentFilter -> {
|
||||
if (filter.state != 0) {
|
||||
add("vars[meta_query][$metaQueryIdx][key]", "manga_adult_content")
|
||||
add(
|
||||
"vars[meta_query][$metaQueryIdx][compare]",
|
||||
if (filter.state == 1) "not exists" else "exists",
|
||||
)
|
||||
|
||||
protected open val orderByFilterTitle: String = when (lang) {
|
||||
"pt-BR" -> "Ordenar por"
|
||||
else -> "Order By"
|
||||
metaQueryIdx++
|
||||
}
|
||||
}
|
||||
is GenreConditionFilter -> {
|
||||
if (filter.state == 1 && genres.isNotEmpty()) {
|
||||
add("vars[tax_query][$taxQueryIdx][operation]", "AND")
|
||||
}
|
||||
}
|
||||
is GenreList -> {
|
||||
if (genres.isNotEmpty()) {
|
||||
add("vars[tax_query][$taxQueryIdx][taxonomy]", "wp-manga-genre")
|
||||
add("vars[tax_query][$taxQueryIdx][field]", "slug")
|
||||
|
||||
genres.forEachIndexed { i, slug ->
|
||||
add("vars[tax_query][$taxQueryIdx][terms][$i]", slug)
|
||||
}
|
||||
|
||||
protected open val orderByFilterOptions: Array<String> = when (lang) {
|
||||
"pt-BR" -> arrayOf(
|
||||
"Relevância",
|
||||
"Recentes",
|
||||
"A-Z",
|
||||
"Avaliação",
|
||||
"Tendência",
|
||||
"Visualizações",
|
||||
"Novos",
|
||||
)
|
||||
else -> arrayOf(
|
||||
"Relevance",
|
||||
"Latest",
|
||||
"A-Z",
|
||||
"Rating",
|
||||
"Trending",
|
||||
"Most Views",
|
||||
"New",
|
||||
)
|
||||
taxQueryIdx++
|
||||
}
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
}.build()
|
||||
|
||||
return POST("$baseUrl/wp-admin/admin-ajax.php", xhrHeaders, formBody)
|
||||
}
|
||||
|
||||
protected open val orderByFilterOptionsValues: Array<String> = arrayOf(
|
||||
"",
|
||||
"latest",
|
||||
"alphabet",
|
||||
"rating",
|
||||
"trending",
|
||||
"views",
|
||||
"new-manga",
|
||||
protected open val statusFilterOptions: Map<String, String> =
|
||||
mapOf(
|
||||
intl["status_filter_completed"] to "end",
|
||||
intl["status_filter_ongoing"] to "on-going",
|
||||
intl["status_filter_canceled"] to "canceled",
|
||||
intl["status_filter_on_hold"] to "on-hold",
|
||||
)
|
||||
|
||||
protected open val genreConditionFilterTitle: String = when (lang) {
|
||||
"pt-BR" -> "Operador dos gêneros"
|
||||
else -> "Genre condition"
|
||||
protected open val orderByFilterOptions: Map<String, String> = mapOf(
|
||||
intl["order_by_filter_relevance"] to "",
|
||||
intl["order_by_filter_latest"] to "latest",
|
||||
intl["order_by_filter_az"] to "alphabet",
|
||||
intl["order_by_filter_rating"] to "rating",
|
||||
intl["order_by_filter_trending"] to "trending",
|
||||
intl["order_by_filter_views"] to "views",
|
||||
intl["order_by_filter_new"] to "new-manga",
|
||||
)
|
||||
|
||||
protected open val genreConditionFilterOptions: Array<String> =
|
||||
arrayOf(
|
||||
intl["genre_condition_filter_or"],
|
||||
intl["genre_condition_filter_and"],
|
||||
)
|
||||
|
||||
protected open val adultContentFilterOptions: Array<String> =
|
||||
arrayOf(
|
||||
intl["adult_content_filter_all"],
|
||||
intl["adult_content_filter_none"],
|
||||
intl["adult_content_filter_only"],
|
||||
)
|
||||
|
||||
open class UriPartFilter(displayName: String, private val vals: Array<Pair<String, String>>, state: Int = 0) :
|
||||
Filter.Select<String>(displayName, vals.map { it.first }.toTypedArray(), state) {
|
||||
fun toUriPart() = vals[state].second
|
||||
}
|
||||
|
||||
protected open val genreConditionFilterOptions: Array<String> = when (lang) {
|
||||
"pt-BR" -> arrayOf("OU", "E")
|
||||
else -> arrayOf("OR", "AND")
|
||||
}
|
||||
|
||||
protected open val adultContentFilterTitle: String = when (lang) {
|
||||
"pt-BR" -> "Conteúdo adulto"
|
||||
else -> "Adult Content"
|
||||
}
|
||||
|
||||
protected open val adultContentFilterOptions: Array<String> = when (lang) {
|
||||
"pt-BR" -> arrayOf("Indiferente", "Nenhum", "Somente")
|
||||
else -> arrayOf("All", "None", "Only")
|
||||
}
|
||||
|
||||
protected open val genreFilterHeader: String = when (lang) {
|
||||
"pt-BR" -> "O filtro de gêneros pode não funcionar"
|
||||
else -> "Genres filter may not work for all sources"
|
||||
}
|
||||
|
||||
protected open val genreFilterTitle: String = when (lang) {
|
||||
"pt-BR" -> "Gêneros"
|
||||
else -> "Genres"
|
||||
}
|
||||
|
||||
protected open val genresMissingWarning: String = when (lang) {
|
||||
"pt-BR" -> "Aperte 'Redefinir' para tentar mostrar os gêneros"
|
||||
else -> "Press 'Reset' to attempt to show the genres"
|
||||
}
|
||||
open class Tag(val id: String, name: String) : Filter.CheckBox(name)
|
||||
|
||||
protected class AuthorFilter(title: String) : Filter.Text(title)
|
||||
protected class ArtistFilter(title: String) : Filter.Text(title)
|
||||
@ -386,50 +519,60 @@ abstract class Madara(
|
||||
class Genre(name: String, val id: String = name) : Filter.CheckBox(name)
|
||||
|
||||
override fun getFilterList(): FilterList {
|
||||
launchIO { fetchGenres() }
|
||||
|
||||
val filters = mutableListOf(
|
||||
AuthorFilter(authorFilterTitle),
|
||||
ArtistFilter(artistFilterTitle),
|
||||
YearFilter(yearFilterTitle),
|
||||
StatusFilter(statusFilterTitle, getStatusList()),
|
||||
AuthorFilter(intl["author_filter_title"]),
|
||||
ArtistFilter(intl["artist_filter_title"]),
|
||||
YearFilter(intl["year_filter_title"]),
|
||||
StatusFilter(
|
||||
title = intl["status_filter_title"],
|
||||
status = statusFilterOptions.map { Tag(it.key, it.value) },
|
||||
),
|
||||
OrderByFilter(
|
||||
title = orderByFilterTitle,
|
||||
options = orderByFilterOptions.zip(orderByFilterOptionsValues),
|
||||
title = intl["order_by_filter_title"],
|
||||
options = orderByFilterOptions.map { Pair(it.key, it.value) },
|
||||
state = 0,
|
||||
),
|
||||
AdultContentFilter(adultContentFilterTitle, adultContentFilterOptions),
|
||||
AdultContentFilter(
|
||||
title = intl["adult_content_filter_title"],
|
||||
options = adultContentFilterOptions,
|
||||
),
|
||||
)
|
||||
|
||||
if (genresList.isNotEmpty()) {
|
||||
filters += listOf(
|
||||
Filter.Separator(),
|
||||
Filter.Header(genreFilterHeader),
|
||||
GenreConditionFilter(genreConditionFilterTitle, genreConditionFilterOptions),
|
||||
GenreList(genreFilterTitle, genresList),
|
||||
Filter.Header(intl["genre_filter_header"]),
|
||||
GenreConditionFilter(
|
||||
title = intl["genre_condition_filter_title"],
|
||||
options = genreConditionFilterOptions,
|
||||
),
|
||||
GenreList(
|
||||
title = intl["genre_filter_title"],
|
||||
genres = genresList,
|
||||
),
|
||||
)
|
||||
} else if (fetchGenres) {
|
||||
filters += listOf(
|
||||
Filter.Separator(),
|
||||
Filter.Header(genresMissingWarning),
|
||||
Filter.Header(intl["genre_missing_warning"]),
|
||||
)
|
||||
}
|
||||
|
||||
return FilterList(filters)
|
||||
}
|
||||
|
||||
protected fun getStatusList() = statusFilterOptionsValues
|
||||
.zip(statusFilterOptions)
|
||||
.map { Tag(it.first, it.second) }
|
||||
|
||||
open class UriPartFilter(displayName: String, private val vals: Array<Pair<String, String>>, state: Int = 0) :
|
||||
Filter.Select<String>(displayName, vals.map { it.first }.toTypedArray(), state) {
|
||||
fun toUriPart() = vals[state].second
|
||||
}
|
||||
|
||||
open class Tag(val id: String, name: String) : Filter.CheckBox(name)
|
||||
|
||||
override fun searchMangaParse(response: Response): MangasPage {
|
||||
runCatching { fetchGenres() }
|
||||
return super.searchMangaParse(response)
|
||||
val document = response.asJsoup()
|
||||
|
||||
val entries = document.select(searchMangaSelector())
|
||||
.map(::searchMangaFromElement)
|
||||
val hasNextPage = searchMangaNextPageSelector()?.let { document.selectFirst(it) } != null
|
||||
|
||||
detectLoadMore(document)
|
||||
|
||||
return MangasPage(entries, hasNextPage)
|
||||
}
|
||||
|
||||
override fun searchMangaSelector() = "div.c-tabs-item__content"
|
||||
@ -438,11 +581,11 @@ abstract class Madara(
|
||||
val manga = SManga.create()
|
||||
|
||||
with(element) {
|
||||
select("div.post-title a").first()?.let {
|
||||
selectFirst("div.post-title a")!!.let {
|
||||
manga.setUrlWithoutDomain(it.attr("abs:href"))
|
||||
manga.title = it.ownText()
|
||||
}
|
||||
select("img").first()?.let {
|
||||
selectFirst("img")?.let {
|
||||
manga.thumbnail_url = imageFromElement(it)
|
||||
}
|
||||
}
|
||||
@ -450,7 +593,7 @@ abstract class Madara(
|
||||
return manga
|
||||
}
|
||||
|
||||
override fun searchMangaNextPageSelector(): String? = "div.nav-previous, nav.navigation-ajax, a.nextpostslink"
|
||||
override fun searchMangaNextPageSelector() = popularMangaNextPageSelector()
|
||||
|
||||
// Manga Details Parse
|
||||
|
||||
@ -493,9 +636,7 @@ abstract class Madara(
|
||||
override fun mangaDetailsParse(document: Document): SManga {
|
||||
val manga = SManga.create()
|
||||
with(document) {
|
||||
select(mangaDetailsSelectorTitle).first()?.let {
|
||||
manga.title = it.ownText()
|
||||
}
|
||||
manga.title = selectFirst(mangaDetailsSelectorTitle)!!.ownText()
|
||||
select(mangaDetailsSelectorAuthor).eachText().filter {
|
||||
it.notUpdating()
|
||||
}.joinToString().takeIf { it.isNotBlank() }?.let {
|
||||
@ -515,7 +656,7 @@ abstract class Madara(
|
||||
manga.description = it.text()
|
||||
}
|
||||
}
|
||||
select(mangaDetailsSelectorThumbnail).first()?.let {
|
||||
selectFirst(mangaDetailsSelectorThumbnail)?.let {
|
||||
manga.thumbnail_url = imageFromElement(it)
|
||||
}
|
||||
select(mangaDetailsSelectorStatus).last()?.let {
|
||||
@ -533,13 +674,6 @@ abstract class Madara(
|
||||
.map { element -> element.text().lowercase(Locale.ROOT) }
|
||||
.toMutableSet()
|
||||
|
||||
// add tag(s) to genre
|
||||
val mangaTitle = try {
|
||||
manga.title
|
||||
} catch (_: UninitializedPropertyAccessException) {
|
||||
"not initialized"
|
||||
}
|
||||
|
||||
if (mangaDetailsSelectorTag.isNotEmpty()) {
|
||||
select(mangaDetailsSelectorTag).forEach { element ->
|
||||
if (genres.contains(element.text()).not() &&
|
||||
@ -547,7 +681,7 @@ abstract class Madara(
|
||||
element.text().contains("read", true).not() &&
|
||||
element.text().contains(name, true).not() &&
|
||||
element.text().contains(name.replace(" ", ""), true).not() &&
|
||||
element.text().contains(mangaTitle, true).not() &&
|
||||
element.text().contains(manga.title, true).not() &&
|
||||
element.text().contains(altName, true).not()
|
||||
) {
|
||||
genres.add(element.text().lowercase(Locale.ROOT))
|
||||
@ -556,13 +690,13 @@ abstract class Madara(
|
||||
}
|
||||
|
||||
// add manga/manhwa/manhua thinggy to genre
|
||||
document.select(seriesTypeSelector).firstOrNull()?.ownText()?.let {
|
||||
document.selectFirst(seriesTypeSelector)?.ownText()?.let {
|
||||
if (it.isEmpty().not() && it.notUpdating() && it != "-" && genres.contains(it).not()) {
|
||||
genres.add(it.lowercase(Locale.ROOT))
|
||||
}
|
||||
}
|
||||
|
||||
manga.genre = genres.toList().joinToString(", ") { genre ->
|
||||
manga.genre = genres.toList().joinToString { genre ->
|
||||
genre.replaceFirstChar {
|
||||
if (it.isLowerCase()) {
|
||||
it.titlecase(
|
||||
@ -575,7 +709,7 @@ abstract class Madara(
|
||||
}
|
||||
|
||||
// add alternative name to manga description
|
||||
document.select(altNameSelector).firstOrNull()?.ownText()?.let {
|
||||
document.selectFirst(altNameSelector)?.ownText()?.let {
|
||||
if (it.isBlank().not() && it.notUpdating()) {
|
||||
manga.description = when {
|
||||
manga.description.isNullOrBlank() -> altName + it
|
||||
@ -600,17 +734,14 @@ abstract class Madara(
|
||||
|
||||
open val seriesTypeSelector = ".post-content_item:contains(Type) .summary-content"
|
||||
open val altNameSelector = ".post-content_item:contains(Alt) .summary-content"
|
||||
open val altName = when (lang) {
|
||||
"pt-BR" -> "Nomes alternativos: "
|
||||
else -> "Alternative Names: "
|
||||
}
|
||||
open val altName = intl["alt_names_heading"]
|
||||
open val updatingRegex = "Updating|Atualizando".toRegex(RegexOption.IGNORE_CASE)
|
||||
|
||||
fun String.notUpdating(): Boolean {
|
||||
return this.contains(updatingRegex).not()
|
||||
}
|
||||
|
||||
fun String.containsIn(array: Array<String>): Boolean {
|
||||
private fun String.containsIn(array: Array<String>): Boolean {
|
||||
return this.lowercase() in array.map { it.lowercase() }
|
||||
}
|
||||
|
||||
@ -644,25 +775,18 @@ abstract class Madara(
|
||||
.add("manga", mangaId)
|
||||
.build()
|
||||
|
||||
val xhrHeaders = headersBuilder()
|
||||
.add("Content-Length", form.contentLength().toString())
|
||||
.add("Content-Type", form.contentType().toString())
|
||||
.add("X-Requested-With", "XMLHttpRequest")
|
||||
.build()
|
||||
|
||||
return POST("$baseUrl/wp-admin/admin-ajax.php", xhrHeaders, form)
|
||||
}
|
||||
|
||||
protected open fun xhrChaptersRequest(mangaUrl: String): Request {
|
||||
val xhrHeaders = headersBuilder()
|
||||
.add("X-Requested-With", "XMLHttpRequest")
|
||||
.build()
|
||||
|
||||
return POST("$mangaUrl/ajax/chapters", xhrHeaders)
|
||||
}
|
||||
|
||||
override fun chapterListParse(response: Response): List<SChapter> {
|
||||
val document = response.asJsoup()
|
||||
|
||||
launchIO { countViews(document) }
|
||||
|
||||
val chaptersWrapper = document.select("div[id^=manga-chapters-holder]")
|
||||
|
||||
var chapterElements = document.select(chapterListSelector())
|
||||
@ -692,8 +816,6 @@ abstract class Madara(
|
||||
xhrResponse.close()
|
||||
}
|
||||
|
||||
countViews(document)
|
||||
|
||||
return chapterElements.map(::chapterFromElement)
|
||||
}
|
||||
|
||||
@ -710,7 +832,7 @@ abstract class Madara(
|
||||
val chapter = SChapter.create()
|
||||
|
||||
with(element) {
|
||||
select(chapterUrlSelector).first()?.let { urlElement ->
|
||||
selectFirst(chapterUrlSelector)!!.let { urlElement ->
|
||||
chapter.url = urlElement.attr("abs:href").let {
|
||||
it.substringBefore("?style=paged") + if (!it.endsWith(chapterUrlSuffix)) chapterUrlSuffix else ""
|
||||
}
|
||||
@ -718,9 +840,9 @@ abstract class Madara(
|
||||
}
|
||||
// Dates can be part of a "new" graphic or plain text
|
||||
// Added "title" alternative
|
||||
chapter.date_upload = select("img:not(.thumb)").firstOrNull()?.attr("alt")?.let { parseRelativeDate(it) }
|
||||
?: select("span a").firstOrNull()?.attr("title")?.let { parseRelativeDate(it) }
|
||||
?: parseChapterDate(select(chapterDateSelector()).firstOrNull()?.text())
|
||||
chapter.date_upload = selectFirst("img:not(.thumb)")?.attr("alt")?.let { parseRelativeDate(it) }
|
||||
?: selectFirst("span a")?.attr("title")?.let { parseRelativeDate(it) }
|
||||
?: parseChapterDate(selectFirst(chapterDateSelector())?.text())
|
||||
}
|
||||
|
||||
return chapter
|
||||
@ -816,7 +938,7 @@ abstract class Madara(
|
||||
open val chapterProtectorSelector = "#chapter-protector-data"
|
||||
|
||||
override fun pageListParse(document: Document): List<Page> {
|
||||
countViews(document)
|
||||
launchIO { countViews(document) }
|
||||
|
||||
val chapterProtector = document.selectFirst(chapterProtectorSelector)
|
||||
?: return document.select(pageListParseSelector).mapIndexed { index, element ->
|
||||
@ -836,7 +958,7 @@ abstract class Madara(
|
||||
|
||||
val unsaltedCiphertext = Base64.decode(chapterData["ct"]!!.jsonPrimitive.content, Base64.DEFAULT)
|
||||
val salt = chapterData["s"]!!.jsonPrimitive.content.decodeHex()
|
||||
val ciphertext = SALTED + salt + unsaltedCiphertext
|
||||
val ciphertext = salted + salt + unsaltedCiphertext
|
||||
|
||||
val rawImgArray = CryptoAES.decrypt(Base64.encodeToString(ciphertext, Base64.DEFAULT), password)
|
||||
val imgArrayString = json.parseToJsonElement(rawImgArray).jsonPrimitive.content
|
||||
@ -860,7 +982,7 @@ abstract class Madara(
|
||||
protected open val sendViewCount: Boolean = true
|
||||
|
||||
protected open fun countViewsRequest(document: Document): Request? {
|
||||
val wpMangaData = document.select("script#wp-manga-js-extra").firstOrNull()
|
||||
val wpMangaData = document.selectFirst("script#wp-manga-js-extra")
|
||||
?.data() ?: return null
|
||||
|
||||
val wpMangaInfo = wpMangaData
|
||||
@ -882,8 +1004,6 @@ abstract class Madara(
|
||||
val formBody = formBuilder.build()
|
||||
|
||||
val newHeaders = headersBuilder()
|
||||
.set("Content-Length", formBody.contentLength().toString())
|
||||
.set("Content-Type", formBody.contentType().toString())
|
||||
.set("Referer", document.location())
|
||||
.build()
|
||||
|
||||
@ -912,18 +1032,17 @@ abstract class Madara(
|
||||
/**
|
||||
* Fetch the genres from the source to be used in the filters.
|
||||
*/
|
||||
protected open fun fetchGenres() {
|
||||
if (fetchGenres && fetchGenresAttempts <= 3 && (genresList.isEmpty() || fetchGenresFailed)) {
|
||||
val genres = runCatching {
|
||||
client.newCall(genresRequest()).execute()
|
||||
protected fun fetchGenres() {
|
||||
if (fetchGenres && fetchGenresAttempts < 3 && genresList.isEmpty()) {
|
||||
try {
|
||||
genresList = client.newCall(genresRequest()).execute()
|
||||
.use { parseGenres(it.asJsoup()) }
|
||||
}
|
||||
|
||||
fetchGenresFailed = genres.isFailure
|
||||
genresList = genres.getOrNull().orEmpty()
|
||||
} catch (_: Exception) {
|
||||
} finally {
|
||||
fetchGenresAttempts++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The request to the search page (or another one) that have the genres list.
|
||||
@ -950,7 +1069,7 @@ abstract class Madara(
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/a/66614516
|
||||
private fun String.decodeHex(): ByteArray {
|
||||
protected fun String.decodeHex(): ByteArray {
|
||||
check(length % 2 == 0) { "Must have an even length" }
|
||||
|
||||
return chunked(2)
|
||||
@ -958,13 +1077,14 @@ abstract class Madara(
|
||||
.toByteArray()
|
||||
}
|
||||
|
||||
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
||||
addRandomUAPreferenceToScreen(screen)
|
||||
}
|
||||
protected val salted = "Salted__".toByteArray(Charsets.UTF_8)
|
||||
|
||||
private val scope = CoroutineScope(Dispatchers.IO)
|
||||
|
||||
protected fun launchIO(block: () -> Unit) = scope.launch { block() }
|
||||
|
||||
companion object {
|
||||
const val URL_SEARCH_PREFIX = "slug:"
|
||||
val SALTED = "Salted__".toByteArray(Charsets.UTF_8)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,4 @@ import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
|
||||
class ComiczNetV2 : Madara("Comicz.net v2", "https://v2.comiz.net", "all") {
|
||||
override val useNewChapterEndpoint = false
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
}
|
||||
|
@ -14,14 +14,6 @@ class GrabberZone : Madara(
|
||||
) {
|
||||
override val mangaSubString = "comics"
|
||||
|
||||
override fun searchPage(page: Int): String {
|
||||
return if (page > 1) {
|
||||
"page/$page/"
|
||||
} else {
|
||||
""
|
||||
}
|
||||
}
|
||||
|
||||
override fun chapterFromElement(element: Element): SChapter {
|
||||
return super.chapterFromElement(element).apply {
|
||||
name = element.selectFirst("a + a")!!.text()
|
||||
|
@ -4,6 +4,4 @@ import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
|
||||
class MangaCrazy : Madara("MangaCrazy", "https://mangacrazy.net", "all") {
|
||||
override val useNewChapterEndpoint = true
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
}
|
||||
|
@ -12,6 +12,4 @@ class MangaTopSite : Madara(
|
||||
) {
|
||||
override val useNewChapterEndpoint = false
|
||||
override val chapterUrlSuffix = ""
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
}
|
||||
|
@ -1,16 +1,12 @@
|
||||
package eu.kanade.tachiyomi.extension.ar.azora
|
||||
|
||||
import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.source.model.SChapter
|
||||
import okhttp3.Request
|
||||
import org.jsoup.nodes.Element
|
||||
|
||||
class Azora : Madara("Azora", "https://azoramoon.com", "ar") {
|
||||
override val mangaSubString = "series"
|
||||
override val useNewChapterEndpoint = false
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
override fun popularMangaRequest(page: Int): Request = GET("$baseUrl/page/$page/?m_orderby=views", headers)
|
||||
override fun chapterListSelector() = "li.wp-manga-chapter:not(.premium-block)" // Filter fake chapters
|
||||
override fun chapterFromElement(element: Element): SChapter {
|
||||
val chapter = SChapter.create()
|
||||
|
@ -9,12 +9,4 @@ class ComicArab : Madara(
|
||||
"https://comicarab.com",
|
||||
"ar",
|
||||
dateFormat = SimpleDateFormat("dd MMMM، yyyy", Locale("ar")),
|
||||
) {
|
||||
override fun searchPage(page: Int): String {
|
||||
return if (page > 1) {
|
||||
"page/$page/"
|
||||
} else {
|
||||
""
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
@ -6,17 +6,20 @@ import android.widget.Toast
|
||||
import androidx.preference.PreferenceScreen
|
||||
import eu.kanade.tachiyomi.extension.BuildConfig
|
||||
import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
import eu.kanade.tachiyomi.source.ConfigurableSource
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
|
||||
class EmpireWebtoon : Madara(
|
||||
class EmpireWebtoon :
|
||||
Madara(
|
||||
"Empire Webtoon",
|
||||
"https://webtoonsempireron.com",
|
||||
"ar",
|
||||
SimpleDateFormat("d MMMM، yyyy", Locale("ar")),
|
||||
) {
|
||||
),
|
||||
ConfigurableSource {
|
||||
|
||||
private val defaultBaseUrl = "https://webtoonsempireron.com"
|
||||
|
||||
@ -30,8 +33,6 @@ class EmpireWebtoon : Madara(
|
||||
|
||||
override val useNewChapterEndpoint = false
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
|
||||
companion object {
|
||||
private const val RESTART_TACHIYOMI = "Restart Tachiyomi to apply new setting."
|
||||
private const val BASE_URL_PREF_TITLE = "Override BaseUrl"
|
||||
@ -53,8 +54,6 @@ class EmpireWebtoon : Madara(
|
||||
}
|
||||
}
|
||||
screen.addPreference(baseUrlPref)
|
||||
|
||||
super.setupPreferenceScreen(screen)
|
||||
}
|
||||
|
||||
private fun getPrefBaseUrl(): String = preferences.getString(BASE_URL_PREF, defaultBaseUrl)!!
|
||||
|
@ -6,14 +6,13 @@ import android.widget.Toast
|
||||
import androidx.preference.PreferenceScreen
|
||||
import eu.kanade.tachiyomi.extension.BuildConfig
|
||||
import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.POST
|
||||
import eu.kanade.tachiyomi.source.ConfigurableSource
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import okhttp3.CacheControl
|
||||
import okhttp3.FormBody
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
@ -22,7 +21,16 @@ import uy.kohesive.injekt.api.get
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
|
||||
class Mangalek : Madara("مانجا ليك", "https://manga-lek.net", "ar", SimpleDateFormat("MMMM dd, yyyy", Locale("ar"))) {
|
||||
class Mangalek :
|
||||
Madara(
|
||||
"مانجا ليك",
|
||||
"https://manga-lek.net",
|
||||
"ar",
|
||||
SimpleDateFormat("MMMM dd, yyyy", Locale("ar")),
|
||||
),
|
||||
ConfigurableSource {
|
||||
|
||||
override val fetchGenres = false
|
||||
|
||||
override val chapterUrlSuffix = ""
|
||||
|
||||
@ -55,22 +63,10 @@ class Mangalek : Madara("مانجا ليك", "https://manga-lek.net", "ar", Simp
|
||||
}
|
||||
}
|
||||
screen.addPreference(baseUrlPref)
|
||||
|
||||
super.setupPreferenceScreen(screen)
|
||||
}
|
||||
|
||||
private fun getPrefBaseUrl(): String = preferences.getString(BASE_URL_PREF, defaultBaseUrl)!!
|
||||
|
||||
override fun popularMangaRequest(page: Int): Request {
|
||||
return GET(
|
||||
url = "$baseUrl/$mangaSubString/${searchPage(page)}",
|
||||
headers = headers,
|
||||
cache = CacheControl.FORCE_NETWORK,
|
||||
)
|
||||
}
|
||||
|
||||
override fun latestUpdatesRequest(page: Int): Request = popularMangaRequest(page)
|
||||
|
||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request =
|
||||
POST(
|
||||
"$baseUrl/wp-admin/admin-ajax.php",
|
||||
|
@ -6,12 +6,20 @@ import android.widget.Toast
|
||||
import androidx.preference.PreferenceScreen
|
||||
import eu.kanade.tachiyomi.extension.BuildConfig
|
||||
import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
import eu.kanade.tachiyomi.source.ConfigurableSource
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
|
||||
class Mangalink : Madara("مانجا لينك", "https://manga-link.com", "ar", SimpleDateFormat("MMMM dd, yyyy", Locale("ar"))) {
|
||||
class Mangalink :
|
||||
Madara(
|
||||
"مانجا لينك",
|
||||
"https://manga-link.com",
|
||||
"ar",
|
||||
SimpleDateFormat("MMMM dd, yyyy", Locale("ar")),
|
||||
),
|
||||
ConfigurableSource {
|
||||
|
||||
override val chapterUrlSuffix = ""
|
||||
|
||||
@ -44,8 +52,6 @@ class Mangalink : Madara("مانجا لينك", "https://manga-link.com", "ar",
|
||||
}
|
||||
}
|
||||
screen.addPreference(baseUrlPref)
|
||||
|
||||
super.setupPreferenceScreen(screen)
|
||||
}
|
||||
private fun getPrefBaseUrl(): String = preferences.getString(BASE_URL_PREF, defaultBaseUrl)!!
|
||||
}
|
||||
|
@ -9,12 +9,12 @@ class MangaLionz : Madara("MangaLionz", "https://mangalionz.org", "ar") {
|
||||
val manga = SManga.create()
|
||||
|
||||
with(element) {
|
||||
select(popularMangaUrlSelector).first()?.let {
|
||||
selectFirst(popularMangaUrlSelector)!!.let {
|
||||
manga.setUrlWithoutDomain(it.attr("abs:href"))
|
||||
manga.title = it.ownText()
|
||||
}
|
||||
|
||||
select("img").first()?.let {
|
||||
selectFirst("img")?.let {
|
||||
manga.thumbnail_url = imageFromElement(it)?.replace("mangalionz", "mangalek")
|
||||
}
|
||||
}
|
||||
|
@ -9,12 +9,4 @@ class MangaRose : Madara(
|
||||
"https://mangarose.net",
|
||||
"ar",
|
||||
dateFormat = SimpleDateFormat("MMMM dd, yyyy", Locale("ar")),
|
||||
) {
|
||||
override fun searchPage(page: Int): String {
|
||||
return if (page > 1) {
|
||||
"page/$page/"
|
||||
} else {
|
||||
""
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
@ -13,6 +13,4 @@ class MangaSpark : Madara(
|
||||
override val chapterUrlSuffix = ""
|
||||
|
||||
override val useNewChapterEndpoint = false
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
}
|
||||
|
@ -13,6 +13,4 @@ class MangaStarz : Madara(
|
||||
override val chapterUrlSuffix = ""
|
||||
|
||||
override val useNewChapterEndpoint = false
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
}
|
||||
|
@ -1,11 +1,5 @@
|
||||
package eu.kanade.tachiyomi.extension.en.allporncomic
|
||||
|
||||
import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import okhttp3.Request
|
||||
|
||||
class AllPornComic : Madara("AllPornComic", "https://allporncomic.com", "en") {
|
||||
override fun popularMangaRequest(page: Int): Request = GET("$baseUrl/manga/page/$page/?m_orderby=views", headers)
|
||||
override fun latestUpdatesRequest(page: Int): Request = GET("$baseUrl/manga/page/$page/?m_orderby=latest", headers)
|
||||
override fun searchMangaNextPageSelector() = "a[rel=next]"
|
||||
}
|
||||
class AllPornComic : Madara("AllPornComic", "https://allporncomic.com", "en")
|
||||
|
@ -8,8 +8,6 @@ import kotlin.random.Random
|
||||
class AquaManga : Madara("Aqua Manga", "https://aquamanga.org", "en") {
|
||||
override val useNewChapterEndpoint = false
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
|
||||
override fun headersBuilder(): Headers.Builder = super.headersBuilder()
|
||||
.add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8")
|
||||
.add("Accept-Language", "en-US,en;q=0.5")
|
||||
|
@ -4,6 +4,4 @@ import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
|
||||
class AsuraScansUs : Madara("Asura Scans.us (unoriginal)", "https://asurascans.us", "en") {
|
||||
override val useNewChapterEndpoint = true
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
}
|
||||
|
@ -1,37 +1,11 @@
|
||||
package eu.kanade.tachiyomi.extension.en.babelwuxia
|
||||
|
||||
import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||
import okhttp3.Response
|
||||
|
||||
class BabelWuxia : Madara("Babel Wuxia", "https://babelwuxia.com", "en") {
|
||||
|
||||
// moved from MangaThemesia
|
||||
override val versionId = 2
|
||||
override val useNewChapterEndpoint = true
|
||||
|
||||
override fun searchPage(page: Int): String {
|
||||
return if (page > 1) {
|
||||
"page/$page/"
|
||||
} else {
|
||||
""
|
||||
}
|
||||
}
|
||||
|
||||
override fun popularMangaParse(response: Response) =
|
||||
super.popularMangaParse(response).fixNextPage()
|
||||
|
||||
override fun latestUpdatesParse(response: Response) =
|
||||
super.latestUpdatesParse(response).fixNextPage()
|
||||
|
||||
override fun searchMangaParse(response: Response) =
|
||||
super.searchMangaParse(response).fixNextPage()
|
||||
|
||||
private fun MangasPage.fixNextPage(): MangasPage {
|
||||
return if (mangas.size < 12) {
|
||||
MangasPage(mangas, false)
|
||||
} else {
|
||||
this
|
||||
}
|
||||
}
|
||||
override val useLoadMoreRequest = LoadMoreStrategy.Always
|
||||
}
|
||||
|
@ -4,6 +4,4 @@ import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
|
||||
class BananaManga : Madara("Banana Manga", "https://bananamanga.net", "en") {
|
||||
override val useNewChapterEndpoint = true
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
}
|
||||
|
@ -6,8 +6,6 @@ import org.jsoup.nodes.Element
|
||||
class CoffeeManga : Madara("Coffee Manga", "https://coffeemanga.io", "en") {
|
||||
override val useNewChapterEndpoint = false
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
|
||||
override fun imageFromElement(element: Element): String? {
|
||||
return when {
|
||||
element.hasAttr("data-src") && element.attr("data-src").isNotEmpty() -> element.attr("abs:data-src")
|
||||
|
@ -11,6 +11,4 @@ class ColoredManga : Madara(
|
||||
dateFormat = SimpleDateFormat("dd-MMM", Locale.ENGLISH),
|
||||
) {
|
||||
override val useNewChapterEndpoint = true
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
}
|
||||
|
@ -4,6 +4,4 @@ import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
|
||||
class ComicScans : Madara("Comic Scans", "https://www.comicscans.org", "en") {
|
||||
override val useNewChapterEndpoint = true
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
}
|
||||
|
@ -14,7 +14,6 @@ import kotlinx.serialization.json.boolean
|
||||
import kotlinx.serialization.json.jsonArray
|
||||
import kotlinx.serialization.json.jsonObject
|
||||
import kotlinx.serialization.json.jsonPrimitive
|
||||
import okhttp3.CacheControl
|
||||
import okhttp3.FormBody
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||
import okhttp3.OkHttpClient
|
||||
@ -35,26 +34,6 @@ class CreepyScans : Madara(
|
||||
|
||||
override val useNewChapterEndpoint = true
|
||||
|
||||
// Popular
|
||||
|
||||
override fun popularMangaRequest(page: Int): Request {
|
||||
return GET(
|
||||
url = "$baseUrl/$mangaSubString/?m_orderby=views",
|
||||
headers = headers,
|
||||
cache = CacheControl.FORCE_NETWORK,
|
||||
)
|
||||
}
|
||||
|
||||
// Latest
|
||||
|
||||
override fun latestUpdatesRequest(page: Int): Request {
|
||||
return GET(
|
||||
url = "$baseUrl/$mangaSubString/?m_orderby=latest",
|
||||
headers = headers,
|
||||
cache = CacheControl.FORCE_NETWORK,
|
||||
)
|
||||
}
|
||||
|
||||
// Search
|
||||
|
||||
override fun fetchSearchManga(
|
||||
@ -142,11 +121,13 @@ class CreepyScans : Madara(
|
||||
Filter.Select<String>("Genre", vals.map { it.first }.toTypedArray())
|
||||
|
||||
override fun getFilterList(): FilterList {
|
||||
launchIO { fetchGenres() }
|
||||
|
||||
val filters = buildList(4) {
|
||||
add(
|
||||
OrderByFilter(
|
||||
title = orderByFilterTitle,
|
||||
options = orderByFilterOptions.zip(orderByFilterOptionsValues),
|
||||
title = intl["order_by_filter_title"],
|
||||
options = orderByFilterOptions.map { Pair(it.key, it.value) },
|
||||
state = 0,
|
||||
),
|
||||
)
|
||||
|
@ -4,6 +4,4 @@ import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
|
||||
class DarkScan : Madara("Dark-scan", "https://dark-scan.com", "en") {
|
||||
override val useNewChapterEndpoint = true
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
}
|
||||
|
@ -27,14 +27,6 @@ class DragonTea : Madara(
|
||||
|
||||
override val useNewChapterEndpoint = true
|
||||
|
||||
override fun searchPage(page: Int): String {
|
||||
return if (page > 1) {
|
||||
"page/$page/"
|
||||
} else {
|
||||
""
|
||||
}
|
||||
}
|
||||
|
||||
private val pageIndexRegex = Regex("""image-(\d+)[a-z]+""", RegexOption.IGNORE_CASE)
|
||||
|
||||
override fun pageListParse(document: Document): List<Page> {
|
||||
@ -69,20 +61,8 @@ class DragonTea : Madara(
|
||||
|
||||
val unsaltedCiphertext = Base64.decode(cipherData["ct"]!!.jsonPrimitive.content, Base64.DEFAULT)
|
||||
val salt = cipherData["s"]!!.jsonPrimitive.content.decodeHex()
|
||||
val saltedCiphertext = SALTED + salt + unsaltedCiphertext
|
||||
val saltedCiphertext = salted + salt + unsaltedCiphertext
|
||||
|
||||
return json.parseToJsonElement(CryptoAES.decrypt(Base64.encodeToString(saltedCiphertext, Base64.DEFAULT), key))
|
||||
}
|
||||
|
||||
private fun String.decodeHex(): ByteArray {
|
||||
check(length % 2 == 0) { "Must have an even length" }
|
||||
|
||||
return chunked(2)
|
||||
.map { it.toInt(16).toByte() }
|
||||
.toByteArray()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val SALTED = "Salted__".toByteArray(Charsets.UTF_8)
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,4 @@ import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
class EliteManga : Madara("Elite Manga", "https://www.elitemanga.org", "en") {
|
||||
override val useNewChapterEndpoint = true
|
||||
override val filterNonMangaItems = false
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
}
|
||||
|
@ -4,6 +4,4 @@ import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
|
||||
class FactManga : Madara("FactManga", "https://factmanga.com", "en") {
|
||||
override val useNewChapterEndpoint = true
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ class FireScans : Madara("Fire Scans", "https://firescans.xyz", "en") {
|
||||
override val useNewChapterEndpoint: Boolean = true
|
||||
|
||||
override fun pageListParse(document: Document): List<Page> {
|
||||
countViews(document)
|
||||
launchIO { countViews(document) }
|
||||
|
||||
val chapterProtector = document.selectFirst(chapterProtectorSelector)
|
||||
?: return document.select(pageListParseSelector).mapIndexed { index, element ->
|
||||
@ -46,7 +46,7 @@ class FireScans : Madara("Fire Scans", "https://firescans.xyz", "en") {
|
||||
|
||||
val unsaltedCiphertext = Base64.decode(chapterData["ct"]!!.jsonPrimitive.content, Base64.DEFAULT)
|
||||
val salt = chapterData["s"]!!.jsonPrimitive.content.decodeHex()
|
||||
val ciphertext = SALTED + salt + unsaltedCiphertext
|
||||
val ciphertext = salted + salt + unsaltedCiphertext
|
||||
|
||||
val rawImgArray = CryptoAES.decrypt(Base64.encodeToString(ciphertext, Base64.DEFAULT), password)
|
||||
val imgArrayString = json.parseToJsonElement(rawImgArray).jsonPrimitive.content
|
||||
@ -56,12 +56,4 @@ class FireScans : Madara("Fire Scans", "https://firescans.xyz", "en") {
|
||||
Page(idx, document.location(), it.jsonPrimitive.content)
|
||||
}
|
||||
}
|
||||
|
||||
private fun String.decodeHex(): ByteArray {
|
||||
check(length % 2 == 0) { "Must have an even length" }
|
||||
|
||||
return chunked(2)
|
||||
.map { it.toInt(16).toByte() }
|
||||
.toByteArray()
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,4 @@ import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
|
||||
class FirstKissDashManga : Madara("1st Kiss-Manga (unoriginal)", "https://1stkiss-manga.com", "en") {
|
||||
override val useNewChapterEndpoint = false
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
}
|
||||
|
@ -6,6 +6,4 @@ class FirstManhwa : Madara("1st Manhwa", "https://1stmanhwa.com", "en") {
|
||||
override val useNewChapterEndpoint = true
|
||||
override val filterNonMangaItems = false
|
||||
override val mangaDetailsSelectorStatus = "div.summary-heading:contains(Status) + div.summary-content"
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
}
|
||||
|
@ -4,6 +4,4 @@ import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
|
||||
class FreeManhwa : Madara("Free Manhwa", "https://manhwas.com", "en") {
|
||||
override val useNewChapterEndpoint = false
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
}
|
||||
|
@ -4,6 +4,4 @@ import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
|
||||
class GirlsLoveManga : Madara("Girls Love Manga!", "https://glmanga.com", "en") {
|
||||
override val useNewChapterEndpoint = true
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
}
|
||||
|
@ -12,8 +12,6 @@ class GlobalBloging : Madara(
|
||||
) {
|
||||
override val useNewChapterEndpoint = true
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
|
||||
// =========================== Manga Details ============================
|
||||
|
||||
override val mangaDetailsSelectorThumbnail = "${super.mangaDetailsSelectorThumbnail}[src~=.]"
|
||||
|
@ -2,72 +2,21 @@ package eu.kanade.tachiyomi.extension.en.goodgirlsscan
|
||||
|
||||
import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.POST
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import okhttp3.FormBody
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||
import okhttp3.Request
|
||||
import org.jsoup.nodes.Element
|
||||
|
||||
class GoodGirlsScan : Madara("Good Girls Scan", "https://goodgirls.moe", "en") {
|
||||
|
||||
override val fetchGenres = false
|
||||
override fun popularMangaNextPageSelector() = "body:not(:has(.no-posts))"
|
||||
override val useLoadMoreRequest = LoadMoreStrategy.Always
|
||||
override fun searchMangaSelector() = "article.wp-manga"
|
||||
override fun searchMangaNextPageSelector() = "div.paginator .nav-next"
|
||||
override val mangaDetailsSelectorStatus = "div.summary-heading:contains(Status) + div.summary-content"
|
||||
override val mangaDetailsSelectorDescription = "div.summary-specialfields"
|
||||
override fun chapterListSelector() = "li.wp-manga-chapter:not(.vip-permission)"
|
||||
|
||||
private fun madaraLoadMoreRequest(page: Int, metaKey: String): Request {
|
||||
val formBody = FormBody.Builder().apply {
|
||||
add("action", "madara_load_more")
|
||||
add("page", page.toString())
|
||||
add("template", "madara-core/content/content-archive")
|
||||
add("vars[paged]", "1")
|
||||
add("vars[orderby]", "meta_value_num")
|
||||
add("vars[template]", "archive")
|
||||
add("vars[sidebar]", "right")
|
||||
add("vars[post_type]", "wp-manga")
|
||||
add("vars[post_status]", "publish")
|
||||
add("vars[meta_key]", metaKey)
|
||||
add("vars[meta_query][0][paged]", "1")
|
||||
add("vars[meta_query][0][orderby]", "meta_value_num")
|
||||
add("vars[meta_query][0][template]", "archive")
|
||||
add("vars[meta_query][0][sidebar]", "right")
|
||||
add("vars[meta_query][0][post_type]", "wp-manga")
|
||||
add("vars[meta_query][0][post_status]", "publish")
|
||||
add("vars[meta_query][0][meta_key]", metaKey)
|
||||
add("vars[meta_query][relation]", "AND")
|
||||
add("vars[manga_archives_item_layout]", "default")
|
||||
}.build()
|
||||
|
||||
val xhrHeaders = headersBuilder()
|
||||
.add("Content-Length", formBody.contentLength().toString())
|
||||
.add("Content-Type", formBody.contentType().toString())
|
||||
.add("X-Requested-With", "XMLHttpRequest")
|
||||
.build()
|
||||
|
||||
return POST("$baseUrl/wp-admin/admin-ajax.php", xhrHeaders, formBody)
|
||||
}
|
||||
|
||||
override fun popularMangaRequest(page: Int): Request {
|
||||
return madaraLoadMoreRequest(page - 1, "_wp_manga_views")
|
||||
}
|
||||
|
||||
override fun latestUpdatesRequest(page: Int): Request {
|
||||
return madaraLoadMoreRequest(page - 1, "_latest_update")
|
||||
}
|
||||
|
||||
override fun searchPage(page: Int): String {
|
||||
return if (page > 1) {
|
||||
"page/$page/"
|
||||
} else {
|
||||
""
|
||||
}
|
||||
}
|
||||
|
||||
// heavily modified madara theme, throws 5xx errors on any search filter
|
||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
||||
val url = "$baseUrl/${searchPage(page)}".toHttpUrl().newBuilder().apply {
|
||||
|
@ -21,8 +21,6 @@ class GourmetScans : Madara(
|
||||
|
||||
// Search
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
|
||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
||||
val url = baseUrl.toHttpUrl().newBuilder()
|
||||
|
||||
@ -77,23 +75,23 @@ class GourmetScans : Madara(
|
||||
|
||||
private var genresList: List<Pair<String, String>> = emptyList()
|
||||
|
||||
class GenreFilter(val vals: List<Pair<String, String>>) :
|
||||
class GenreFilter(vals: List<Pair<String, String>>) :
|
||||
UriPartFilter("Genre", vals.toTypedArray())
|
||||
|
||||
override fun getFilterList(): FilterList {
|
||||
val filters = buildList(4) {
|
||||
add(YearFilter(yearFilterTitle))
|
||||
add(YearFilter(intl["year_filter_title"]))
|
||||
add(
|
||||
OrderByFilter(
|
||||
title = orderByFilterTitle,
|
||||
options = orderByFilterOptions.zip(orderByFilterOptionsValues),
|
||||
title = intl["order_by_filter_title"],
|
||||
options = orderByFilterOptions.map { Pair(it.key, it.value) },
|
||||
state = 0,
|
||||
),
|
||||
)
|
||||
add(Filter.Separator())
|
||||
|
||||
if (genresList.isEmpty()) {
|
||||
add(Filter.Header(genresMissingWarning))
|
||||
add(Filter.Header(intl["genre_missing_warning"]))
|
||||
} else {
|
||||
add(GenreFilter(listOf(Pair("<select>", "")) + genresList))
|
||||
}
|
||||
|
@ -4,6 +4,4 @@ import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
|
||||
class Hentai3z : Madara("Hentai3z", "https://hentai3z.xyz", "en") {
|
||||
override val useNewChapterEndpoint = false
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
}
|
||||
|
@ -8,8 +8,6 @@ class Hentai4Free : Madara("Hentai4Free", "https://hentai4free.net", "en") {
|
||||
override val useNewChapterEndpoint = true
|
||||
override val mangaSubString = "hentai"
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
|
||||
override fun popularMangaSelector() = searchMangaSelector()
|
||||
|
||||
override fun popularMangaRequest(page: Int): Request =
|
||||
|
@ -22,10 +22,10 @@ class Hentairead : Madara("HentaiRead", "https://hentairead.com", "en", dateForm
|
||||
override val pageListParseSelector = "li.chapter-image-item > a > div.image-wrapper"
|
||||
|
||||
override fun pageListParse(document: Document): List<Page> {
|
||||
super.countViews(document)
|
||||
launchIO { countViews(document) }
|
||||
|
||||
return document.select(pageListParseSelector).mapIndexed { index, element ->
|
||||
var pageUri: String? = element.select("img").first()?.let {
|
||||
val pageUri: String? = element.selectFirst("img")!!.let {
|
||||
it.absUrl(if (it.hasAttr("data-src")) "data-src" else "src")
|
||||
}
|
||||
Page(
|
||||
|
@ -7,14 +7,6 @@ import org.jsoup.nodes.Document
|
||||
|
||||
class HentaiXDickgirl : Madara("HentaiXDickgirl", "https://hentaixdickgirl.com", "en") {
|
||||
|
||||
override fun searchPage(page: Int): String {
|
||||
return if (page > 1) {
|
||||
"page/$page/"
|
||||
} else {
|
||||
""
|
||||
}
|
||||
}
|
||||
|
||||
override fun mangaDetailsParse(document: Document): SManga {
|
||||
return super.mangaDetailsParse(document).apply {
|
||||
update_strategy = UpdateStrategy.ONLY_FETCH_ONCE
|
||||
|
@ -6,23 +6,22 @@ import android.widget.Toast
|
||||
import androidx.preference.EditTextPreference
|
||||
import androidx.preference.PreferenceScreen
|
||||
import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
import eu.kanade.tachiyomi.source.ConfigurableSource
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.Response
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
class Hiperdex : Madara("Hiperdex", "https://hiperdex.com", "en") {
|
||||
class Hiperdex :
|
||||
Madara(
|
||||
"Hiperdex",
|
||||
"https://hiperdex.com",
|
||||
"en",
|
||||
),
|
||||
ConfigurableSource {
|
||||
override val useNewChapterEndpoint: Boolean = true
|
||||
|
||||
override fun searchPage(page: Int): String {
|
||||
return if (page > 1) {
|
||||
"page/$page/"
|
||||
} else {
|
||||
""
|
||||
}
|
||||
}
|
||||
|
||||
override val baseUrl by lazy { getPrefBaseUrl() }
|
||||
|
||||
private val preferences by lazy {
|
||||
@ -103,8 +102,6 @@ class Hiperdex : Madara("Hiperdex", "https://hiperdex.com", "en") {
|
||||
}
|
||||
}
|
||||
screen.addPreference(baseUrlPref)
|
||||
|
||||
super.setupPreferenceScreen(screen)
|
||||
}
|
||||
|
||||
private var SharedPreferences.baseUrlHost
|
||||
|
@ -40,9 +40,6 @@ class IsekaiScanTop : Madara(
|
||||
|
||||
if (chapterElements.isEmpty() && !chaptersWrapper.isNullOrEmpty()) {
|
||||
val mangaId = chaptersWrapper.attr("data-id")
|
||||
val xhrHeaders = headersBuilder()
|
||||
.add("X-Requested-With", "XMLHttpRequest")
|
||||
.build()
|
||||
val xhrRequest = GET("$baseUrl/ajax-list-chapter?mangaID=$mangaId", xhrHeaders)
|
||||
val xhrResponse = client.newCall(xhrRequest).execute()
|
||||
|
||||
@ -50,7 +47,7 @@ class IsekaiScanTop : Madara(
|
||||
xhrResponse.close()
|
||||
}
|
||||
|
||||
countViews(document)
|
||||
launchIO { countViews(document) }
|
||||
return chapterElements.map(::chapterFromElement)
|
||||
}
|
||||
|
||||
@ -65,7 +62,7 @@ class IsekaiScanTop : Madara(
|
||||
}
|
||||
}
|
||||
|
||||
override fun searchPage(page: Int): String = "search?page=$page"
|
||||
override fun searchPage(page: Int) = "search?page=$page"
|
||||
|
||||
override fun searchMangaNextPageSelector(): String? = "ul.pagination li:last-child a"
|
||||
override fun searchMangaNextPageSelector() = "ul.pagination li:last-child a"
|
||||
}
|
||||
|
@ -5,6 +5,4 @@ import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
class Jimanga : Madara("Jimanga", "https://jimanga.com", "en") {
|
||||
override val useNewChapterEndpoint = false
|
||||
override val filterNonMangaItems = false
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
}
|
||||
|
@ -4,6 +4,4 @@ import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
|
||||
class LuffyManga : Madara("Luffy Manga", "https://luffymanga.com", "en") {
|
||||
override val useNewChapterEndpoint = false
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
}
|
||||
|
@ -4,6 +4,4 @@ import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
|
||||
class LuxManga : Madara("LuxManga", "https://luxmanga.net", "en") {
|
||||
override val useNewChapterEndpoint = false
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
}
|
||||
|
@ -4,6 +4,4 @@ import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
|
||||
class Manga18h : Madara("Manga 18h", "https://manga18h.com", "en") {
|
||||
override val useNewChapterEndpoint = false
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
}
|
||||
|
@ -4,6 +4,4 @@ import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
|
||||
class Manga18x : Madara("Manga 18x", "https://manga18x.net", "en") {
|
||||
override val useNewChapterEndpoint = true
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
}
|
||||
|
@ -12,6 +12,4 @@ class MangaBee : Madara(
|
||||
) {
|
||||
override val useNewChapterEndpoint = true
|
||||
override val filterNonMangaItems = false
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
}
|
||||
|
@ -4,6 +4,4 @@ import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
|
||||
class MangaClashTv : Madara("MangaClash.tv (unoriginal)", "https://mangaclash.tv", "en") {
|
||||
override val useNewChapterEndpoint = false
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
}
|
||||
|
@ -4,6 +4,4 @@ import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
|
||||
class MangaDash1001Com : Madara("Manga-1001.com", "https://manga-1001.com", "en") {
|
||||
override val useNewChapterEndpoint = false
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
}
|
||||
|
@ -4,6 +4,4 @@ import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
|
||||
class MangaDinoTop : Madara("MangaDino.top (unoriginal)", "https://mangadino.top", "en") {
|
||||
override val useNewChapterEndpoint = false
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
}
|
||||
|
@ -6,6 +6,4 @@ class MangaHentai : Madara("Manga Hentai", "https://mangahentai.me", "en") {
|
||||
override val mangaSubString = "manga-hentai"
|
||||
|
||||
override val useNewChapterEndpoint: Boolean = true
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
}
|
||||
|
@ -5,6 +5,4 @@ import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
class MangaKitsu : Madara("Manga Kitsu", "https://mangakitsu.com", "en") {
|
||||
override val useNewChapterEndpoint = false
|
||||
override val mangaDetailsSelectorStatus = "div.summary-heading:contains(Status) + div.summary-content"
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ class MangaLeveling : Madara("Manga Leveling", "https://mangaleveling.com", "en"
|
||||
val chapter = SChapter.create()
|
||||
|
||||
with(element) {
|
||||
select(chapterUrlSelector).first()?.let { urlElement ->
|
||||
selectFirst(chapterUrlSelector)!!.let { urlElement ->
|
||||
chapter.url = urlElement.attr("abs:href").let {
|
||||
it.substringBefore("?style=paged") + if (!it.endsWith(chapterUrlSuffix)) chapterUrlSuffix else ""
|
||||
}
|
||||
@ -20,9 +20,9 @@ class MangaLeveling : Madara("Manga Leveling", "https://mangaleveling.com", "en"
|
||||
}
|
||||
// Dates can be part of a "new" graphic or plain text
|
||||
// Added "title" alternative
|
||||
chapter.date_upload = select("img:not(.thumb)").firstOrNull()?.attr("alt")?.let { parseRelativeDate(it) }
|
||||
?: select("span a").firstOrNull()?.attr("title")?.let { parseRelativeDate(it) }
|
||||
?: parseChapterDate(select(chapterDateSelector()).firstOrNull()?.text())
|
||||
chapter.date_upload = selectFirst("img:not(.thumb)")?.attr("alt")?.let { parseRelativeDate(it) }
|
||||
?: selectFirst("span a")?.attr("title")?.let { parseRelativeDate(it) }
|
||||
?: parseChapterDate(selectFirst(chapterDateSelector())?.text())
|
||||
}
|
||||
|
||||
return chapter
|
||||
|
@ -4,6 +4,4 @@ import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
|
||||
class ManganeloBiz : Madara("Manganelo.biz", "https://manganelo.biz", "en") {
|
||||
override val useNewChapterEndpoint = false
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
}
|
||||
|
@ -4,6 +4,4 @@ import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
|
||||
class ManganeloWebsite : Madara("Manganelo.website (unoriginal)", "https://manganelo.website", "en") {
|
||||
override val useNewChapterEndpoint = false
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
}
|
||||
|
@ -4,6 +4,4 @@ import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
|
||||
class MangaNerds : Madara("Manga Nerds", "https://manganerds.com", "en") {
|
||||
override val useNewChapterEndpoint = true
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
}
|
||||
|
@ -4,6 +4,4 @@ import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
|
||||
class MangaOnlineTeamUnoriginal : Madara("MangaOnline.team (unoriginal)", "https://mangaonline.team", "en") {
|
||||
override val useNewChapterEndpoint = false
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
}
|
||||
|
@ -4,6 +4,4 @@ import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
|
||||
class MangaOwlBlog : Madara("MangaOwl.blog (unoriginal)", "https://mangaowl.blog", "en") {
|
||||
override val useNewChapterEndpoint = false
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
}
|
||||
|
@ -4,6 +4,4 @@ import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
|
||||
class MangaOwlIo : Madara("MangaOwl.io (unoriginal)", "https://mangaowl.io", "en") {
|
||||
override val useNewChapterEndpoint = true
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
}
|
||||
|
@ -5,6 +5,4 @@ import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
class MangaOwlOne : Madara("MangaOwl.one (unoriginal)", "https://mangaowl.one", "en") {
|
||||
override val useNewChapterEndpoint = false
|
||||
override val filterNonMangaItems = false
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
}
|
||||
|
@ -4,6 +4,4 @@ import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
|
||||
class MangaOwlUs : Madara("MangaOwl.us (unoriginal)", "https://mangaowl.us", "en") {
|
||||
override val useNewChapterEndpoint = true
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ class MangaPure : Madara(
|
||||
xhrResponse.close()
|
||||
}
|
||||
|
||||
countViews(document)
|
||||
launchIO { countViews(document) }
|
||||
return chapterElements.map(::chapterFromElement)
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,4 @@ import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
|
||||
class MangaQueenCom : Madara("Manga Queen.com", "https://mangaqueen.com", "en") {
|
||||
override val useNewChapterEndpoint = false
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
}
|
||||
|
@ -4,6 +4,4 @@ import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
|
||||
class MangaRawInfo : Madara("Manga-Raw.info (unoriginal)", "https://manga-raw.info", "en") {
|
||||
override val useNewChapterEndpoint = false
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
}
|
||||
|
@ -4,6 +4,4 @@ import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
|
||||
class MangaRockTeamUnoriginal : Madara("Manga Rock.team (unoriginal)", "https://mangarock.team", "en") {
|
||||
override val useNewChapterEndpoint = false
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
}
|
||||
|
@ -5,6 +5,4 @@ import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
class MangaRosie : Madara("MangaRosie", "https://mangarosie.in", "en") {
|
||||
override val useNewChapterEndpoint = false
|
||||
override val mangaDetailsSelectorStatus = "div.summary-heading:contains(Status) + div.summary-content"
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
}
|
||||
|
@ -5,6 +5,4 @@ import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
class MangaRubyCom : Madara("MangaRuby.com", "https://mangaruby.com", "en") {
|
||||
override val useNewChapterEndpoint = true
|
||||
override val filterNonMangaItems = false
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
}
|
||||
|
@ -4,6 +4,4 @@ import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
|
||||
class Mangaryu : Madara("Mangaryu", "https://mangaryu.com", "en") {
|
||||
override val useNewChapterEndpoint = false
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
}
|
||||
|
@ -4,6 +4,4 @@ import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
|
||||
class MangaTxGg : Madara("Manga Tx.gg (unoriginal)", "https://mangatx.gg", "en") {
|
||||
override val useNewChapterEndpoint = false
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
}
|
||||
|
@ -5,6 +5,4 @@ import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
class MangaTyrant : Madara("MangaTyrant", "https://mangatyrant.com", "en") {
|
||||
override val useNewChapterEndpoint = true
|
||||
override val filterNonMangaItems = false
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
}
|
||||
|
@ -4,6 +4,4 @@ import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
|
||||
class MangaUpdatesTop : Madara("MangaUpdates.top (unoriginal)", "https://mangaupdates.top", "en") {
|
||||
override val useNewChapterEndpoint = false
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
}
|
||||
|
@ -4,6 +4,4 @@ import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
|
||||
class ManhuaDex : Madara("ManhuaDex", "https://manhuadex.com", "en") {
|
||||
override val useNewChapterEndpoint = true
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
}
|
||||
|
@ -1,11 +1,8 @@
|
||||
package eu.kanade.tachiyomi.extension.en.manhuafast
|
||||
|
||||
import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
||||
import okhttp3.CacheControl
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class ManhuaFast : Madara("ManhuaFast", "https://manhuafast.com", "en") {
|
||||
@ -16,22 +13,4 @@ class ManhuaFast : Madara("ManhuaFast", "https://manhuafast.com", "en") {
|
||||
|
||||
// The website does not flag the content.
|
||||
override val filterNonMangaItems = false
|
||||
|
||||
override fun popularMangaRequest(page: Int): Request {
|
||||
return GET(
|
||||
url = "$baseUrl/${searchPage(page)}?s&post_type=wp-manga&m_orderby=views",
|
||||
headers = headers,
|
||||
cache = CacheControl.FORCE_NETWORK,
|
||||
)
|
||||
}
|
||||
|
||||
override fun popularMangaSelector() = searchMangaSelector()
|
||||
|
||||
override fun latestUpdatesRequest(page: Int): Request {
|
||||
return GET(
|
||||
url = "$baseUrl/${searchPage(page)}?s&post_type=wp-manga&m_orderby=latest",
|
||||
headers = headers,
|
||||
cache = CacheControl.FORCE_NETWORK,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,4 @@ import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
|
||||
class ManhuaFastNet : Madara("ManhuaFast.net (unoriginal)", "https://manhuafast.net", "en") {
|
||||
override val useNewChapterEndpoint = true
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
}
|
||||
|
@ -12,6 +12,4 @@ class ManhuaManhwa : Madara(
|
||||
) {
|
||||
override val useNewChapterEndpoint = true
|
||||
override val filterNonMangaItems = false
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
}
|
||||
|
@ -4,6 +4,4 @@ import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
|
||||
class ManhuaManhwaOnline : Madara("ManhuaManhwa.online", "https://manhuamanhwa.online", "en") {
|
||||
override val useNewChapterEndpoint = false
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
}
|
||||
|
@ -4,6 +4,4 @@ import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
|
||||
class ManhuaScanInfo : Madara("ManhuaScan.info (unoriginal)", "https://manhuascan.info", "en") {
|
||||
override val useNewChapterEndpoint = false
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
}
|
||||
|
@ -6,6 +6,4 @@ class ManhuaZonghe : Madara("Manhua Zonghe", "https://manhuazonghe.com", "en") {
|
||||
override val useNewChapterEndpoint = false
|
||||
override val filterNonMangaItems = false
|
||||
override val mangaSubString = "manhua"
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
}
|
||||
|
@ -4,6 +4,4 @@ import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
|
||||
class Manhwa2Read : Madara("Manhwa2Read", "https://manhwa2read.com", "en") {
|
||||
override val useNewChapterEndpoint = true
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
}
|
||||
|
@ -1,26 +1,7 @@
|
||||
package eu.kanade.tachiyomi.extension.en.manhwafull
|
||||
|
||||
import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import okhttp3.CacheControl
|
||||
import okhttp3.Request
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
|
||||
class Manhwafull : Madara("Manhwafull", "https://manhwafull.com", "en") {
|
||||
|
||||
override fun popularMangaNextPageSelector(): String? = "a.nextpostslink"
|
||||
|
||||
override fun popularMangaRequest(page: Int): Request {
|
||||
return GET(
|
||||
"$baseUrl/manga-mwf/page/$page/?m_orderby=views",
|
||||
headers,
|
||||
CacheControl.FORCE_NETWORK,
|
||||
)
|
||||
}
|
||||
override fun latestUpdatesRequest(page: Int): Request {
|
||||
return GET(
|
||||
"$baseUrl/manga-mwf/page/$page/?m_orderby=latest",
|
||||
headers,
|
||||
CacheControl.FORCE_NETWORK,
|
||||
)
|
||||
}
|
||||
}
|
||||
class Manhwafull : Madara("Manhwafull", "https://manhwafull.com", "en", SimpleDateFormat("MM/dd/yyyy", Locale.ENGLISH))
|
||||
|
@ -5,6 +5,4 @@ import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
class ManhwaManhua : Madara("ManhwaManhua", "https://manhwamanhua.com", "en") {
|
||||
override val useNewChapterEndpoint = true
|
||||
override val filterNonMangaItems = false
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
}
|
||||
|
@ -12,6 +12,4 @@ class ManhwaNew : Madara(
|
||||
) {
|
||||
override val useNewChapterEndpoint = true
|
||||
override val filterNonMangaItems = false
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
}
|
||||
|
@ -108,9 +108,7 @@ class ManhwaZ : Madara(
|
||||
val mangaList = document.select(".page-search > .container > .row > div")
|
||||
.map(::searchMangaFromElement)
|
||||
|
||||
val hasNextPage = searchMangaNextPageSelector().let { selector ->
|
||||
document.select(selector).first()
|
||||
} != null
|
||||
val hasNextPage = document.selectFirst(searchMangaNextPageSelector()) != null
|
||||
|
||||
return MangasPage(mangaList, hasNextPage)
|
||||
}
|
||||
|
@ -12,19 +12,19 @@ class MidnightMessScans : Madara("Midnight Mess Scans", "https://midnightmess.or
|
||||
override fun mangaDetailsParse(document: Document): SManga {
|
||||
val manga = SManga.create()
|
||||
with(document) {
|
||||
select("div.post-title h3").first()?.let {
|
||||
selectFirst("div.post-title h3")!!.let {
|
||||
manga.title = it.ownText()
|
||||
}
|
||||
select("div.author-content").first()?.let {
|
||||
selectFirst("div.author-content")?.let {
|
||||
if (it.text().notUpdating()) manga.author = it.text()
|
||||
}
|
||||
select("div.artist-content").first()?.let {
|
||||
selectFirst("div.artist-content")?.let {
|
||||
if (it.text().notUpdating()) manga.artist = it.text()
|
||||
}
|
||||
select("div.summary_content div.post-content").let {
|
||||
manga.description = it.select("div.manga-excerpt").text()
|
||||
}
|
||||
select("div.summary_image img").first()?.let {
|
||||
selectFirst("div.summary_image img")?.let {
|
||||
manga.thumbnail_url = imageFromElement(it)
|
||||
}
|
||||
select("div.summary-content").last()?.let {
|
||||
@ -48,7 +48,7 @@ class MidnightMessScans : Madara("Midnight Mess Scans", "https://midnightmess.or
|
||||
}
|
||||
|
||||
// add manga/manhwa/manhua thinggy to genre
|
||||
document.select(seriesTypeSelector).firstOrNull()?.ownText()?.let {
|
||||
document.selectFirst(seriesTypeSelector)?.ownText()?.let {
|
||||
if (it.isEmpty().not() && it.notUpdating() && it != "-" && genres.contains(it).not()) {
|
||||
genres.add(it.lowercase(Locale.ROOT))
|
||||
}
|
||||
|
@ -1,10 +1,7 @@
|
||||
package eu.kanade.tachiyomi.extension.en.milftoon
|
||||
|
||||
import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import okhttp3.Request
|
||||
|
||||
class Milftoon : Madara("Milftoon", "https://milftoon.xxx", "en") {
|
||||
override fun popularMangaRequest(page: Int): Request = GET("$baseUrl/page/$page/?m_orderby=views", headers)
|
||||
override fun latestUpdatesRequest(page: Int): Request = GET("$baseUrl/page/$page/?m_orderby=latest", headers)
|
||||
override val mangaSubString = "comics"
|
||||
}
|
||||
|
@ -1,71 +1,30 @@
|
||||
package eu.kanade.tachiyomi.extension.en.mmscans
|
||||
|
||||
import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
import eu.kanade.tachiyomi.network.POST
|
||||
import eu.kanade.tachiyomi.source.model.SChapter
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import okhttp3.FormBody
|
||||
import okhttp3.Request
|
||||
import org.jsoup.nodes.Element
|
||||
|
||||
class MMScans : Madara("MMScans", "https://mm-scans.org", "en") {
|
||||
|
||||
// The site customized the listing and does not include a .manga class.
|
||||
override val filterNonMangaItems = false
|
||||
override val useLoadMoreRequest = LoadMoreStrategy.Always
|
||||
|
||||
override val popularMangaUrlSelector = "div.item-summary a"
|
||||
override fun chapterListSelector() = "li.chapter-li"
|
||||
override fun searchMangaSelector() = ".search-wrap >.tab-content-wrap > a"
|
||||
override fun searchMangaNextPageSelector(): String? = "body:not(:has(.no-posts))"
|
||||
|
||||
fun oldLoadMoreRequest(page: Int, metaKey: String): Request {
|
||||
val form = FormBody.Builder()
|
||||
.add("action", "madara_load_more")
|
||||
.add("page", page.toString())
|
||||
.add("template", "madara-core/content/content-archive")
|
||||
.add("vars[paged]", "1")
|
||||
.add("vars[orderby]", "meta_value_num")
|
||||
.add("vars[template]", "archive")
|
||||
.add("vars[sidebar]", "right")
|
||||
.add("vars[post_type]", "wp-manga")
|
||||
.add("vars[post_status]", "publish")
|
||||
.add("vars[meta_key]", metaKey)
|
||||
.add("vars[meta_query][0][paged]", "1")
|
||||
.add("vars[meta_query][0][orderby]", "meta_value_num")
|
||||
.add("vars[meta_query][0][template]", "archive")
|
||||
.add("vars[meta_query][0][sidebar]", "right")
|
||||
.add("vars[meta_query][0][post_type]", "wp-manga")
|
||||
.add("vars[meta_query][0][post_status]", "publish")
|
||||
.add("vars[meta_query][0][meta_key]", metaKey)
|
||||
.add("vars[meta_query][relation]", "AND")
|
||||
.add("vars[manga_archives_item_layout]", "default")
|
||||
.build()
|
||||
|
||||
val xhrHeaders = headersBuilder()
|
||||
.add("Content-Length", form.contentLength().toString())
|
||||
.add("Content-Type", form.contentType().toString())
|
||||
.add("X-Requested-With", "XMLHttpRequest")
|
||||
.build()
|
||||
|
||||
return POST("$baseUrl/wp-admin/admin-ajax.php", xhrHeaders, form)
|
||||
}
|
||||
|
||||
override fun popularMangaRequest(page: Int): Request {
|
||||
return oldLoadMoreRequest(page - 1, "_wp_manga_views")
|
||||
}
|
||||
override fun latestUpdatesRequest(page: Int): Request {
|
||||
return oldLoadMoreRequest(page - 1, "_latest_update")
|
||||
}
|
||||
override fun popularMangaFromElement(element: Element): SManga {
|
||||
val manga = SManga.create()
|
||||
|
||||
with(element) {
|
||||
select(popularMangaUrlSelector).first()?.let {
|
||||
selectFirst(popularMangaUrlSelector)?.let {
|
||||
manga.setUrlWithoutDomain(it.attr("abs:href"))
|
||||
manga.title = it.selectFirst("h3")!!.ownText()
|
||||
}
|
||||
|
||||
select("img").first()?.let {
|
||||
selectFirst("img")?.let {
|
||||
manga.thumbnail_url = imageFromElement(it)
|
||||
}
|
||||
}
|
||||
@ -77,13 +36,13 @@ class MMScans : Madara("MMScans", "https://mm-scans.org", "en") {
|
||||
val chapter = SChapter.create()
|
||||
|
||||
with(element) {
|
||||
select(chapterUrlSelector).first()?.let { urlElement ->
|
||||
selectFirst(chapterUrlSelector)!!.let { urlElement ->
|
||||
chapter.url = urlElement.attr("abs:href").let {
|
||||
it.substringBefore("?style=paged") + if (!it.endsWith(chapterUrlSuffix)) chapterUrlSuffix else ""
|
||||
}
|
||||
chapter.name = urlElement.selectFirst(".chapter-title-date p")!!.text()
|
||||
}
|
||||
chapter.date_upload = parseChapterDate(select(chapterDateSelector()).firstOrNull()?.text())
|
||||
chapter.date_upload = parseChapterDate(selectFirst(chapterDateSelector())?.text())
|
||||
}
|
||||
|
||||
return chapter
|
||||
|
@ -10,6 +10,4 @@ class NitroScans : Madara("Nitro Manga", "https://nitromanga.com", "en") {
|
||||
override val filterNonMangaItems = false
|
||||
|
||||
override val useNewChapterEndpoint = true
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
}
|
||||
|
@ -13,6 +13,4 @@ class OnlyManhwa : Madara(
|
||||
override val useNewChapterEndpoint = true
|
||||
override val mangaSubString = "manhwa"
|
||||
override val mangaDetailsSelectorStatus = "div.summary-heading:contains(Status) + div.summary-content"
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
}
|
||||
|
@ -4,12 +4,4 @@ import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
|
||||
class OPSCANS : Madara("OPSCANS", "https://opchapters.com", "en") {
|
||||
override val versionId = 2
|
||||
|
||||
override fun searchPage(page: Int): String {
|
||||
return if (page > 1) {
|
||||
"page/$page/"
|
||||
} else {
|
||||
""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,8 +14,6 @@ class ParagonScans : Madara(
|
||||
override val useNewChapterEndpoint = true
|
||||
override val mangaSubString = "mangax"
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
|
||||
override fun parseChapterDate(date: String?): Long {
|
||||
date ?: return 0
|
||||
|
||||
|
@ -4,6 +4,4 @@ import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
|
||||
class PawManga : Madara("Paw Manga", "https://pawmanga.com", "en") {
|
||||
override val useNewChapterEndpoint = true
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
}
|
||||
|
@ -12,6 +12,4 @@ class PMScans : Madara(
|
||||
) {
|
||||
override val versionId = 2
|
||||
override val useNewChapterEndpoint = true
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
}
|
||||
|
@ -4,6 +4,4 @@ import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
|
||||
class PonyManga : Madara("Pony Manga", "https://ponymanga.com", "en") {
|
||||
override val useNewChapterEndpoint = false
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ class ReadManhua : Madara(
|
||||
val year = Calendar.getInstance().get(Calendar.YEAR).toLong()
|
||||
|
||||
with(element) {
|
||||
select(chapterUrlSelector).first()?.let { urlElement ->
|
||||
selectFirst(chapterUrlSelector)?.let { urlElement ->
|
||||
chapter.url = urlElement.attr("abs:href").let {
|
||||
it.substringBefore("?style=paged") + if (!it.endsWith(chapterUrlSuffix)) chapterUrlSuffix else ""
|
||||
}
|
||||
@ -27,8 +27,8 @@ class ReadManhua : Madara(
|
||||
}
|
||||
|
||||
// Dates can be part of a "new" graphic or plain text
|
||||
chapter.date_upload = select("img").firstOrNull()?.attr("alt")?.let { parseRelativeDate(it) }
|
||||
?: parseChapterDate(select("span.chapter-release-date i").firstOrNull()?.text() + " " + year)
|
||||
chapter.date_upload = selectFirst("img")?.attr("alt")?.let { parseRelativeDate(it) }
|
||||
?: parseChapterDate(selectFirst("span.chapter-release-date i")?.text() + " " + year)
|
||||
}
|
||||
|
||||
return chapter
|
||||
|
@ -19,8 +19,6 @@ class SectScans : Madara("SectScans", "https://sectscans.com", "en") {
|
||||
|
||||
override val useNewChapterEndpoint = true
|
||||
|
||||
override fun searchPage(page: Int): String = if (page == 1) "" else "page/$page/"
|
||||
|
||||
// =========================== Manga Details ============================
|
||||
|
||||
override val mangaDetailsSelectorTitle = ".post-title"
|
||||
|
@ -2,7 +2,6 @@ package eu.kanade.tachiyomi.extension.en.setsuscans
|
||||
|
||||
import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.Response
|
||||
|
||||
@ -60,31 +59,7 @@ class SetsuScans : Madara(
|
||||
}
|
||||
|
||||
override val useNewChapterEndpoint = true
|
||||
|
||||
override fun searchPage(page: Int): String {
|
||||
return if (page > 1) {
|
||||
"page/$page/"
|
||||
} else {
|
||||
""
|
||||
}
|
||||
}
|
||||
|
||||
override fun popularMangaParse(response: Response) =
|
||||
super.popularMangaParse(response).fixNextPage()
|
||||
|
||||
override fun latestUpdatesParse(response: Response) =
|
||||
super.latestUpdatesParse(response).fixNextPage()
|
||||
|
||||
override fun searchMangaParse(response: Response) =
|
||||
super.searchMangaParse(response).fixNextPage()
|
||||
|
||||
private fun MangasPage.fixNextPage(): MangasPage {
|
||||
return if (mangas.size < 12) {
|
||||
MangasPage(mangas, false)
|
||||
} else {
|
||||
this
|
||||
}
|
||||
}
|
||||
override val useLoadMoreRequest = LoadMoreStrategy.Always
|
||||
|
||||
override val mangaDetailsSelectorStatus = "div.summary-heading:contains(status) + div.summary-content"
|
||||
}
|
||||
|
@ -12,12 +12,4 @@ class ShibaManga : Madara(
|
||||
) {
|
||||
override val filterNonMangaItems = false
|
||||
override val useNewChapterEndpoint = true
|
||||
|
||||
override fun searchPage(page: Int): String {
|
||||
return if (page > 1) {
|
||||
"page/$page/"
|
||||
} else {
|
||||
""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user