Remove dead sources
Closes #16016 Closes #16110 Closes #16194 Closes #16314 Closes #16515 Closes #16517 Closes #16519 Closes #16520
| Before Width: | Height: | Size: 3.5 KiB | 
| Before Width: | Height: | Size: 2.1 KiB | 
| Before Width: | Height: | Size: 4.8 KiB | 
| Before Width: | Height: | Size: 8.1 KiB | 
| Before Width: | Height: | Size: 12 KiB | 
| Before Width: | Height: | Size: 44 KiB | 
| @ -1,5 +0,0 @@ | ||||
| package eu.kanade.tachiyomi.extension.es.kirishimafansub | ||||
| 
 | ||||
| import eu.kanade.tachiyomi.multisrc.foolslide.FoolSlide | ||||
| 
 | ||||
| class KirishimaFansub : FoolSlide("Kirishima Fansub", "https://www.kirishimafansub.net", "es", "/lector") | ||||
| Before Width: | Height: | Size: 2.5 KiB | 
| Before Width: | Height: | Size: 1.5 KiB | 
| Before Width: | Height: | Size: 3.4 KiB | 
| Before Width: | Height: | Size: 5.7 KiB | 
| Before Width: | Height: | Size: 9.0 KiB | 
| Before Width: | Height: | Size: 40 KiB | 
| @ -1,9 +0,0 @@ | ||||
| package eu.kanade.tachiyomi.extension.en.fastmanhwa | ||||
| 
 | ||||
| import eu.kanade.tachiyomi.multisrc.madara.Madara | ||||
| import java.text.SimpleDateFormat | ||||
| import java.util.Locale | ||||
| 
 | ||||
| class FastManhwa : Madara("FastManhwa", "https://fastmanhwa.net", "en", dateFormat = SimpleDateFormat("MMMM d, yyyy", Locale.US)) { | ||||
|     override val useNewChapterEndpoint = true | ||||
| } | ||||
| Before Width: | Height: | Size: 4.6 KiB | 
| Before Width: | Height: | Size: 2.5 KiB | 
| Before Width: | Height: | Size: 5.3 KiB | 
| Before Width: | Height: | Size: 10 KiB | 
| Before Width: | Height: | Size: 11 KiB | 
| Before Width: | Height: | Size: 53 KiB | 
| @ -1,23 +0,0 @@ | ||||
| package eu.kanade.tachiyomi.extension.es.fusionscanlation | ||||
| 
 | ||||
| import eu.kanade.tachiyomi.multisrc.madara.Madara | ||||
| import eu.kanade.tachiyomi.network.interceptor.rateLimit | ||||
| import okhttp3.OkHttpClient | ||||
| import java.text.SimpleDateFormat | ||||
| import java.util.Locale | ||||
| import java.util.concurrent.TimeUnit | ||||
| 
 | ||||
| class FusionScanlation : Madara("Fusion Scanlation", "https://fusionscanlation.com", "es", SimpleDateFormat("d 'de' MMMM 'de' yyyy", Locale("es"))) { | ||||
| 
 | ||||
|     override val versionId = 2 | ||||
| 
 | ||||
|     override val seriesTypeSelector = ".post-content_item:contains(Tipo) .summary-content" | ||||
|     override val altNameSelector = ".post-content_item:contains(Nombre Alternativo) .summary-content" | ||||
|     override val altName = "Nombre alternativo: " | ||||
| 
 | ||||
|     override val client: OkHttpClient = network.cloudflareClient.newBuilder() | ||||
|         .connectTimeout(10, TimeUnit.SECONDS) | ||||
|         .readTimeout(30, TimeUnit.SECONDS) | ||||
|         .rateLimit(1, 2) | ||||
|         .build() | ||||
| } | ||||
| Before Width: | Height: | Size: 4.3 KiB | 
| Before Width: | Height: | Size: 2.5 KiB | 
| Before Width: | Height: | Size: 5.4 KiB | 
| Before Width: | Height: | Size: 9.7 KiB | 
| Before Width: | Height: | Size: 14 KiB | 
| Before Width: | Height: | Size: 67 KiB | 
| @ -1,54 +0,0 @@ | ||||
| package eu.kanade.tachiyomi.extension.es.mangastk | ||||
| 
 | ||||
