Remove more dead sources (#19157)

* Remove Manga4All

* Remove Hatachi Manga

* Remove Comictoon

* Remove Manga-Online.co

* Remove Familiar by Soushiyo

* Remove FaeStorm

* Remove Painful Nightz Scan

* Remove Scans Raw

* Remove QManga

* Remove MangaTigre
This commit is contained in:
Vetle Ledaal 2023-12-02 15:41:06 +00:00 committed by GitHub
parent e5b246774c
commit a17eee9d8c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
78 changed files with 0 additions and 1964 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

View File

@ -1,7 +0,0 @@
package eu.kanade.tachiyomi.extension.th.comictoon
import eu.kanade.tachiyomi.multisrc.madara.Madara
import java.text.SimpleDateFormat
import java.util.Locale
class Comictoon : Madara("Comictoon", "https://comictoonthaith-new.com", "th", SimpleDateFormat("MMMMM dd, yyyy", Locale("th")))

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 317 KiB

View File

@ -1,12 +0,0 @@
package eu.kanade.tachiyomi.extension.tr.faestorm
import eu.kanade.tachiyomi.multisrc.madara.Madara
import java.text.SimpleDateFormat
import java.util.Locale
class FaeStorm : Madara(
"FaeStorm",
"https://faestormmanga.com",
"tr",
SimpleDateFormat("d MMM yyy", Locale("tr")),
)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

View File

@ -1,12 +0,0 @@
package eu.kanade.tachiyomi.extension.en.manga4all
import eu.kanade.tachiyomi.multisrc.madara.Madara
import java.text.SimpleDateFormat
import java.util.Locale
class Manga4All : Madara(
"Manga4All",
"https://manga4all.net",
"en",
dateFormat = SimpleDateFormat("d MMM yyyy", Locale.US),
)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 75 KiB

View File

@ -1,11 +0,0 @@
package eu.kanade.tachiyomi.extension.th.mangaonlineco
import eu.kanade.tachiyomi.multisrc.madara.Madara
import eu.kanade.tachiyomi.source.model.SChapter
import okhttp3.Response
import java.text.SimpleDateFormat
import java.util.Locale
class MangaOnlineCo : Madara("Manga-Online.co", "https://www.manga-online.co", "th", SimpleDateFormat("MMM dd, yyyy", Locale("th"))) {
override fun chapterListParse(response: Response): List<SChapter> = super.chapterListParse(response).reversed()
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 257 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 101 KiB

View File

@ -1,7 +0,0 @@
package eu.kanade.tachiyomi.extension.en.scansraw
import eu.kanade.tachiyomi.multisrc.madara.Madara
class ScansRaw : Madara("Scans Raw", "https://scansraw.com", "en") {
override val useNewChapterEndpoint: Boolean = true
}

View File

@ -77,7 +77,6 @@ class MadaraGenerator : ThemeSourceGenerator {
SingleLang("ComicKiba", "https://comickiba.com", "en", overrideVersionCode = 1),
SingleLang("Comics Valley", "https://comicsvalley.com", "hi", isNsfw = true, overrideVersionCode = 1),
SingleLang("ComicsWorld", "https://comicsworld.in", "hi"),
SingleLang("Comictoon", "https://comictoonthaith-new.com", "th", isNsfw = true),
SingleLang("Comicz.net v2", "https://v2.comiz.net", "all", isNsfw = true, className = "ComiczNetV2"),
SingleLang("Cookie Kiara", "https://18.kiara.cool", "en", isNsfw = true),
SingleLang("CopyPasteScan", "https://copypastescan.xyz", "es", overrideVersionCode = 1),
@ -101,7 +100,6 @@ class MadaraGenerator : ThemeSourceGenerator {
SingleLang("Eromiau", "https://www.eromiau.com", "es", isNsfw = true),
SingleLang("Esomanga", "https://esomanga.com", "tr", overrideVersionCode = 1),
SingleLang("FactManga", "https://factmanga.com", "en", isNsfw = false),
SingleLang("FaeStorm", "https://faestormmanga.com", "tr"),
SingleLang("Fay Scans", "https://fayscans.com.br", "pt-BR", overrideVersionCode = 1),
SingleLang("Final Scans", "https://finalscans.com", "pt-BR", isNsfw = true, overrideVersionCode = 1),
SingleLang("Fire Scans", "https://firescans.xyz", "en", overrideVersionCode = 1),
@ -128,7 +126,6 @@ class MadaraGenerator : ThemeSourceGenerator {
SingleLang("Hades no Fansub Hentai", "https://h.mangareaderpro.com", "es", isNsfw = true),
SingleLang("Hades no Fansub", "https://mangareaderpro.com", "es", overrideVersionCode = 1),
SingleLang("Harimanga", "https://harimanga.com", "en", overrideVersionCode = 3),
SingleLang("Hatachi Manga", "https://hachiraw.com", "ja", isNsfw = true, overrideVersionCode = 2),
SingleLang("Hattori Manga", "https://hattorimanga.com", "tr", isNsfw = true),
SingleLang("Hayalistic", "https://hayalistic.com", "tr"),
SingleLang("Hentai CB", "https://hentaicube.net", "vi", isNsfw = true, overrideVersionCode = 6, pkgName = "hentaicube"),
@ -236,7 +233,6 @@ class MadaraGenerator : ThemeSourceGenerator {
SingleLang("Manga Weebs", "https://mangaweebs.in", "en", overrideVersionCode = 8),
SingleLang("Manga-1001.com", "https://manga-1001.com", "en", isNsfw = false, className = "MangaDash1001Com"),
SingleLang("Manga-fast.com", "https://manga-fast.com", "en", className = "Mangafastcom", overrideVersionCode = 3),
SingleLang("Manga-Online.co", "https://www.manga-online.co", "th", className = "MangaOnlineCo"),
SingleLang("Manga-Raw.info (unoriginal)", "https://manga-raw.info", "en", isNsfw = true, className = "MangaRawInfo"),
SingleLang("Manga-Scantrad", "https://manga-scantrad.io", "fr", className = "MangaScantrad", overrideVersionCode = 3),
SingleLang("Manga-TX", "https://manga-tx.com", "en", className = "Mangatxunoriginal"),
@ -244,7 +240,6 @@ class MadaraGenerator : ThemeSourceGenerator {
SingleLang("Manga1st.online", "https://manga1st.online", "en", className = "MangaFirstOnline", overrideVersionCode = 1),
SingleLang("Manga347", "https://manga347.com", "en", overrideVersionCode = 3),
SingleLang("Manga3S", "https://manga3s.com", "en", overrideVersionCode = 4),
SingleLang("Manga4All", "https://manga4all.net", "en", overrideVersionCode = 3),
SingleLang("Manga68", "https://manga68.com", "en", overrideVersionCode = 1),
SingleLang("MangaBaz", "https://mangabaz.net", "en"),
SingleLang("MangaBob", "https://mangabob.com", "en", overrideVersionCode = 1),
@ -385,7 +380,6 @@ class MadaraGenerator : ThemeSourceGenerator {
SingleLang("Novels Town", "https://novelstown.cyou", "ar"),
SingleLang("Oh No Manga", "https://ohnomanga.com", "en", isNsfw = true),
SingleLang("OnlyManhwa", "https://onlymanhwa.org", "en", isNsfw = true),
SingleLang("Painful Nightz Scan", "https://painfulnightz.com", "en", overrideVersionCode = 1),
SingleLang("Pantheon Scan", "https://pantheon-scan.com", "fr", overrideVersionCode = 1),
SingleLang("Paragon Scans", "https://paragonscans.com", "en", isNsfw = true),
SingleLang("Passa Mão Scan", "https://passamaoscan.com", "pt-BR", isNsfw = true, className = "PassaMaoScan"),
@ -430,7 +424,6 @@ class MadaraGenerator : ThemeSourceGenerator {
SingleLang("Sawamics", "https://sawamics.com", "en"),
SingleLang("ScamberTraslator", "https://scambertraslator.com", "es", overrideVersionCode = 3),
SingleLang("Scan Hentai Menu", "https://scan.hentai.menu", "fr", isNsfw = true, overrideVersionCode = 1),
SingleLang("Scans Raw", "https://scansraw.com", "en", overrideVersionCode = 1),
SingleLang("Scantrad-VF", "https://scantrad-vf.co", "fr", className = "ScantradVF"),
SingleLang("Sdl scans", "https://sdlscans.com", "es", className = "SdlScans"),
SingleLang("Shadowtrad", "https://shadowtrad.net", "fr"),

View File

@ -1,2 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest />

View File

@ -1,12 +0,0 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
ext {
extName = 'Familiar by Soushiyo'
pkgNameSuffix = 'en.soushiyofamiliar'
extClass = '.SoushiyoFamiliar'
extVersionCode = 1
isNsfw = true
}
apply from: "$rootDir/common.gradle"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 228 KiB

View File

@ -1,135 +0,0 @@
package eu.kanade.tachiyomi.extension.en.soushiyofamiliar
import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.source.model.MangasPage
import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import okhttp3.Request
import okhttp3.Response
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import rx.Observable
import java.text.SimpleDateFormat
import java.util.Locale
class SoushiyoFamiliar : ParsedHttpSource() {
override val name = "Soushiyo: Familiar"
override val baseUrl = "https://familiar.soushiyo.com"
override val lang = "en"
override val supportsLatest = false
override fun fetchPopularManga(page: Int): Observable<MangasPage> {
val manga = SManga.create().apply {
title = "Familiar"
artist = "Soushiyo"
author = "Soushiyo"
status = SManga.ONGOING
url = "/familiar-chapter-list/"
description = "a witch. a cat. a contract.\n\nWhen career-driven editor Diana Vallejo accidentally summons a familiar whose specialty is soft domination, her life takes a turn for the better but for how long?\n\nFamiliar is a modern-day, slice-of-life romcomic about magick, work/life balance, BDSM, and relationships. It is kinky, queer, sex-positive, and free to read online. It is also erotic, sexually explicit, and written for adult audiences only."
thumbnail_url = "https://i.redd.it/wbe6ewkjtz291.jpg"
}
return Observable.just(MangasPage(arrayListOf(manga), false))
}
override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> = Observable.just(MangasPage(emptyList(), false))
override fun fetchMangaDetails(manga: SManga): Observable<SManga> = Observable.just(manga)
override fun chapterListParse(response: Response): List<SChapter> {
val chapterList = super.chapterListParse(response).distinct()
val chapterListNew = mutableListOf<SChapter>()
for (i in chapterList.indices) {
/* Some chapters are already listed on the site but are not yet out (have no link) --> Skip them */
if (chapterList[i].url.isNotEmpty()) {
/* Add chapter to front of new list --> Reverse order so that newest chapter is first */
chapterListNew.add(0, chapterList[i])
}
}
return chapterListNew
}
override fun chapterListSelector() = "tbody > tr[class^='row-']"
override fun chapterFromElement(element: Element): SChapter {
val textAct = element.select(".column-1").text()
val textChapNum = element.select(".column-2").text()
val textChapName = element.select(".column-3").text()
var textDate = ""
/* The date is in column 6 after a globe symbol --> Find/select the symbol */
val dateSymbolElements = element.select(".column-6 > .fa-globe")
/* Unreleased entries don't have a symbol and date */
if (dateSymbolElements.size != 0) {
/* Get the text after the symbol (if there are more occurrences then take the last, so the latest date is used in the app) */
textDate = dateSymbolElements.last()!!.nextSibling().toString()
/* Filter out any characters that do not belong to the valid date format "M/d/yy" */
textDate = textDate.replace("[^0-9/]".toRegex(), "")
}
val chapter = SChapter.create()
chapter.url = element.select(".column-3 > a").attr("href").substringAfter(baseUrl) // This is empty if there is no link (e.g. for unreleased chapters) --> This is then handled in chapterListParse
chapter.name = "Act $textAct - Chapter $textChapNum: $textChapName"
chapter.date_upload = parseDate(textDate)
return chapter
}
override fun pageListParse(document: Document): List<Page> {
val pages = mutableListOf<Page>()
val elements = document.select(".esg-entry-media > img")
for (i in 0 until elements.size) {
pages.add(Page(pages.size, "", elements[i].attr("abs:src")))
}
return pages
}
override fun imageUrlParse(document: Document) = throw UnsupportedOperationException("Not used.")
override fun popularMangaSelector(): String = throw UnsupportedOperationException("Not used.")
override fun searchMangaFromElement(element: Element): SManga = throw UnsupportedOperationException("Not used.")
override fun searchMangaNextPageSelector(): String = throw UnsupportedOperationException("Not used.")
override fun searchMangaSelector(): String = throw UnsupportedOperationException("Not used.")
override fun popularMangaRequest(page: Int): Request = throw UnsupportedOperationException("Not used.")
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request = throw UnsupportedOperationException("Not used.")
override fun popularMangaNextPageSelector(): String = throw UnsupportedOperationException("Not used.")
override fun popularMangaFromElement(element: Element): SManga = throw UnsupportedOperationException("Not used.")
override fun mangaDetailsParse(document: Document): SManga = throw UnsupportedOperationException("Not used.")
override fun latestUpdatesNextPageSelector(): String? = throw UnsupportedOperationException("Not used.")
override fun latestUpdatesFromElement(element: Element): SManga = throw UnsupportedOperationException("Not used.")
override fun latestUpdatesRequest(page: Int): Request = throw UnsupportedOperationException("Not used.")
override fun latestUpdatesSelector(): String = throw UnsupportedOperationException("Not used.")
private fun parseDate(dateStr: String): Long {
return runCatching { DATE_FORMATTER.parse(dateStr)?.time }
.getOrNull() ?: 0L
}
companion object {
private val DATE_FORMATTER by lazy {
SimpleDateFormat("M/d/yy", Locale.ENGLISH)
}
}
}

View File

@ -1,2 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest />

View File

@ -1,13 +0,0 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlinx-serialization'
ext {
extName = 'MangaTigre'
pkgNameSuffix = 'es.mangatigre'
extClass = '.MangaTigre'
extVersionCode = 3
isNsfw = true
}
apply from: "$rootDir/common.gradle"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 122 KiB

View File

@ -1,389 +0,0 @@
package eu.kanade.tachiyomi.extension.es.mangatigre
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.POST
import eu.kanade.tachiyomi.network.interceptor.rateLimitHost
import eu.kanade.tachiyomi.source.model.Filter
import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.source.model.MangasPage
import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.HttpSource
import eu.kanade.tachiyomi.util.asJsoup
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.JsonPrimitive
import kotlinx.serialization.json.jsonObject
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.Response
import okio.Buffer
import org.jsoup.nodes.Element
import uy.kohesive.injekt.injectLazy
import java.util.Calendar
class MangaTigre : HttpSource() {
override val name = "MangaTigre"
override val baseUrl = "https://www.mangatigre.net"
override val lang = "es"
override val supportsLatest = true
private val json: Json by injectLazy()
private val imgCDNUrl = "https://i2.mtcdn.xyz"
private var mtToken = ""
override val client: OkHttpClient = network.client.newBuilder()
.addInterceptor { chain ->
val request = chain.request()
if (request.method == "POST") {
val response = chain.proceed(request)
if (response.code == 419) {
response.close()
setToken()
val newBody = json.parseToJsonElement(request.bodyString).jsonObject.toMutableMap().apply {
this["_token"] = JsonPrimitive(mtToken)
}
val payload = Json.encodeToString(JsonObject(newBody)).toRequestBody(JSON_MEDIA_TYPE)
val apiHeaders = headersBuilder()
.add("Accept", ACCEPT_JSON)
.add("Content-Type", payload.contentType().toString())
.build()
val newRequest = request.newBuilder()
.headers(apiHeaders)
.method(request.method, payload)
.build()
return@addInterceptor chain.proceed(newRequest)
}
return@addInterceptor response
}
chain.proceed(request)
}
.rateLimitHost(baseUrl.toHttpUrl(), 1, 2)
.build()
private fun setToken() {
val document = client.newCall(GET(baseUrl, headers)).execute().asJsoup()
mtToken = document.selectFirst("input.input-search[data-csrf]")!!.attr("data-csrf")
}
override fun popularMangaRequest(page: Int): Request {
val payloadObj = PayloadManga(
page = page,
token = mtToken,
)
val payload = json.encodeToString(payloadObj).toRequestBody(JSON_MEDIA_TYPE)
val apiHeaders = headersBuilder()
.add("Accept", ACCEPT_JSON)
.add("Content-Type", payload.contentType().toString())
.build()
return POST("$baseUrl/mangas?sort=views", apiHeaders, payload)
}
override fun popularMangaParse(response: Response): MangasPage {
val jsonString = response.body.string()
val result = json.decodeFromString<MangasDto>(jsonString)
val mangas = result.mangas.map {
SManga.create().apply {
setUrlWithoutDomain("$baseUrl/manga/${it.slug}")
title = it.title
thumbnail_url = "$imgCDNUrl/mangas/${it.thumbnailFileName}"
}
}
val hasNextPage = result.totalPages > result.page
return MangasPage(mangas, hasNextPage)
}
override fun latestUpdatesRequest(page: Int): Request {
val payloadObj = PayloadManga(
page = page,
token = mtToken,
)
val payload = json.encodeToString(payloadObj).toRequestBody(JSON_MEDIA_TYPE)
val apiHeaders = headersBuilder()
.add("Accept", ACCEPT_JSON)
.add("Content-Type", payload.contentType().toString())
.build()
return POST("$baseUrl/mangas?sort=date", apiHeaders, payload)
}
override fun latestUpdatesParse(response: Response) = popularMangaParse(response)
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
if (query.isNotEmpty()) {
if (query.length < 2) throw Exception("La cadena de búsqueda debe tener por lo menos 2 caracteres")
val payloadObj = PayloadSearch(
query = query,
token = mtToken,
)
val payload = json.encodeToString(payloadObj).toRequestBody(JSON_MEDIA_TYPE)
val apiHeaders = headersBuilder()
.add("Accept", ACCEPT_JSON)
.add("Content-Type", payload.contentType().toString())
.build()
return POST("$baseUrl/mangas/search#$query", apiHeaders, payload)
}
val url = "$baseUrl/mangas".toHttpUrlOrNull()!!.newBuilder()
filters.forEach { filter ->
when (filter) {
is OrderFilter -> {
url.addQueryParameter("sort", filter.toUriPart())
}
is TypeFilter -> {
filter.state.forEach { content ->
if (content.state) url.addQueryParameter("type[]", content.id)
}
}
is StatusFilter -> {
filter.state.forEach { content ->
if (content.state) url.addQueryParameter("status[]", content.id)
}
}
is DemographicFilter -> {
filter.state.forEach { content ->
if (content.state) url.addQueryParameter("demographic[]", content.id)
}
}
is ContentFilter -> {
filter.state.forEach { content ->
if (content.state) url.addQueryParameter("content[]", content.id)
}
}
is FormatFilter -> {
filter.state.forEach { content ->
if (content.state) url.addQueryParameter("format[]", content.id)
}
}
is GenreFilter -> {
filter.state.forEach { content ->
if (content.state) url.addQueryParameter("genre[]", content.id)
}
}
is ThemeFilter -> {
filter.state.forEach { content ->
if (content.state) url.addQueryParameter("theme[]", content.id)
}
}
else -> {}
}
}
val payloadObj = PayloadManga(
page = page,
token = mtToken,
)
val payload = json.encodeToString(payloadObj).toRequestBody(JSON_MEDIA_TYPE)
val apiHeaders = headersBuilder()
.add("Accept", ACCEPT_JSON)
.add("Content-Type", payload.contentType().toString())
.build()
return POST(url.build().toString(), apiHeaders, payload)
}
override fun searchMangaParse(response: Response): MangasPage {
val query = response.request.url.fragment
val jsonString = response.body.string()
if (!query.isNullOrEmpty()) {
val result = json.decodeFromString<SearchDto>(jsonString)
val mangas = result.result.map {
SManga.create().apply {
setUrlWithoutDomain("$baseUrl/manga/${it.slug}")
title = it.title
thumbnail_url = "$imgCDNUrl/mangas/${it.thumbnailFileName}"
}
}
return MangasPage(mangas, false)
}
val result = json.decodeFromString<MangasDto>(jsonString)
val mangas = result.mangas.map {
SManga.create().apply {
setUrlWithoutDomain("$baseUrl/manga/${it.slug}")
title = it.title
thumbnail_url = "$imgCDNUrl/mangas/${it.thumbnailFileName}"
}
}
val hasNextPage = result.totalPages > result.page
return MangasPage(mangas, hasNextPage)
}
override fun mangaDetailsParse(response: Response): SManga {
val document = response.asJsoup()
return SManga.create().apply {
document.selectFirst("div.mangas-content")!!.let { mangasContent ->
thumbnail_url = mangasContent.selectFirst("div.manga-image > img")!!.attr("abs:data-src")
val summary = mangasContent.selectFirst("div.synopsis > p")?.ownText()?.trim() ?: ""
with(mangasContent.selectFirst("ul.list-group")!!) {
description = createDescription(this, summary)
genre = createGenres(this)
author = selectFirst("li:has(strong:contains(Autor)) > a")?.ownText()?.trim()
artist = selectFirst("li:has(strong:contains(Artista)) > a")?.ownText()?.trim()
status = selectFirst("li:has(strong:contains(Estado))")?.ownText()?.trim()!!.toStatus()
}
}
}
}
private fun createGenres(element: Element): String {
val demographic = element.select("li:has(strong:contains(Demografía)) a").joinToString { it.text() }
val genres = element.select("li:has(strong:contains(Géneros)) a").joinToString { it.text() }
val themes = element.select("li:has(strong:contains(Temas)) a").joinToString { it.text() }
val content = element.select("li:has(strong:contains(Contenido)) a").joinToString { it.text() }
return listOf(demographic, genres, themes, content).joinToString(", ")
}
private fun createDescription(element: Element, summary: String): String {
val originalName = element.selectFirst("li:has(strong:contains(Original))")?.ownText()?.trim() ?: ""
val alternativeName = element.select("li:has(strong:contains(Alternativo)) span.alter-name").text()
val year = element.selectFirst("li:has(strong:contains(Año))")?.ownText()?.trim() ?: ""
val animeAdaptation = element.selectFirst("li:has(strong:contains(Anime))")?.ownText()?.trim() ?: ""
val country = element.selectFirst("li:has(strong:contains(País))")?.ownText()?.trim() ?: ""
return StringBuilder()
.appendLine("Nombre Original: $originalName")
.appendLine("Títulos Alternativos: $alternativeName")
.appendLine("Año: $year")
.appendLine("Adaptación al Anime: $animeAdaptation")
.appendLine("País: $country")
.appendLine()
.appendLine("Sinopsis: $summary")
.toString()
}
override fun chapterListRequest(manga: SManga): Request {
val payloadObj = PayloadChapter(
token = mtToken,
)
val payload = json.encodeToString(payloadObj).toRequestBody(JSON_MEDIA_TYPE)
val apiHeaders = headersBuilder()
.add("Accept", ACCEPT_JSON)
.add("Content-Type", payload.contentType().toString())
.build()
return POST("$baseUrl${manga.url}", apiHeaders, payload)
}
override fun chapterListParse(response: Response): List<SChapter> {
return response.asJsoup().select("li").map {
SChapter.create().apply {
setUrlWithoutDomain(it.select("a").attr("href"))
name = it.selectFirst("a")!!.ownText().trim()
date_upload = parseRelativeDate(it.selectFirst("span")!!.ownText().trim())
}
}
}
override fun pageListParse(response: Response): List<Page> {
val document = response.asJsoup()
val script = document.selectFirst("script:containsData(window.chapter)")!!.data()
val jsonString = CHAPTERS_REGEX.find(script)!!.groupValues[1]
val result = json.decodeFromString<ChapterDto>(jsonString)
val slug = result.manga.slug
val number = result.number.toString()
return result.images.map {
val imageUrl = "$imgCDNUrl/chapters/$slug/$number/${it.value.name}.${it.value.format}"
Page(it.key.toInt(), "", imageUrl)
}.sortedBy { it.index }
}
override fun getFilterList() = FilterList(
Filter.Header("Los filtros serán ignorados si se realiza una búsqueda textual"),
Filter.Separator(),
OrderFilter(),
Filter.Separator(),
TypeFilter(getFilterTypeList()),
Filter.Separator(),
StatusFilter(getFilterStatusList()),
Filter.Separator(),
DemographicFilter(getFilterDemographicList()),
Filter.Separator(),
ContentFilter(getFilterContentList()),
Filter.Separator(),
FormatFilter(getFilterFormatList()),
Filter.Separator(),
GenreFilter(getFilterGenreList()),
Filter.Separator(),
ThemeFilter(getFilterThemeList()),
)
override fun imageUrlParse(response: Response) = throw UnsupportedOperationException("Not used.")
private fun parseRelativeDate(date: String): Long {
val number = Regex("""(\d+)""").find(date)?.value?.toIntOrNull() ?: return 0
val cal = Calendar.getInstance()
return when {
WordSet("segundo").anyWordIn(date) -> cal.apply { add(Calendar.SECOND, -number) }.timeInMillis
WordSet("minuto").anyWordIn(date) -> cal.apply { add(Calendar.MINUTE, -number) }.timeInMillis
WordSet("hora").anyWordIn(date) -> cal.apply { add(Calendar.HOUR, -number) }.timeInMillis
WordSet("día").anyWordIn(date) -> cal.apply { add(Calendar.DAY_OF_MONTH, -number) }.timeInMillis
WordSet("semana").anyWordIn(date) -> cal.apply { add(Calendar.DAY_OF_MONTH, -number * 7) }.timeInMillis
WordSet("mes").anyWordIn(date) -> cal.apply { add(Calendar.MONTH, -number) }.timeInMillis
WordSet("año").anyWordIn(date) -> cal.apply { add(Calendar.YEAR, -number) }.timeInMillis
else -> 0
}
}
class WordSet(private vararg val words: String) {
fun anyWordIn(dateString: String): Boolean = words.any { dateString.contains(it, ignoreCase = true) }
}
private val Request.bodyString: String
get() {
val requestCopy = newBuilder().build()
val buffer = Buffer()
return runCatching { buffer.apply { requestCopy.body!!.writeTo(this) }.readUtf8() }
.getOrNull() ?: ""
}
companion object {
private const val ACCEPT_JSON = "application/json, text/plain, */*"
private val JSON_MEDIA_TYPE = "application/json".toMediaType()
private val CHAPTERS_REGEX = """window\.chapter\s*=\s*'(.+?)';""".toRegex()
}
}

View File

@ -1,76 +0,0 @@
package eu.kanade.tachiyomi.extension.es.mangatigre
import eu.kanade.tachiyomi.source.model.SManga
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonPrimitive
@Serializable
data class PayloadManga(
val page: Int,
@SerialName("_token") val token: String,
)
@Serializable
data class PayloadChapter(
@SerialName("_token") val token: String,
)
@Serializable
data class PayloadSearch(
val query: String,
@SerialName("_token") val token: String,
)
@Serializable
data class MangasDto(
@SerialName("current_page") val page: Int,
@SerialName("last_page") val totalPages: Int,
@SerialName("data") val mangas: List<MangasDataDto>,
)
@Serializable
data class MangasDataDto(
@SerialName("name") val title: String,
val slug: String,
@SerialName("image") val thumbnailFileName: String,
)
@Serializable
data class ChapterDto(
val manga: ChapterMangaInfoDto,
val number: JsonPrimitive, // Can be Int or Float
val images: Map<String, ChapterImagesDto>,
)
@Serializable
data class ChapterMangaInfoDto(
val slug: String,
)
@Serializable
data class ChapterImagesDto(
val name: String,
val format: String,
)
@Serializable
data class SearchDto(
val result: List<SearchDataDto>,
)
@Serializable
data class SearchDataDto(
val id: Int,
@SerialName("name") val title: String,
val slug: String,
@SerialName("image")val thumbnailFileName: String,
)
fun String.toStatus(): Int = when (this) {
"En Marcha" -> SManga.ONGOING
"Terminado" -> SManga.COMPLETED
"Detenido" -> SManga.ON_HIATUS
"Pausado" -> SManga.ON_HIATUS
else -> SManga.UNKNOWN
}

View File

@ -1,148 +0,0 @@
package eu.kanade.tachiyomi.extension.es.mangatigre
import eu.kanade.tachiyomi.source.model.Filter
class Type(name: String, val id: String) : Filter.CheckBox(name)
class TypeFilter(values: List<Type>) : Filter.Group<Type>("Tipos", values)
class Status(name: String, val id: String) : Filter.CheckBox(name)
class StatusFilter(values: List<Status>) : Filter.Group<Status>("Estado", values)
class Demographic(name: String, val id: String) : Filter.CheckBox(name)
class DemographicFilter(values: List<Demographic>) : Filter.Group<Demographic>("Demografía", values)
class Content(name: String, val id: String) : Filter.CheckBox(name)
class ContentFilter(values: List<Content>) : Filter.Group<Content>("Contenido", values)
class Format(name: String, val id: String) : Filter.CheckBox(name)
class FormatFilter(values: List<Format>) : Filter.Group<Format>("Formato", values)
class Genre(name: String, val id: String) : Filter.CheckBox(name)
class GenreFilter(values: List<Genre>) : Filter.Group<Genre>("Géneros", values)
class Theme(name: String, val id: String) : Filter.CheckBox(name)
class ThemeFilter(values: List<Theme>) : Filter.Group<Theme>("Temas", values)
open class UriPartFilter(displayName: String, val vals: Array<Pair<String, String>>) :
Filter.Select<String>(displayName, vals.map { it.first }.toTypedArray()) {
fun toUriPart() = vals[state].second
}
class OrderFilter() : UriPartFilter(
"Ordenar por",
arrayOf(
Pair("Alfabético", "name"),
Pair("Vistas", "views"),
Pair("Fecha Estreno", "date"),
),
)
fun getFilterTypeList() = listOf(
Type("Manga", "1"),
Type("Manhwa", "2"),
Type("Manhua", "3"),
)
fun getFilterStatusList() = listOf(
Status("En Marcha", "1"),
Status("Terminado", "2"),
Status("Detenido", "3"),
Status("Pausado", "4"),
)
fun getFilterDemographicList() = listOf(
Demographic("Shonen", "1"),
Demographic("Seinen", "2"),
Demographic("Shojo", "3"),
Demographic("Josei", "4"),
)
fun getFilterContentList() = listOf(
Content("Ecchi", "1"),
Content("Gore", "2"),
Content("Smut", "3"),
Content("Violencia Sexual", "4"),
)
fun getFilterFormatList() = listOf(
Format("Adaptación", "14"),
Format("Antalogía", "9"),
Format("Color Completo", "18"),
Format("Coloreado Oficial", "19"),
Format("Coloreado Por Fan", "15"),
Format("Creado Por Usuario", "20"),
Format("Delincuencia", "16"),
Format("Doujinshi", "10"),
Format("Galardonado", "13"),
Format("One Shot", "11"),
Format("Tira Larga", "17"),
Format("Webcomic", "12"),
Format("YonKoma", "8"),
)
fun getFilterGenreList() = listOf(
Genre("Acción", "49"),
Genre("Aventura", "50"),
Genre("Boys Love", "75"),
Genre("Chicas Mágicas", "73"),
Genre("Ciencia-Ficción", "64"),
Genre("Comedia", "51"),
Genre("Crimen", "52"),
Genre("Deporte", "65"),
Genre("Drama", "53"),
Genre("Fantasía", "54"),
Genre("Filosófico", "61"),
Genre("Girls Love", "76"),
Genre("Guerra", "74"),
Genre("Histórico", "55"),
Genre("Horror", "56"),
Genre("Isekai", "57"),
Genre("Mecha", "58"),
Genre("Médica", "59"),
Genre("Misterio", "60"),
Genre("Psicológico", "62"),
Genre("Recuentos De La Vida", "72"),
Genre("Romance", "63"),
Genre("Superhéroe", "66"),
Genre("Thriller", "67"),
Genre("Tragedia", "68"),
Genre("Wuxia", "69"),
Genre("Yaoi", "70"),
Genre("Yuri", "71"),
)
fun getFilterThemeList() = listOf(
Theme("Animales", "52"),
Theme("Apocalíptico", "50"),
Theme("Artes Marciales", "60"),
Theme("Chicas Monstruo", "77"),
Theme("Cocinando", "53"),
Theme("Crossdressing", "79"),
Theme("Delincuencia", "78"),
Theme("Demonios", "54"),
Theme("Extranjeros", "51"),
Theme("Fantasma", "55"),
Theme("Género Bender", "81"),
Theme("Gyaru", "56"),
Theme("Harén", "57"),
Theme("Incesto", "58"),
Theme("Lolicon", "59"),
Theme("Mafia", "64"),
Theme("Magia", "65"),
Theme("Militar", "61"),
Theme("Monstruos", "62"),
Theme("Música", "63"),
Theme("Ninja", "66"),
Theme("Policía", "67"),
Theme("Realidad Virtual", "74"),
Theme("Reencarnación", "68"),
Theme("Samurái", "73"),
Theme("Shotacon", "71"),
Theme("Sobrenatural", "69"),
Theme("Superpoderes", "82"),
Theme("Supervivencia", "72"),
Theme("Vampiros", "75"),
Theme("Vida Escolar", "70"),
Theme("Videojuegos", "80"),
Theme("Zombis", "76"),
)

View File

@ -1,22 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
<activity
android:name="eu.kanade.tachiyomi.extension.vi.qmanga.QMangaUrlActivity"
android:excludeFromRecents="true"
android:exported="true"
android:theme="@android:style/Theme.NoDisplay">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:host="qmanga5.net" />
<data
android:pathPattern="/..*"
android:scheme="https" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@ -1,12 +0,0 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
ext {
extName = 'QManga'
pkgNameSuffix = 'vi.qmanga'
extClass = '.QManga'
extVersionCode = 1
isNsfw = true
}
apply from: "$rootDir/common.gradle"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

View File

@ -1,33 +0,0 @@
package eu.kanade.tachiyomi.extension.vi.qmanga
import android.app.Activity
import android.content.ActivityNotFoundException
import android.content.Intent
import android.os.Bundle
import android.util.Log
import kotlin.system.exitProcess
class QMangaUrlActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val pathSegments = intent?.data?.pathSegments
if (pathSegments != null && pathSegments.size > 0 && pathSegments[0].endsWith(".html")) {
val id = pathSegments[0].removeSuffix(".html")
try {
startActivity(
Intent().apply {
action = "eu.kanade.tachiyomi.SEARCH"
putExtra("query", "${QManga.PREFIX_ID_SEARCH}$id")
putExtra("filter", packageName)
},
)
} catch (e: ActivityNotFoundException) {
Log.e("QMangaUrlActivity", e.toString())
}
} else {
Log.e("QMangaUrlActivity", "Could not parse URI from intent $intent")
}
finish()
exitProcess(0)
}
}