diff --git a/src/all/wpmangastream/build.gradle b/src/all/wpmangastream/build.gradle index 32c76d234..34b04d1ef 100644 --- a/src/all/wpmangastream/build.gradle +++ b/src/all/wpmangastream/build.gradle @@ -5,7 +5,7 @@ ext { appName = 'Tachiyomi: WP Manga Stream' pkgNameSuffix = 'all.wpmangastream' extClass = '.WPMangaStreamFactory' - extVersionCode = 8 + extVersionCode = 9 libVersion = '1.2' } diff --git a/src/all/wpmangastream/src/eu/kanade/tachiyomi/extension/all/wpmangastream/WPMangaStream.kt b/src/all/wpmangastream/src/eu/kanade/tachiyomi/extension/all/wpmangastream/WPMangaStream.kt index 8351b0219..3e90ff58f 100644 --- a/src/all/wpmangastream/src/eu/kanade/tachiyomi/extension/all/wpmangastream/WPMangaStream.kt +++ b/src/all/wpmangastream/src/eu/kanade/tachiyomi/extension/all/wpmangastream/WPMangaStream.kt @@ -1,6 +1,5 @@ package eu.kanade.tachiyomi.extension.all.wpmangastream -import android.annotation.SuppressLint import android.app.Application import android.content.SharedPreferences import android.support.v7.preference.ListPreference @@ -24,6 +23,7 @@ import okhttp3.OkHttpClient import okhttp3.Request import org.jsoup.nodes.Document import org.jsoup.nodes.Element +import org.jsoup.select.Elements import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get @@ -91,6 +91,9 @@ abstract class WPMangaStream( .addNetworkInterceptor(rateLimitInterceptor) .build() + protected fun Element.imgAttr(): String = if (this.hasAttr("data-src")) this.attr("abs:data-src") else this.attr("abs:src") + protected fun Elements.imgAttr(): String = this.first().imgAttr() + override fun popularMangaRequest(page: Int): Request { return GET("$baseUrl/manga/page/$page/?order=popular", headers) } @@ -142,7 +145,7 @@ abstract class WPMangaStream( override fun popularMangaFromElement(element: Element): SManga { val manga = SManga.create() - manga.thumbnail_url = element.select("div.limit img").attr("abs:src") + manga.thumbnail_url = element.select("div.limit img").imgAttr() element.select("div.bsx > a").first().let { manga.setUrlWithoutDomain(it.attr("href")) manga.title = it.attr("title") @@ -158,23 +161,22 @@ abstract class WPMangaStream( override fun searchMangaNextPageSelector() = popularMangaNextPageSelector() override fun mangaDetailsParse(document: Document): SManga { - val infoElement = document.select("div.spe").first() - val sepName = infoElement.select(".spe > span:contains(Author)").last() - val manga = SManga.create() - manga.author = sepName?.ownText() ?: "N/A" - manga.artist = sepName?.ownText() ?: "N/A" - manga.genre = infoElement.select(".spe > span:nth-child(1) > a").joinToString { it.text() } - manga.status = parseStatus(infoElement.select(".spe > span:nth-child(2)").text()) - manga.description = document.select(".infox > div.desc").first().select("p").text() - manga.thumbnail_url = document.select(".thumb > img:nth-child(1)").attr("src") - - return manga + return SManga.create().apply { + document.select("div.bigcontent, div.animefull").firstOrNull()?.let { infoElement -> + genre = infoElement.select("span:contains(Genres:) a").joinToString { it.text() } + status = parseStatus(infoElement.select("span:contains(Status:)").firstOrNull()?.ownText()) + author = infoElement.select("span:contains(Author:)").firstOrNull()?.ownText() + artist = author + description = infoElement.select("div.desc p").joinToString("\n") { it.text() } + thumbnail_url = infoElement.select("img").imgAttr() + } + } } - @SuppressLint("DefaultLocale") - internal open fun parseStatus(element: String): Int = when { - element.toLowerCase().contains("ongoing") -> SManga.ONGOING - element.toLowerCase().contains("completed") -> SManga.COMPLETED + protected fun parseStatus(element: String?): Int = when { + element == null -> SManga.UNKNOWN + listOf("ongoing", "publishing").any { it.contains(element, ignoreCase = true) } -> SManga.ONGOING + listOf("completed").any { it.contains(element, ignoreCase = true) } -> SManga.COMPLETED else -> SManga.UNKNOWN } @@ -236,16 +238,9 @@ abstract class WPMangaStream( } override fun pageListParse(document: Document): List { - val pages = mutableListOf() - var i = 0 - document.select("div#readerarea img").forEach { element -> - val url = element.attr("abs:src") - i++ - if (url.isNotEmpty()) { - pages.add(Page(i, "", url)) - } - } - return pages + return document.select("div#readerarea img") + .filterNot { it.attr("src").isNullOrEmpty() } + .mapIndexed { i, img -> Page(i, "", img.attr("abs:src")) } } override fun imageUrlParse(document: Document): String = throw UnsupportedOperationException("Not used") @@ -257,7 +252,7 @@ abstract class WPMangaStream( add("User-Agent", "Mozilla/5.0 (Linux; U; Android 4.4.2; en-us; LGMS323 Build/KOT49I.MS32310c) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/76.0.3809.100 Mobile Safari/537.36") } - if (page.imageUrl!!.contains("i0.wp.com")) { + if (page.imageUrl!!.contains(".wp.com")) { headers.apply { add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3") } @@ -279,7 +274,7 @@ abstract class WPMangaStream( private class YearFilter : Filter.Text("Year") - private class TypeFilter : UriPartFilter("Type", arrayOf( + protected class TypeFilter : UriPartFilter("Type", arrayOf( Pair("Default", ""), Pair("Manga", "Manga"), Pair("Manhwa", "Manhwa"), diff --git a/src/all/wpmangastream/src/eu/kanade/tachiyomi/extension/all/wpmangastream/WPMangaStreamFactory.kt b/src/all/wpmangastream/src/eu/kanade/tachiyomi/extension/all/wpmangastream/WPMangaStreamFactory.kt index 66b2b8566..1378a5835 100644 --- a/src/all/wpmangastream/src/eu/kanade/tachiyomi/extension/all/wpmangastream/WPMangaStreamFactory.kt +++ b/src/all/wpmangastream/src/eu/kanade/tachiyomi/extension/all/wpmangastream/WPMangaStreamFactory.kt @@ -11,6 +11,8 @@ 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.util.asJsoup +import java.io.IOException +import okhttp3.Headers import okhttp3.HttpUrl import okhttp3.Interceptor import okhttp3.OkHttpClient @@ -32,7 +34,8 @@ class WPMangaStreamFactory : SourceFactory { MaidManga(), SekteKomik(), MangaSwat(), - MangaRaw() + MangaRaw(), + SekteDoujin() ) } @@ -106,25 +109,6 @@ class KomikCast : WPMangaStream("Komik Cast (WP Manga Stream)", "https://komikca return manga } - override fun mangaDetailsParse(document: Document): SManga { - val infoElement = document.select("div.spe").first() - val sepName = infoElement.select(".spe > span:nth-child(4)").last() - val manga = SManga.create() - manga.author = sepName.ownText() - manga.artist = sepName.ownText() - val genres = mutableListOf() - infoElement.select(".spe > span:nth-child(1) > a").forEach { element -> - val genre = element.text() - genres.add(genre) - } - manga.genre = genres.joinToString(", ") - manga.status = parseStatus(infoElement.select(".spe > span:nth-child(2)").text()) - manga.description = document.select("div[^itemprop]").last().text() - manga.thumbnail_url = document.select(".thumb > img:nth-child(1)").attr("src") - - return manga - } - override fun pageListParse(document: Document): List { return document.select("div#readerarea img.size-full") .mapIndexed { i, img -> Page(i, "", img.attr("abs:Src")) } @@ -204,12 +188,6 @@ class WestManga : WPMangaStream("West Manga (WP Manga Stream)", "https://westman return manga } - @SuppressLint("DefaultLocale") - override fun parseStatus(element: String): Int = when { - element.toLowerCase().contains("publishing") -> SManga.ONGOING - else -> SManga.UNKNOWN - } - private class SortByFilter : UriPartFilter("Sort By", arrayOf( Pair("Default", ""), Pair("A-Z", "A-Z"), @@ -390,7 +368,7 @@ class KomikGo : WPMangaStream("Komik GO (WP Manga Stream)", "https://komikgo.com override fun pageListParse(document: Document): List { return document.select("div.reading-content * img").mapIndexed { i, img -> - Page(i, "", img.let { if (it.hasAttr("data-src")) it.attr("abs:data-src") else it.attr("abs:src") }) + Page(i, "", img.imgAttr()) } } @@ -805,40 +783,103 @@ class MaidManga : WPMangaStream("Maid Manga (WP Manga Stream)", "https://www.mai } class MangaSwat : WPMangaStream("MangaSwat", "https://mangaswat.com", "ar") { + /** + * Use IOException or the app crashes! + * x-sucuri-cache header is never present on images; specify webpages or glide won't load images! + */ private class Sucuri : Interceptor { override fun intercept(chain: Interceptor.Chain): Response { - val originalRequest = chain.request() - val response = chain.proceed(originalRequest) - if (response.headers().get("x-sucuri-cache").isNullOrEmpty()) throw Exception("Site protected, open webview | موقع محمي ، عرض ويب مفتوح") + val response = chain.proceed(chain.request()) + if (response.header("x-sucuri-cache").isNullOrEmpty() && response.request().url().toString().contains("//mangaswat.com")) + throw IOException("Site protected, open webview | موقع محمي ، عرض ويب مفتوح") return response } } override val client: OkHttpClient = super.client.newBuilder().addInterceptor(Sucuri()).build() - override fun mangaDetailsParse(document: Document): SManga = SManga.create().apply { - thumbnail_url = document.select("div.thumb img.lazyload").attr("data-src") - title = document.select("div.infox h1").text() - genre = document.select("div.spe [rel=tag]").joinToString(", ") { it.text() } - status = when (document.select("span:contains(الحالة)").text().substringAfter(":").trim()) { - "Ongoing" -> SManga.ONGOING - "Completed" -> SManga.COMPLETED - else -> SManga.UNKNOWN + override fun headersBuilder(): Headers.Builder = Headers.Builder() + .add("Referer", baseUrl) + .add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:76.0) Gecko/20100101 Firefox/76.0") + .add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3") + + override fun popularMangaNextPageSelector() = "div.hpage a.r" + + override fun mangaDetailsParse(document: Document): SManga { + return SManga.create().apply { + document.select("div.bigcontent").firstOrNull()?.let { infoElement -> + genre = infoElement.select("span:contains(التصنيف) a").joinToString { it.text() } + status = parseStatus(infoElement.select("span:contains(الحالة)").firstOrNull()?.ownText()) + author = infoElement.select("span:contains(المؤلف) i").firstOrNull()?.ownText() + artist = author + description = infoElement.select("div.desc").text() + thumbnail_url = infoElement.select("img").imgAttr() + } } - author = document.select("span:contains(المؤلف)").text().substringAfter(":").trim() - artist = author - description = document.select("div[itemprop=articleBody]").text() } override fun pageListRequest(chapter: SChapter): Request { return GET(baseUrl + chapter.url + "?/", headers) // Bypass "linkvertise" ads } - override fun pageListParse(document: Document): List = mutableListOf().apply { - document.select("div#readerarea img[data-src]").forEachIndexed { index, element -> - add(Page(index, "", element.attr("data-src"))) - } - } - override fun imageRequest(page: Page): Request { - return GET(page.imageUrl!!, headers) - } + + override fun getFilterList() = FilterList( + StatusFilter(), + TypeFilter(), + SortByFilter(), + GenreListFilter(getGenrePairs()) + ) + + private class GenreListFilter(pairs: Array>) : UriPartFilter("Genre", pairs) + + private fun getGenrePairs() = arrayOf( + Pair("<--->", ""), + Pair("آلات", "%d8%a2%d9%84%d8%a7%d8%aa"), + Pair("أكشن", "%d8%a3%d9%83%d8%b4%d9%86"), + Pair("إثارة", "%d8%a5%d8%ab%d8%a7%d8%b1%d8%a9"), + Pair("إعادة", "%d8%a5%d8%b9%d8%a7%d8%af%d8%a9-%d8%a5%d8%ad%d9%8a%d8%a7%d8%a1"), + Pair("الحياة", "%d8%a7%d9%84%d8%ad%d9%8a%d8%a7%d8%a9-%d8%a7%d9%84%d9%85%d8%af%d8%b1%d8%b3%d9%8a%d8%a9"), + Pair("الحياة", "%d8%a7%d9%84%d8%ad%d9%8a%d8%a7%d8%a9-%d8%a7%d9%84%d9%8a%d9%88%d9%85%d9%8a%d8%a9"), + Pair("العاب", "%d8%a7%d9%84%d8%b9%d8%a7%d8%a8-%d9%81%d9%8a%d8%af%d9%8a%d9%88"), + Pair("ايتشي", "%d8%a7%d9%8a%d8%aa%d8%b4%d9%8a"), + Pair("ايسكاي", "%d8%a7%d9%8a%d8%b3%d9%83%d8%a7%d9%8a"), + Pair("بالغ", "%d8%a8%d8%a7%d9%84%d8%ba"), + Pair("تاريخي", "%d8%aa%d8%a7%d8%b1%d9%8a%d8%ae%d9%8a"), + Pair("تراجيدي", "%d8%aa%d8%b1%d8%a7%d8%ac%d9%8a%d8%af%d9%8a"), + Pair("جوسيه", "%d8%ac%d9%88%d8%b3%d9%8a%d9%87"), + Pair("جيندر", "%d8%ac%d9%8a%d9%86%d8%af%d8%b1-%d8%a8%d9%86%d8%af%d8%b1"), + Pair("حربي", "%d8%ad%d8%b1%d8%a8%d9%8a"), + Pair("حريم", "%d8%ad%d8%b1%d9%8a%d9%85"), + Pair("خارق", "%d8%ae%d8%a7%d8%b1%d9%82-%d9%84%d9%84%d8%b7%d8%a8%d9%8a%d8%b9%d8%a9"), + Pair("خيال", "%d8%ae%d9%8a%d8%a7%d9%84"), + Pair("خيال", "%d8%ae%d9%8a%d8%a7%d9%84-%d8%b9%d9%84%d9%85%d9%8a"), + Pair("دراما", "%d8%af%d8%b1%d8%a7%d9%85%d8%a7"), + Pair("دموي", "%d8%af%d9%85%d9%88%d9%8a"), + Pair("رعب", "%d8%b1%d8%b9%d8%a8"), + Pair("رومانسي", "%d8%b1%d9%88%d9%85%d8%a7%d9%86%d8%b3%d9%8a"), + Pair("رياضة", "%d8%b1%d9%8a%d8%a7%d8%b6%d8%a9"), + Pair("زمكاني", "%d8%b2%d9%85%d9%83%d8%a7%d9%86%d9%8a"), + Pair("زومبي", "%d8%b2%d9%88%d9%85%d8%a8%d9%8a"), + Pair("سحر", "%d8%b3%d8%ad%d8%b1"), + Pair("سينين", "%d8%b3%d9%8a%d9%86%d9%8a%d9%86"), + Pair("شريحة", "%d8%b4%d8%b1%d9%8a%d8%ad%d8%a9-%d9%85%d9%86-%d8%a7%d9%84%d8%ad%d9%8a%d8%a7%d8%a9"), + Pair("شوجو", "%d8%b4%d9%88%d8%ac%d9%88"), + Pair("شونين", "%d8%b4%d9%88%d9%86%d9%8a%d9%86"), + Pair("شياطين", "%d8%b4%d9%8a%d8%a7%d8%b7%d9%8a%d9%86"), + Pair("طبخ", "%d8%b7%d8%a8%d8%ae"), + Pair("طبي", "%d8%b7%d8%a8%d9%8a"), + Pair("غموض", "%d8%ba%d9%85%d9%88%d8%b6"), + Pair("فانتازي", "%d9%81%d8%a7%d9%86%d8%aa%d8%a7%d8%b2%d9%8a"), + Pair("فنون", "%d9%81%d9%86%d9%88%d9%86-%d9%82%d8%aa%d8%a7%d9%84%d9%8a%d8%a9"), + Pair("فوق", "%d9%81%d9%88%d9%82-%d8%a7%d9%84%d8%b7%d8%a8%d9%8a%d8%b9%d8%a9"), + Pair("قوى", "%d9%82%d9%88%d9%89-%d8%ae%d8%a7%d8%b1%d9%82%d8%a9"), + Pair("كوميدي", "%d9%83%d9%88%d9%85%d9%8a%d8%af%d9%8a"), + Pair("لعبة", "%d9%84%d8%b9%d8%a8%d8%a9"), + Pair("مافيا", "%d9%85%d8%a7%d9%81%d9%8a%d8%a7"), + Pair("مصاصى", "%d9%85%d8%b5%d8%a7%d8%b5%d9%89-%d8%a7%d9%84%d8%af%d9%85%d8%a7%d8%a1"), + Pair("مغامرات", "%d9%85%d8%ba%d8%a7%d9%85%d8%b1%d8%a7%d8%aa"), + Pair("ميكا", "%d9%85%d9%8a%d9%83%d8%a7"), + Pair("نفسي", "%d9%86%d9%81%d8%b3%d9%8a"), + Pair("وحوش", "%d9%88%d8%ad%d9%88%d8%b4"), + Pair("ويب-تون", "%d9%88%d9%8a%d8%a8-%d8%aa%d9%88%d9%86") + ) } class MangaRaw : WPMangaStream("Manga Raw", "https://mangaraw.org", "ja") { @@ -858,6 +899,8 @@ class MangaRaw : WPMangaStream("Manga Raw", "https://mangaraw.org", "ja") { override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request = GET("$baseUrl/search?s=$query&page=$page") override fun searchMangaFromElement(element: Element): SManga = popularMangaFromElement(element) + override fun mangaDetailsParse(document: Document): SManga = super.mangaDetailsParse(document) + .apply { description = document.select("div.bottom").firstOrNull()?.ownText() } override fun fetchPageList(chapter: SChapter): Observable> { return client.newCall(pageListRequest(chapter)) .asObservableSuccess() @@ -873,3 +916,5 @@ class MangaRaw : WPMangaStream("Manga Raw", "https://mangaraw.org", "ja") { override fun imageUrlParse(document: Document): String = document.select("a.img-block img").attr("abs:src") override fun getFilterList(): FilterList = FilterList() } + +class SekteDoujin : WPMangaStream("Sekte Doujin", "https://sektedoujin.com", "id")