| import eu.kanade.tachiyomi.multisrc.madara.Madara | ||||
| import eu.kanade.tachiyomi.source.model.SChapter | ||||
| import eu.kanade.tachiyomi.source.model.SManga | ||||
| import org.jsoup.nodes.Element | ||||
| import java.text.SimpleDateFormat | ||||
| import java.util.Locale | ||||
| 
 | ||||
| class MangasTK : Madara( | ||||
|     "MangasTK", | ||||
|     "https://mangastk.net", | ||||
|     "es", | ||||
|     SimpleDateFormat("dd.MM.yyyy", Locale("es")), | ||||
| ) { | ||||
|     override fun popularMangaSelector() = "div#series-card:has(a:not([href*='bilibilicomics.com']))" | ||||
|     override val popularMangaUrlSelector = "a.series-link" | ||||
| 
 | ||||
|     override val mangaDetailsSelectorTag = "div.tags-content a.notUsed" // Source use this for the scanlator | ||||
|     override val mangaDetailsSelectorStatus = "div.post-status div.summary-content" | ||||
| 
 | ||||
|     override fun popularMangaFromElement(element: Element): SManga { | ||||
|         val manga = SManga.create() | ||||
| 
 | ||||
|         with(element) { | ||||
|             select(popularMangaUrlSelector).first()?.let { | ||||
|                 manga.setUrlWithoutDomain(it.attr("abs:href")) | ||||
|                 manga.title = it.attr("title") | ||||
|             } | ||||
| 
 | ||||
|             select("img").first()?.let { | ||||
|                 manga.thumbnail_url = imageFromElement(it) | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return manga | ||||
|     } | ||||
| 
 | ||||
|     override fun chapterFromElement(element: Element): SChapter { | ||||
|         val chapter = SChapter.create() | ||||
| 
 | ||||
|         with(element) { | ||||
|             select(chapterUrlSelector).first()?.let { urlElement -> | ||||
|                 chapter.url = urlElement.attr("abs:href").let { | ||||
|                     it.substringBefore("?style=paged") + if (!it.endsWith(chapterUrlSuffix)) chapterUrlSuffix else "" | ||||
|                 } | ||||
|                 chapter.name = urlElement.select("p.chapter-manhwa-title").text() | ||||
|                 chapter.date_upload = parseChapterDate(select("span.chapter-release-date").text()) | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return chapter | ||||
|     } | ||||
| } | ||||
| Before Width: | Height: | Size: 3.9 KiB | 
| Before Width: | Height: | Size: 2.3 KiB | 
| Before Width: | Height: | Size: 5.0 KiB | 
| Before Width: | Height: | Size: 8.9 KiB | 
| Before Width: | Height: | Size: 13 KiB | 
| Before Width: | Height: | Size: 60 KiB | 
| @ -1,54 +0,0 @@ | ||||
| package eu.kanade.tachiyomi.extension.es.mangastkxyz | ||||
| 
 | ||||
| import eu.kanade.tachiyomi.multisrc.madara.Madara | ||||
| import eu.kanade.tachiyomi.source.model.SChapter | ||||
| import eu.kanade.tachiyomi.source.model.SManga | ||||
| import org.jsoup.nodes.Element | ||||
| import java.text.SimpleDateFormat | ||||
| import java.util.Locale | ||||
| 
 | ||||
| class MangasTkXyz : Madara( | ||||
|     "MangasTK.xyz", | ||||
|     "https://mangastk.xyz", | ||||
|     "es", | ||||
|     SimpleDateFormat("dd.MM.yyyy", Locale("es")), | ||||
| ) { | ||||
|     override fun popularMangaSelector() = "div#series-card:has(a:not([href*='bilibilicomics.com']))" | ||||
|     override val popularMangaUrlSelector = "a.series-link" | ||||
| 
 | ||||
|     override val mangaDetailsSelectorTag = "div.tags-content a.notUsed" // Source use this for the scanlator | ||||
|     override val mangaDetailsSelectorStatus = "div.post-status div.summary-content" | ||||
| 
 | ||||
|     override fun popularMangaFromElement(element: Element): SManga { | ||||
|         val manga = SManga.create() | ||||
| 
 | ||||
|         with(element) { | ||||
|             select(popularMangaUrlSelector).first()?.let { | ||||
|                 manga.setUrlWithoutDomain(it.attr("abs:href")) | ||||
|                 manga.title = it.attr("title") | ||||
|             } | ||||
| 
 | ||||
|             select("img").first()?.let { | ||||
|                 manga.thumbnail_url = imageFromElement(it) | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return manga | ||||
|     } | ||||
| 
 | ||||
|     override fun chapterFromElement(element: Element): SChapter { | ||||
|         val chapter = SChapter.create() | ||||
| 
 | ||||
|         with(element) { | ||||
|             select(chapterUrlSelector).first()?.let { urlElement -> | ||||
|                 chapter.url = urlElement.attr("abs:href").let { | ||||
|                     it.substringBefore("?style=paged") + if (!it.endsWith(chapterUrlSuffix)) chapterUrlSuffix else "" | ||||
|                 } | ||||
|                 chapter.name = urlElement.select("p.chapter-manhwa-title").text() | ||||
|                 chapter.date_upload = parseChapterDate(select("span.chapter-release-date").text()) | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return chapter | ||||
|     } | ||||
| } | ||||
| Before Width: | Height: | Size: 5.7 KiB | 
| Before Width: | Height: | Size: 3.0 KiB | 
| Before Width: | Height: | Size: 8.3 KiB | 
| Before Width: | Height: | Size: 16 KiB | 
| Before Width: | Height: | Size: 22 KiB | 
| Before Width: | Height: | Size: 117 KiB | 
| @ -1,7 +0,0 @@ | ||||
| package eu.kanade.tachiyomi.extension.es.merakiscan | ||||
| 
 | ||||
| import eu.kanade.tachiyomi.multisrc.madara.Madara | ||||
| import java.text.SimpleDateFormat | ||||
| import java.util.Locale | ||||
| 
 | ||||
| class MerakiScan : Madara("Meraki Scan", "https://meraki801.com", "es", SimpleDateFormat("dd 'de' MMMMM 'de' yyyy", Locale("es"))) | ||||
| @ -19,7 +19,6 @@ class FoolSlideGenerator : ThemeSourceGenerator { | ||||
|         SingleLang("Baixar Hentai", "https://leitura.baixarhentai.net", "pt-BR", isNsfw = true, overrideVersionCode = 4), | ||||
|         SingleLang("Death Toll Scans", "https://reader.deathtollscans.net", "en"), | ||||
|         SingleLang("Evil Flowers", "https://reader.evilflowers.com", "en", overrideVersionCode = 1), | ||||
|         SingleLang("Kirishima Fansub", "https://www.kirishimafansub.net", "es"), | ||||
|         SingleLang("Le Cercle du Scan", "https://lel.lecercleduscan.com", "fr", className = "LeCercleDuScan", overrideVersionCode = 1), | ||||
|         SingleLang("Lilyreader", "https://manga.smuglo.li", "en"), | ||||
|         SingleLang("MangaScouts", "http://onlinereader.mangascouts.org", "de", overrideVersionCode = 1), | ||||
|  | ||||
| @ -96,7 +96,6 @@ class MadaraGenerator : ThemeSourceGenerator { | ||||
|         SingleLang("EvaScans", "https://evascans.com", "tr"), | ||||
|         SingleLang("FreeMangaTop", "https://freemangatop.com", "en", overrideVersionCode = 2), | ||||
|         SingleLang("FaeStorm", "https://faestormmanga.com", "tr"), | ||||
|         SingleLang("FastManhwa", "https://fastmanhwa.net", "en", isNsfw = true, overrideVersionCode = 2), | ||||
|         SingleLang("Fay Scans", "https://fayscans.com.br", "pt-BR", overrideVersionCode = 1), | ||||
|         SingleLang("FDM Scan", "https://fdmscan.com", "pt-BR", overrideVersionCode = 3), | ||||
|         SingleLang("Final Scans", "https://finalscans.com", "pt-BR", isNsfw = true, overrideVersionCode = 1), | ||||
| @ -110,7 +109,6 @@ class MadaraGenerator : ThemeSourceGenerator { | ||||
|         SingleLang("Fug Manga", "https://fugmanga.net", "ar", overrideVersionCode = 1), | ||||
|         SingleLang("Fukushuu no Yuusha", "https://fny-scantrad.com", "fr", overrideVersionCode = 2), | ||||
|         SingleLang("Furio Scans", "https://furioscans.com", "pt-BR", overrideVersionCode = 4), | ||||
|         SingleLang("Fusion Scanlation", "https://fusionscanlation.com", "es", className = "FusionScanlation", overrideVersionCode = 3), | ||||
|         SingleLang("GalaxyDegenScans", "https://gdscans.com", "en", overrideVersionCode = 4), | ||||
|         SingleLang("Gatemanga", "https://gatemanga.com", "ar", overrideVersionCode = 1), | ||||
|         SingleLang("GeassToon", "https://geasstoon.com", "tr"), | ||||
| @ -257,9 +255,7 @@ class MadaraGenerator : ThemeSourceGenerator { | ||||
|         SingleLang("MangaSiro", "https://mangasiro.com", "en", isNsfw = true), | ||||
|         SingleLang("MangaSpark", "https://mangaspark.com", "ar", overrideVersionCode = 2), | ||||
|         SingleLang("MangaStic", "https://mangastic9.com", "en", overrideVersionCode = 2), | ||||
|         SingleLang("MangasTK", "https://mangastk.net", "es", isNsfw = true, overrideVersionCode = 3), | ||||
|         SingleLang("MangasTK18", "https://mangastk18.com", "es", isNsfw = true), | ||||
|         SingleLang("MangasTK.xyz", "https://mangastk.xyz", "es", className = "MangasTkXyz"), | ||||
|         SingleLang("Mangasushi", "https://mangasushi.org", "en", overrideVersionCode = 3), | ||||
|         SingleLang("MangaTone", "https://mangatone.com", "en"), | ||||
|         SingleLang("MangaToRead", "https://mangatoread.com", "en"), | ||||
| @ -303,7 +299,6 @@ class MadaraGenerator : ThemeSourceGenerator { | ||||
|         SingleLang("ManyToon", "https://manytoon.com", "en", isNsfw = true, overrideVersionCode = 5), | ||||
|         SingleLang("ManyToon.me", "https://manytoon.me", "en", isNsfw = true, className = "ManyToonMe", overrideVersionCode = 4), | ||||
|         SingleLang("ManyToonClub", "https://manytoon.club", "ko", isNsfw = true, overrideVersionCode = 1), | ||||
|         SingleLang("Meraki Scan", "https://meraki801.com", "es", isNsfw = true), | ||||
|         SingleLang("MG Komik", "https://mgkomik.com", "id", overrideVersionCode = 4), | ||||
|         SingleLang("MHentais", "https://mhentais.com", "pt-BR", isNsfw = true, overrideVersionCode = 1), | ||||
|         SingleLang("Midnight Mess Scans", "https://midnightmess.org", "en", isNsfw = true, overrideVersionCode = 6), | ||||
|  | ||||
| @ -1,2 +0,0 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <manifest package="eu.kanade.tachiyomi.extension" /> | ||||
| @ -1,11 +0,0 @@ | ||||
| apply plugin: 'com.android.application' | ||||
| apply plugin: 'kotlin-android' | ||||
| 
 | ||||
| ext { | ||||
|     extName = 'Asgard Team' | ||||
|     pkgNameSuffix = 'ar.asgardteam' | ||||
|     extClass = '.AsgardTeam' | ||||
|     extVersionCode = 11 | ||||
| } | ||||
| 
 | ||||
| apply from: "$rootDir/common.gradle" | ||||
| Before Width: | Height: | Size: 3.9 KiB | 
| Before Width: | Height: | Size: 2.2 KiB | 
| Before Width: | Height: | Size: 5.8 KiB | 
| Before Width: | Height: | Size: 11 KiB | 
| Before Width: | Height: | Size: 17 KiB | 
| Before Width: | Height: | Size: 110 KiB | 
| @ -1,165 +0,0 @@ | ||||
| package eu.kanade.tachiyomi.extension.ar.asgardteam | ||||
| 
 | ||||
| import eu.kanade.tachiyomi.network.GET | ||||
| import eu.kanade.tachiyomi.source.model.Filter | ||||
| import eu.kanade.tachiyomi.source.model.FilterList | ||||
| import eu.kanade.tachiyomi.source.model.Page | ||||
| import eu.kanade.tachiyomi.source.model.SChapter | ||||
| import eu.kanade.tachiyomi.source.model.SManga | ||||
| import eu.kanade.tachiyomi.source.online.ParsedHttpSource | ||||
| import okhttp3.Headers | ||||
| import okhttp3.HttpUrl.Companion.toHttpUrlOrNull | ||||
| import okhttp3.OkHttpClient | ||||
| import okhttp3.Request | ||||
| import org.jsoup.nodes.Document | ||||
| import org.jsoup.nodes.Element | ||||
| import java.util.concurrent.TimeUnit | ||||
| 
 | ||||
| class AsgardTeam : ParsedHttpSource() { | ||||
| 
 | ||||
|     override val name = "AsgardTeam" | ||||
| 
 | ||||
|     override val baseUrl = "https://asgard1team.com" | ||||
| 
 | ||||
|     override val lang = "ar" | ||||
| 
 | ||||
|     override val supportsLatest = true | ||||
| 
 | ||||
|     override val client: OkHttpClient = network.cloudflareClient.newBuilder() | ||||
|         .connectTimeout(10, TimeUnit.SECONDS) | ||||
|         .readTimeout(30, TimeUnit.SECONDS) | ||||
|         .build() | ||||
| 
 | ||||
|     override fun headersBuilder(): Headers.Builder = super.headersBuilder() | ||||
|         .add("Referer", baseUrl) | ||||
| 
 | ||||
|     // Popular | ||||
| 
 | ||||
|     override fun popularMangaSelector() = "div.manga-card" | ||||
| 
 | ||||
|     override fun popularMangaRequest(page: Int): Request { | ||||
|         return GET("$baseUrl/manga-list/?page=$page", headers) | ||||
|     } | ||||
| 
 | ||||
|     override fun popularMangaFromElement(element: Element): SManga = SManga.create().apply { | ||||
|         element.select("div.manga-details__container").let { | ||||
|             thumbnail_url = element.select("img").attr("abs:src") | ||||
|             // title = it.text() | ||||
|         } | ||||
|         element.select("div.manga-details__container").let { | ||||
|             title = element.select("img").attr("alt") | ||||
|         } | ||||
|         element.select("div a.manga-card__title").let { | ||||
|             setUrlWithoutDomain(it.attr("abs:href")) | ||||
|             // title = it.text() | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     override fun popularMangaNextPageSelector() = "ul.pagination a.page-link" | ||||
| 
 | ||||
|     // Latest | ||||
| 
 | ||||
|     override fun latestUpdatesRequest(page: Int): Request { | ||||
|         return GET(baseUrl) | ||||
|     } | ||||
| 
 | ||||
|     override fun latestUpdatesSelector() = popularMangaSelector() | ||||
| 
 | ||||
|     override fun latestUpdatesFromElement(element: Element): SManga = popularMangaFromElement(element) | ||||
| 
 | ||||
|     override fun latestUpdatesNextPageSelector(): String? = null | ||||
| 
 | ||||
|     // Search | ||||
| 
 | ||||
|     override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { | ||||
|         return if (query.isNotBlank()) { | ||||
|             GET("$baseUrl/search/?s=$query&page=$page", headers) | ||||
|         } else { | ||||
|             val url = "$baseUrl/manga-list/?page=$page".toHttpUrlOrNull()!!.newBuilder() | ||||
|             filters.forEach { filter -> | ||||
|                 when (filter) { | ||||
|                     is TypeFilter -> url.addQueryParameter("type", filter.toUriPart()) | ||||
|                     else -> {} | ||||
|                 } | ||||
|             } | ||||
|             GET(url.build().toString(), headers) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     override fun searchMangaSelector() = popularMangaSelector() | ||||
| 
 | ||||
|     override fun searchMangaFromElement(element: Element): SManga = popularMangaFromElement(element) | ||||
| 
 | ||||
|     override fun searchMangaNextPageSelector() = popularMangaNextPageSelector() | ||||
| 
 | ||||
|     // Details | ||||
| 
 | ||||
|     override fun mangaDetailsParse(document: Document): SManga = SManga.create().apply { | ||||
|         return SManga.create().apply { | ||||
|             document.select("div.author-info-title").first()!!.let { info -> | ||||
|                 title = info.select("h6").text() | ||||
|             } | ||||
|             document.select("div.review-author-info").let { info -> | ||||
|                 genre = info.select("a").joinToString { it.text() } | ||||
|             } | ||||
|             document.select("div.full-list-info:contains(المؤلف)").let { info -> | ||||
|                 author = info.select("small").joinToString { it.text() } | ||||
|             } | ||||
|             document.select("div.full-list-info:contains(الرسام)").let { info -> | ||||
|                 artist = info.select("small").joinToString { it.text() } | ||||
|             } | ||||
|             document.select("div.review-content").let { info -> | ||||
|                 description = info.select("p").text() | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // Chapters | ||||
| 
 | ||||
|     override fun chapterListSelector() = "tbody > tr > td" | ||||
| 
 | ||||
|     override fun chapterFromElement(element: Element): SChapter { | ||||
|         val chapter = SChapter.create() | ||||
|         element.select("a").let { | ||||
|             chapter.setUrlWithoutDomain(it.attr("abs:href")) | ||||
|             chapter.name = it.text() | ||||
|         } | ||||
|         chapter.date_upload = 0 | ||||
|         return chapter | ||||
|     } | ||||
| 
 | ||||
|     // Pages | ||||
| 
 | ||||
|     override fun pageListParse(document: Document): List<Page> { | ||||
|         return document.select("section div.container div.container img").mapIndexed { i, img -> | ||||
|             Page(i, "", img.attr("abs:src")) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     override fun imageRequest(page: Page): Request { | ||||
|         return GET(page.imageUrl!!, headersBuilder().set("Referer", page.url).build()) | ||||
|     } | ||||
| 
 | ||||
|     override fun imageUrlParse(document: Document): String = throw UnsupportedOperationException("Not used") | ||||
| 
 | ||||
|     // Filters (TODO: Add Genre Filters Later) | ||||
| 
 | ||||
|     override fun getFilterList() = FilterList( | ||||
|         Filter.Header("NOTE: Ignored if using text search!"), | ||||
|         TypeFilter(getTypeFilter()), | ||||
|     ) | ||||
| 
 | ||||
|     private class TypeFilter(vals: Array<Pair<String?, String>>) : UriPartFilter("Type", vals) | ||||
| 
 | ||||
|     private fun getTypeFilter(): Array<Pair<String?, String>> = arrayOf( | ||||
|         Pair("", "<select>"), | ||||
|         Pair("3", "صينية (مانها)"), | ||||
|         Pair("2", "مانجا (يابانية)"), | ||||
|         Pair("1", "كورية (مانهوا)"), | ||||
|     ) | ||||
| 
 | ||||
|     open class UriPartFilter(displayName: String, private val vals: Array<Pair<String?, String>>) : | ||||
|         Filter.Select<String>(displayName, vals.map { it.second }.toTypedArray()) { | ||||
|         fun toUriPart() = vals[state].first | ||||
|     } | ||||
| } | ||||
| @ -1,3 +0,0 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     package="eu.kanade.tachiyomi.extension" /> | ||||
| @ -1,12 +0,0 @@ | ||||
| apply plugin: 'com.android.application' | ||||
| apply plugin: 'kotlin-android' | ||||
| 
 | ||||
| ext { | ||||
|     extName = 'Nana' | ||||
|     pkgNameSuffix = 'en.nana' | ||||
|     extClass = '.Nana' | ||||
|     extVersionCode = 2 | ||||
|     isNsfw = true | ||||
| } | ||||
| 
 | ||||
| apply from: "$rootDir/common.gradle" | ||||
| Before Width: | Height: | Size: 2.2 KiB | 
| Before Width: | Height: | Size: 1.3 KiB | 
| Before Width: | Height: | Size: 3.1 KiB | 
| Before Width: | Height: | Size: 5.2 KiB | 
| Before Width: | Height: | Size: 7.1 KiB | 
| Before Width: | Height: | Size: 28 KiB | 
| @ -1,207 +0,0 @@ | ||||
| package eu.kanade.tachiyomi.extension.en.nana | ||||
| 
 | ||||
| import eu.kanade.tachiyomi.network.GET | ||||
| import eu.kanade.tachiyomi.network.asObservable | ||||
| import eu.kanade.tachiyomi.network.interceptor.rateLimit | ||||
| 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.model.UpdateStrategy | ||||
| import eu.kanade.tachiyomi.source.online.ParsedHttpSource | ||||
| import okhttp3.Call | ||||
| import okhttp3.HttpUrl.Companion.toHttpUrl | ||||
| import okhttp3.Request | ||||
| import okhttp3.Response | ||||
| import org.jsoup.nodes.Document | ||||
| import org.jsoup.nodes.Element | ||||
| import rx.Observable | ||||
| 
 | ||||
| class Nana : ParsedHttpSource() { | ||||
|     override val name = "Nana ナナ" | ||||
| 
 | ||||
|     override val baseUrl = "https://nana.my.id" | ||||
| 
 | ||||
|     override val lang = "en" | ||||
| 
 | ||||
|     override val supportsLatest = false | ||||
| 
 | ||||
|     override val client = super.client.newBuilder() | ||||
|         .rateLimit(1) | ||||
|         .build() | ||||
| 
 | ||||
|     // ~~Popular~~ Latest | ||||
|     override fun popularMangaRequest(page: Int): Request = | ||||
|         searchMangaRequest(page, "", FilterList()) | ||||
| 
 | ||||
|     override fun popularMangaSelector(): String = | ||||
|         searchMangaSelector() | ||||
| 
 | ||||
|     override fun popularMangaFromElement(element: Element): SManga = | ||||
|         searchMangaFromElement(element) | ||||
| 
 | ||||
|     override fun popularMangaNextPageSelector(): String? = | ||||
|         searchMangaNextPageSelector() | ||||
| 
 | ||||
|     // Search | ||||
|     // The search returns 404 when there's no results. | ||||
|     override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> { | ||||
|         return client.newCall(searchMangaRequest(page, query, filters)) | ||||
|             .asObservableIgnoreCode(404) | ||||
|             .map(::searchMangaParse) | ||||
|     } | ||||
| 
 | ||||
|     override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { | ||||
|         val filterList = if (filters.isEmpty()) getFilterList() else filters | ||||
|         val tagsFilter = filterList.find { it is TagsFilter } as TagsFilter | ||||
|         val sortFilter = filterList.find { it is SortFilter } as SortFilter | ||||
| 
 | ||||
|         val url = "$baseUrl/".toHttpUrl().newBuilder() | ||||
|             .addQueryParameter("q", "${tagsFilter.toUriPart()} $query".trim()) | ||||
|             .addQueryParameter("sort", sortFilter.toUriPart()) | ||||
| 
 | ||||
|         if (page != 1) { | ||||
|             url.addQueryParameter("p", page.toString()) | ||||
|         } | ||||
| 
 | ||||
|         return GET(url.toString(), headers) | ||||
|     } | ||||
| 
 | ||||
|     override fun searchMangaSelector(): String = | ||||
|         "#thumbs_container > .id1" | ||||
| 
 | ||||
|     override fun searchMangaFromElement(element: Element): SManga = SManga.create().apply { | ||||
|         val a = element.selectFirst(".id3 > a")!! | ||||
|         setUrlWithoutDomain(a.absUrl("href")) | ||||
|         title = a.attr("title") | ||||
| 
 | ||||
|         val img = a.selectFirst("> img")!! | ||||
|         thumbnail_url = img.absUrl("src") | ||||
|         author = img.attr("alt") | ||||
|             .replace("$title by ", "") | ||||
|             .ifBlank { null } | ||||
| 
 | ||||
|         genre = element.select(".id4 > .tags > span") | ||||
|             .joinToString { it.text() } | ||||
| 
 | ||||
|         status = SManga.COMPLETED | ||||
|         update_strategy = UpdateStrategy.ONLY_FETCH_ONCE | ||||
|         initialized = true | ||||
|     } | ||||
| 
 | ||||
|     override fun searchMangaNextPageSelector(): String = | ||||
|         "a.paginate_button.current + a.paginate_button" | ||||
| 
 | ||||
|     // Latest | ||||
|     override fun latestUpdatesRequest(page: Int): Request = | ||||
|         throw UnsupportedOperationException("Not used.") | ||||
| 
 | ||||
|     override fun latestUpdatesSelector(): String = | ||||
|         throw UnsupportedOperationException("Not used.") | ||||
| 
 | ||||
|     override fun latestUpdatesFromElement(element: Element): SManga = | ||||
|         throw UnsupportedOperationException("Not used.") | ||||
| 
 | ||||
|     override fun latestUpdatesNextPageSelector(): String = | ||||
|         throw UnsupportedOperationException("Not used.") | ||||
| 
 | ||||
|     // Details | ||||
|     override fun fetchMangaDetails(manga: SManga): Observable<SManga> = | ||||
|         Observable.just(manga) | ||||
| 
 | ||||
|     override fun mangaDetailsParse(document: Document): SManga = | ||||
|         throw UnsupportedOperationException("Not used.") | ||||
| 
 | ||||
|     // Chapters | ||||
|     override fun fetchChapterList(manga: SManga): Observable<List<SChapter>> { | ||||
|         return Observable.just( | ||||
|             listOf( | ||||
|                 SChapter.create().apply { | ||||
|                     setUrlWithoutDomain(manga.url) | ||||
|                     name = "Chapter" | ||||
|                     date_upload = 0L | ||||
|                     chapter_number = 1F | ||||
|                 }, | ||||
|             ), | ||||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     override fun chapterListSelector(): String = | ||||
|         throw UnsupportedOperationException("Not used.") | ||||
| 
 | ||||
|     override fun chapterFromElement(element: Element): SChapter = | ||||
|         throw UnsupportedOperationException("Not used.") | ||||
| 
 | ||||
|     // Pages | ||||
|     override fun pageListParse(document: Document): List<Page> { | ||||
|         val body = document.body().toString() | ||||
| 
 | ||||
|         return PATTERN_PAGES.find(body) | ||||
|             ?.groupValues?.get(1) | ||||
|             ?.split(',') | ||||
|             ?.map(String::trim) | ||||
|             ?.mapIndexed { i, imgStr -> | ||||
|                 val imgUrl = baseUrl + imgStr.substring(1, imgStr.lastIndex) | ||||
|                 Page(i, "", imgUrl) | ||||
|             } | ||||
|             ?: emptyList() | ||||
|     } | ||||
| 
 | ||||
|     override fun imageUrlParse(document: Document): String = | ||||
|         throw UnsupportedOperationException("Not used.") | ||||
| 
 | ||||
|     // Filters | ||||
|     override fun getFilterList(): FilterList = FilterList( | ||||
|         Filter.Header("Use comma (,) to separate tags"), | ||||
|         Filter.Header("Prefix plus (+) to require tag"), | ||||
|         Filter.Header("Prefix minus (-) to exclude tag"), | ||||
|         TagsFilter(), | ||||
| 
 | ||||
|         Filter.Separator(), | ||||
|         SortFilter(), | ||||
|     ) | ||||
| 
 | ||||
|     open class TagsFilter : | ||||
|         Filter.Text("Tags", "") { | ||||
|         fun toUriPart(): String { | ||||
|             return state.split(',') | ||||
|                 .map(String::trim) | ||||
|                 .map { tag -> | ||||
|                     if (tag.isEmpty() || tag.contains('"')) { return@map tag } | ||||
| 
 | ||||
|                     val prefix = tag.substring(0, 1) | ||||
| 
 | ||||
|                     if (listOf("+", "-").any { prefix.contains(it) }) { | ||||
|                         "$prefix\"${tag.substring(1)}\"" | ||||
|                     } else { | ||||
|                         "\"$tag\"" | ||||
|                     } | ||||
|                 } | ||||
|                 .joinToString(" ") | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     open class SortFilter : | ||||
|         Filter.Sort("Sort", arrayOf("Date Added"), Selection(0, false)) { | ||||
|         fun toUriPart(): String = when (state?.ascending) { | ||||
|             true -> "asc" | ||||
|             else -> "desc" | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // Other | ||||
|     private fun Call.asObservableIgnoreCode(code: Int): Observable<Response> { | ||||
|         return asObservable().doOnNext { response -> | ||||
|             if (!response.isSuccessful && response.code != code) { | ||||
|                 response.close() | ||||
|                 throw Exception("HTTP error ${response.code}") | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     companion object { | ||||
|         private val PATTERN_PAGES = Regex("Reader\\.pages\\s*=\\s*\\{\\\"pages\\\":\\[([^];\\n]+)]\\}\\.pages;") | ||||
|     } | ||||
| } | ||||
 arkon
						arkon