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
Before Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 5.4 KiB |
Before Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 78 KiB |
|
@ -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")))
|
|
Before Width: | Height: | Size: 9.3 KiB |
Before Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 49 KiB |
Before Width: | Height: | Size: 317 KiB |
|
@ -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")),
|
|
||||||
)
|
|
Before Width: | Height: | Size: 5.0 KiB |
Before Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 6.8 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 85 KiB |
Before Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 7.9 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 64 KiB |
|
@ -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),
|
|
||||||
)
|
|
Before Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 4.0 KiB |
Before Width: | Height: | Size: 7.8 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 75 KiB |
|
@ -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()
|
|
||||||
}
|
|
Before Width: | Height: | Size: 8.1 KiB |
Before Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 40 KiB |
Before Width: | Height: | Size: 257 KiB |
Before Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 101 KiB |
|
@ -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
|
|
||||||
}
|
|
|
@ -77,7 +77,6 @@ class MadaraGenerator : ThemeSourceGenerator {
|
||||||
SingleLang("ComicKiba", "https://comickiba.com", "en", overrideVersionCode = 1),
|
SingleLang("ComicKiba", "https://comickiba.com", "en", overrideVersionCode = 1),
|
||||||
SingleLang("Comics Valley", "https://comicsvalley.com", "hi", isNsfw = true, overrideVersionCode = 1),
|
SingleLang("Comics Valley", "https://comicsvalley.com", "hi", isNsfw = true, overrideVersionCode = 1),
|
||||||
SingleLang("ComicsWorld", "https://comicsworld.in", "hi"),
|
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("Comicz.net v2", "https://v2.comiz.net", "all", isNsfw = true, className = "ComiczNetV2"),
|
||||||
SingleLang("Cookie Kiara", "https://18.kiara.cool", "en", isNsfw = true),
|
SingleLang("Cookie Kiara", "https://18.kiara.cool", "en", isNsfw = true),
|
||||||
SingleLang("CopyPasteScan", "https://copypastescan.xyz", "es", overrideVersionCode = 1),
|
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("Eromiau", "https://www.eromiau.com", "es", isNsfw = true),
|
||||||
SingleLang("Esomanga", "https://esomanga.com", "tr", overrideVersionCode = 1),
|
SingleLang("Esomanga", "https://esomanga.com", "tr", overrideVersionCode = 1),
|
||||||
SingleLang("FactManga", "https://factmanga.com", "en", isNsfw = false),
|
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("Fay Scans", "https://fayscans.com.br", "pt-BR", overrideVersionCode = 1),
|
||||||
SingleLang("Final Scans", "https://finalscans.com", "pt-BR", isNsfw = true, overrideVersionCode = 1),
|
SingleLang("Final Scans", "https://finalscans.com", "pt-BR", isNsfw = true, overrideVersionCode = 1),
|
||||||
SingleLang("Fire Scans", "https://firescans.xyz", "en", 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 Hentai", "https://h.mangareaderpro.com", "es", isNsfw = true),
|
||||||
SingleLang("Hades no Fansub", "https://mangareaderpro.com", "es", overrideVersionCode = 1),
|
SingleLang("Hades no Fansub", "https://mangareaderpro.com", "es", overrideVersionCode = 1),
|
||||||
SingleLang("Harimanga", "https://harimanga.com", "en", overrideVersionCode = 3),
|
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("Hattori Manga", "https://hattorimanga.com", "tr", isNsfw = true),
|
||||||
SingleLang("Hayalistic", "https://hayalistic.com", "tr"),
|
SingleLang("Hayalistic", "https://hayalistic.com", "tr"),
|
||||||
SingleLang("Hentai CB", "https://hentaicube.net", "vi", isNsfw = true, overrideVersionCode = 6, pkgName = "hentaicube"),
|
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 Weebs", "https://mangaweebs.in", "en", overrideVersionCode = 8),
|
||||||
SingleLang("Manga-1001.com", "https://manga-1001.com", "en", isNsfw = false, className = "MangaDash1001Com"),
|
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-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-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-Scantrad", "https://manga-scantrad.io", "fr", className = "MangaScantrad", overrideVersionCode = 3),
|
||||||
SingleLang("Manga-TX", "https://manga-tx.com", "en", className = "Mangatxunoriginal"),
|
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("Manga1st.online", "https://manga1st.online", "en", className = "MangaFirstOnline", overrideVersionCode = 1),
|
||||||
SingleLang("Manga347", "https://manga347.com", "en", overrideVersionCode = 3),
|
SingleLang("Manga347", "https://manga347.com", "en", overrideVersionCode = 3),
|
||||||
SingleLang("Manga3S", "https://manga3s.com", "en", overrideVersionCode = 4),
|
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("Manga68", "https://manga68.com", "en", overrideVersionCode = 1),
|
||||||
SingleLang("MangaBaz", "https://mangabaz.net", "en"),
|
SingleLang("MangaBaz", "https://mangabaz.net", "en"),
|
||||||
SingleLang("MangaBob", "https://mangabob.com", "en", overrideVersionCode = 1),
|
SingleLang("MangaBob", "https://mangabob.com", "en", overrideVersionCode = 1),
|
||||||
|
@ -385,7 +380,6 @@ class MadaraGenerator : ThemeSourceGenerator {
|
||||||
SingleLang("Novels Town", "https://novelstown.cyou", "ar"),
|
SingleLang("Novels Town", "https://novelstown.cyou", "ar"),
|
||||||
SingleLang("Oh No Manga", "https://ohnomanga.com", "en", isNsfw = true),
|
SingleLang("Oh No Manga", "https://ohnomanga.com", "en", isNsfw = true),
|
||||||
SingleLang("OnlyManhwa", "https://onlymanhwa.org", "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("Pantheon Scan", "https://pantheon-scan.com", "fr", overrideVersionCode = 1),
|
||||||
SingleLang("Paragon Scans", "https://paragonscans.com", "en", isNsfw = true),
|
SingleLang("Paragon Scans", "https://paragonscans.com", "en", isNsfw = true),
|
||||||
SingleLang("Passa Mão Scan", "https://passamaoscan.com", "pt-BR", isNsfw = true, className = "PassaMaoScan"),
|
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("Sawamics", "https://sawamics.com", "en"),
|
||||||
SingleLang("ScamberTraslator", "https://scambertraslator.com", "es", overrideVersionCode = 3),
|
SingleLang("ScamberTraslator", "https://scambertraslator.com", "es", overrideVersionCode = 3),
|
||||||
SingleLang("Scan Hentai Menu", "https://scan.hentai.menu", "fr", isNsfw = true, overrideVersionCode = 1),
|
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("Scantrad-VF", "https://scantrad-vf.co", "fr", className = "ScantradVF"),
|
||||||
SingleLang("Sdl scans", "https://sdlscans.com", "es", className = "SdlScans"),
|
SingleLang("Sdl scans", "https://sdlscans.com", "es", className = "SdlScans"),
|
||||||
SingleLang("Shadowtrad", "https://shadowtrad.net", "fr"),
|
SingleLang("Shadowtrad", "https://shadowtrad.net", "fr"),
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<manifest />
|
|
|
@ -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"
|
|
Before Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 47 KiB |
Before Width: | Height: | Size: 228 KiB |
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,2 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<manifest />
|
|
|
@ -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"
|
|
Before Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 7.6 KiB |
Before Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 122 KiB |
|
@ -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()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
}
|
|
|
@ -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"),
|
|
||||||
)
|
|
|
@ -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>
|
|
|
@ -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"
|
|
Before Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 7.6 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 59 KiB |
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|