From 0e3464457c293ce1c25f0db734b60b5b8010d85d Mon Sep 17 00:00:00 2001 From: inorichi Date: Fri, 12 Apr 2019 19:05:18 +0200 Subject: [PATCH] Remove internal sources --- .../kanade/tachiyomi/source/SourceManager.kt | 17 +- .../tachiyomi/source/online/english/Batoto.kt | 31 -- .../source/online/english/Kissmanga.kt | 253 --------------- .../source/online/english/Mangafox.kt | 231 -------------- .../source/online/english/Mangahere.kt | 259 ---------------- .../source/online/english/Mangasee.kt | 249 --------------- .../source/online/english/Readmangatoday.kt | 224 -------------- .../source/online/german/WieManga.kt | 122 -------- .../source/online/russian/Mangachan.kt | 290 ------------------ .../source/online/russian/Mintmanga.kt | 251 --------------- .../source/online/russian/Readmanga.kt | 247 --------------- 11 files changed, 1 insertion(+), 2173 deletions(-) delete mode 100644 app/src/main/java/eu/kanade/tachiyomi/source/online/english/Batoto.kt delete mode 100644 app/src/main/java/eu/kanade/tachiyomi/source/online/english/Kissmanga.kt delete mode 100644 app/src/main/java/eu/kanade/tachiyomi/source/online/english/Mangafox.kt delete mode 100644 app/src/main/java/eu/kanade/tachiyomi/source/online/english/Mangahere.kt delete mode 100644 app/src/main/java/eu/kanade/tachiyomi/source/online/english/Mangasee.kt delete mode 100644 app/src/main/java/eu/kanade/tachiyomi/source/online/english/Readmangatoday.kt delete mode 100644 app/src/main/java/eu/kanade/tachiyomi/source/online/german/WieManga.kt delete mode 100644 app/src/main/java/eu/kanade/tachiyomi/source/online/russian/Mangachan.kt delete mode 100644 app/src/main/java/eu/kanade/tachiyomi/source/online/russian/Mintmanga.kt delete mode 100644 app/src/main/java/eu/kanade/tachiyomi/source/online/russian/Readmanga.kt diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/SourceManager.kt b/app/src/main/java/eu/kanade/tachiyomi/source/SourceManager.kt index 4c3596a0fd..a8d0fed162 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/source/SourceManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/SourceManager.kt @@ -6,11 +6,6 @@ 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.source.online.english.* -import eu.kanade.tachiyomi.source.online.german.WieManga -import eu.kanade.tachiyomi.source.online.russian.Mangachan -import eu.kanade.tachiyomi.source.online.russian.Mintmanga -import eu.kanade.tachiyomi.source.online.russian.Readmanga import rx.Observable open class SourceManager(private val context: Context) { @@ -48,17 +43,7 @@ open class SourceManager(private val context: Context) { } private fun createInternalSources(): List = listOf( - LocalSource(context), - Batoto(), - Mangahere(), - Mangafox(), - Kissmanga(), - Readmanga(), - Mintmanga(), - Mangachan(), - Readmangatoday(), - Mangasee(), - WieManga() + LocalSource(context) ) private inner class StubSource(override val id: Long) : Source { diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/english/Batoto.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/english/Batoto.kt deleted file mode 100644 index bf1ef7a757..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/source/online/english/Batoto.kt +++ /dev/null @@ -1,31 +0,0 @@ -package eu.kanade.tachiyomi.source.online.english - -import eu.kanade.tachiyomi.source.Source -import eu.kanade.tachiyomi.source.model.Page -import eu.kanade.tachiyomi.source.model.SChapter -import eu.kanade.tachiyomi.source.model.SManga -import rx.Observable - -class Batoto : Source { - - override val id: Long = 1 - - override val name = "Batoto" - - override fun fetchMangaDetails(manga: SManga): Observable { - return Observable.error(Exception("RIP Batoto")) - } - - override fun fetchChapterList(manga: SManga): Observable> { - return Observable.error(Exception("RIP Batoto")) - } - - override fun fetchPageList(chapter: SChapter): Observable> { - return Observable.error(Exception("RIP Batoto")) - } - - override fun toString(): String { - return "$name (EN)" - } - -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/english/Kissmanga.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/english/Kissmanga.kt deleted file mode 100644 index 0287c1fb56..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/source/online/english/Kissmanga.kt +++ /dev/null @@ -1,253 +0,0 @@ -package eu.kanade.tachiyomi.source.online.english - -import com.squareup.duktape.Duktape -import eu.kanade.tachiyomi.network.GET -import eu.kanade.tachiyomi.network.POST -import eu.kanade.tachiyomi.source.model.* -import eu.kanade.tachiyomi.source.online.ParsedHttpSource -import okhttp3.FormBody -import okhttp3.Headers -import okhttp3.OkHttpClient -import okhttp3.Request -import okhttp3.Response -import org.jsoup.nodes.Document -import org.jsoup.nodes.Element -import timber.log.Timber -import java.text.SimpleDateFormat -import java.util.regex.Pattern - -class Kissmanga : ParsedHttpSource() { - - override val id: Long = 4 - - override val name = "Kissmanga" - - override val baseUrl = "http://kissmanga.com" - - override val lang = "en" - - override val supportsLatest = true - - override val client: OkHttpClient = network.cloudflareClient - - override fun headersBuilder(): Headers.Builder { - return Headers.Builder() - .add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) Gecko/20100101 Firefox/60") - } - - override fun popularMangaSelector() = "table.listing tr:gt(1)" - - override fun latestUpdatesSelector() = "table.listing tr:gt(1)" - - override fun popularMangaRequest(page: Int): Request { - return GET("$baseUrl/MangaList/MostPopular?page=$page", headers) - } - - override fun latestUpdatesRequest(page: Int): Request { - return GET("http://kissmanga.com/MangaList/LatestUpdate?page=$page", headers) - } - - override fun popularMangaFromElement(element: Element): SManga { - val manga = SManga.create() - element.select("td a:eq(0)").first().let { - manga.setUrlWithoutDomain(it.attr("href")) - val title = it.text() - //check if cloudfire email obfuscation is affecting title name - if (title.contains("[email protected]", true)) { - try { - var str: String = it.html() - //get the number - str = str.substringAfter("data-cfemail=\"") - str = str.substringBefore("\">[email") - val sb = StringBuilder() - //convert number to char - val r = Integer.valueOf(str.substring(0, 2), 16)!! - var i = 2 - while (i < str.length) { - val c = (Integer.valueOf(str.substring(i, i + 2), 16) xor r).toChar() - sb.append(c) - i += 2 - } - //replace the new word into the title - manga.title = title.replace("[email protected]", sb.toString(), true) - } catch (e: Exception) { - //on error just default to obfuscated title - Timber.e("error parsing [email protected]", e) - manga.title = title - } - } else { - manga.title = title - } - } - return manga - } - - override fun latestUpdatesFromElement(element: Element): SManga { - return popularMangaFromElement(element) - } - - override fun popularMangaNextPageSelector() = "li > a:contains(› Next)" - - override fun latestUpdatesNextPageSelector(): String = "ul.pager > li > a:contains(Next)" - - override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { - val form = FormBody.Builder().apply { - add("mangaName", query) - - for (filter in if (filters.isEmpty()) getFilterList() else filters) { - when (filter) { - is Author -> add("authorArtist", filter.state) - is Status -> add("status", arrayOf("", "Completed", "Ongoing")[filter.state]) - is GenreList -> filter.state.forEach { genre -> add("genres", genre.state.toString()) } - } - } - } - return POST("$baseUrl/AdvanceSearch", headers, form.build()) - } - - override fun searchMangaSelector() = popularMangaSelector() - - override fun searchMangaFromElement(element: Element): SManga { - return popularMangaFromElement(element) - } - - override fun searchMangaNextPageSelector() = null - - override fun mangaDetailsParse(document: Document): SManga { - val infoElement = document.select("div.barContent").first() - - val manga = SManga.create() - manga.author = infoElement.select("p:has(span:contains(Author:)) > a").first()?.text() - manga.genre = infoElement.select("p:has(span:contains(Genres:)) > *:gt(0)").text() - manga.description = infoElement.select("p:has(span:contains(Summary:)) ~ p").text() - manga.status = infoElement.select("p:has(span:contains(Status:))").first()?.text().orEmpty().let { parseStatus(it) } - manga.thumbnail_url = document.select(".rightBox:eq(0) img").first()?.attr("src") - return manga - } - - fun parseStatus(status: String) = when { - status.contains("Ongoing") -> SManga.ONGOING - status.contains("Completed") -> SManga.COMPLETED - else -> SManga.UNKNOWN - } - - override fun chapterListSelector() = "table.listing tr:gt(1)" - - override fun chapterFromElement(element: Element): SChapter { - val urlElement = element.select("a").first() - - val chapter = SChapter.create() - chapter.setUrlWithoutDomain(urlElement.attr("href")) - chapter.name = urlElement.text() - chapter.date_upload = element.select("td:eq(1)").first()?.text()?.let { - SimpleDateFormat("MM/dd/yyyy").parse(it).time - } ?: 0 - return chapter - } - - override fun pageListRequest(chapter: SChapter) = POST(baseUrl + chapter.url, headers) - - override fun pageListParse(response: Response): List { - val body = response.body()!!.string() - - val pages = mutableListOf() - - // Kissmanga now encrypts the urls, so we need to execute these two scripts in JS. - val ca = client.newCall(GET("$baseUrl/Scripts/ca.js", headers)).execute().body()!!.string() - val lo = client.newCall(GET("$baseUrl/Scripts/lo.js", headers)).execute().body()!!.string() - - Duktape.create().use { - it.evaluate(ca) - it.evaluate(lo) - - // There are two functions in an inline script needed to decrypt the urls. We find and - // execute them. - var p = Pattern.compile("(var.*CryptoJS.*)") - var m = p.matcher(body) - while (m.find()) { - it.evaluate(m.group(1)) - } - - // Finally find all the urls and decrypt them in JS. - p = Pattern.compile("""lstImages.push\((.*)\);""") - m = p.matcher(body) - - var i = 0 - while (m.find()) { - val url = it.evaluate(m.group(1)) as String - pages.add(Page(i++, "", url)) - } - } - - return pages - } - - override fun pageListParse(document: Document): List { - throw Exception("Not used") - } - - override fun imageUrlRequest(page: Page) = GET(page.url) - - override fun imageUrlParse(document: Document) = "" - - private class Status : Filter.TriState("Completed") - private class Author : Filter.Text("Author") - private class Genre(name: String) : Filter.TriState(name) - private class GenreList(genres: List) : Filter.Group("Genres", genres) - - override fun getFilterList() = FilterList( - Author(), - Status(), - GenreList(getGenreList()) - ) - - // $("select[name=\"genres\"]").map((i,el) => `Genre("${$(el).next().text().trim()}", ${i})`).get().join(',\n') - // on http://kissmanga.com/AdvanceSearch - private fun getGenreList() = listOf( - Genre("4-Koma"), - Genre("Action"), - Genre("Adult"), - Genre("Adventure"), - Genre("Comedy"), - Genre("Comic"), - Genre("Cooking"), - Genre("Doujinshi"), - Genre("Drama"), - Genre("Ecchi"), - Genre("Fantasy"), - Genre("Gender Bender"), - Genre("Harem"), - Genre("Historical"), - Genre("Horror"), - Genre("Josei"), - Genre("Lolicon"), - Genre("Manga"), - Genre("Manhua"), - Genre("Manhwa"), - Genre("Martial Arts"), - Genre("Mature"), - Genre("Mecha"), - Genre("Medical"), - Genre("Music"), - Genre("Mystery"), - Genre("One shot"), - Genre("Psychological"), - Genre("Romance"), - Genre("School Life"), - Genre("Sci-fi"), - Genre("Seinen"), - Genre("Shotacon"), - Genre("Shoujo"), - Genre("Shoujo Ai"), - Genre("Shounen"), - Genre("Shounen Ai"), - Genre("Slice of Life"), - Genre("Smut"), - Genre("Sports"), - Genre("Supernatural"), - Genre("Tragedy"), - Genre("Webtoon"), - Genre("Yaoi"), - Genre("Yuri") - ) -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/english/Mangafox.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/english/Mangafox.kt deleted file mode 100644 index e41a4775a3..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/source/online/english/Mangafox.kt +++ /dev/null @@ -1,231 +0,0 @@ -package eu.kanade.tachiyomi.source.online.english - -import eu.kanade.tachiyomi.network.GET -import eu.kanade.tachiyomi.source.model.* -import eu.kanade.tachiyomi.source.online.ParsedHttpSource -import okhttp3.HttpUrl -import okhttp3.Request -import org.jsoup.nodes.Document -import org.jsoup.nodes.Element -import java.text.ParseException -import java.text.SimpleDateFormat -import java.util.* - -class Mangafox : ParsedHttpSource() { - - override val id: Long = 3 - - override val name = "Mangafox" - - override val baseUrl = "http://mangafox.la" - - override val lang = "en" - - override val supportsLatest = true - - override fun popularMangaSelector() = "div#mangalist > ul.list > li" - - override fun popularMangaRequest(page: Int): Request { - val pageStr = if (page != 1) "$page.htm" else "" - return GET("$baseUrl/directory/$pageStr", headers) - } - - override fun latestUpdatesSelector() = "div#mangalist > ul.list > li" - - override fun latestUpdatesRequest(page: Int): Request { - val pageStr = if (page != 1) "$page.htm" else "" - return GET("$baseUrl/directory/$pageStr?latest") - } - - override fun popularMangaFromElement(element: Element): SManga { - val manga = SManga.create() - element.select("a.title").first().let { - manga.setUrlWithoutDomain(it.attr("href")) - manga.title = it.text() - } - return manga - } - - override fun latestUpdatesFromElement(element: Element): SManga { - return popularMangaFromElement(element) - } - - override fun popularMangaNextPageSelector() = "a:has(span.next)" - - override fun latestUpdatesNextPageSelector() = "a:has(span.next)" - - override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { - val url = HttpUrl.parse("$baseUrl/search.php?name_method=cw&author_method=cw&artist_method=cw&advopts=1")!!.newBuilder().addQueryParameter("name", query) - (if (filters.isEmpty()) getFilterList() else filters).forEach { filter -> - when (filter) { - is Status -> url.addQueryParameter(filter.id, filter.state.toString()) - is GenreList -> filter.state.forEach { genre -> url.addQueryParameter(genre.id, genre.state.toString()) } - is TextField -> url.addQueryParameter(filter.key, filter.state) - is Type -> url.addQueryParameter("type", if (filter.state == 0) "" else filter.state.toString()) - is OrderBy -> { - url.addQueryParameter("sort", arrayOf("name", "rating", "views", "total_chapters", "last_chapter_time")[filter.state!!.index]) - url.addQueryParameter("order", if (filter.state?.ascending == true) "az" else "za") - } - } - } - url.addQueryParameter("page", page.toString()) - return GET(url.toString(), headers) - } - - override fun searchMangaSelector() = "div#mangalist > ul.list > li" - - override fun searchMangaFromElement(element: Element): SManga { - val manga = SManga.create() - element.select("a.title").first().let { - manga.setUrlWithoutDomain(it.attr("href")) - manga.title = it.text() - } - return manga - } - - override fun searchMangaNextPageSelector() = "a:has(span.next)" - - override fun mangaDetailsParse(document: Document): SManga { - val infoElement = document.select("div#title").first() - val rowElement = infoElement.select("table > tbody > tr:eq(1)").first() - val sideInfoElement = document.select("#series_info").first() - val licensedElement = document.select("div.warning").first() - - val manga = SManga.create() - manga.author = rowElement.select("td:eq(1)").first()?.text() - manga.artist = rowElement.select("td:eq(2)").first()?.text() - manga.genre = rowElement.select("td:eq(3)").first()?.text() - manga.description = infoElement.select("p.summary").first()?.text() - val isLicensed = licensedElement?.text()?.contains("licensed") - if (isLicensed == true) { - manga.status = SManga.LICENSED - } else { - manga.status = sideInfoElement.select(".data").first()?.text().orEmpty().let { parseStatus(it) } - } - - manga.thumbnail_url = sideInfoElement.select("div.cover > img").first()?.attr("src") - return manga - } - - private fun parseStatus(status: String) = when { - status.contains("Ongoing") -> SManga.ONGOING - status.contains("Completed") -> SManga.COMPLETED - else -> SManga.UNKNOWN - } - - override fun chapterListSelector() = "div#chapters li div" - - override fun chapterFromElement(element: Element): SChapter { - val urlElement = element.select("a.tips").first() - - val chapter = SChapter.create() - chapter.setUrlWithoutDomain(urlElement.attr("href")) - chapter.name = element.select("span.title.nowrap").first()?.text()?.let { urlElement.text() + " - " + it } ?: urlElement.text() - chapter.date_upload = element.select("span.date").first()?.text()?.let { parseChapterDate(it) } ?: 0 - return chapter - } - - private fun parseChapterDate(date: String): Long { - return if ("Today" in date || " ago" in date) { - Calendar.getInstance().apply { - set(Calendar.HOUR_OF_DAY, 0) - set(Calendar.MINUTE, 0) - set(Calendar.SECOND, 0) - set(Calendar.MILLISECOND, 0) - }.timeInMillis - } else if ("Yesterday" in date) { - Calendar.getInstance().apply { - add(Calendar.DATE, -1) - set(Calendar.HOUR_OF_DAY, 0) - set(Calendar.MINUTE, 0) - set(Calendar.SECOND, 0) - set(Calendar.MILLISECOND, 0) - }.timeInMillis - } else { - try { - SimpleDateFormat("MMM d, yyyy", Locale.ENGLISH).parse(date).time - } catch (e: ParseException) { - 0L - } - } - } - - override fun pageListParse(document: Document): List { - val url = document.baseUri().substringBeforeLast('/') - - val pages = mutableListOf() - document.select("select.m").first()?.select("option:not([value=0])")?.forEach { - pages.add(Page(pages.size, "$url/${it.attr("value")}.html")) - } - return pages - } - - override fun imageUrlParse(document: Document): String { - val url = document.getElementById("image").attr("src") - return if ("compressed?token=" !in url) { - url - } else { - "http://mangafox.me/media/logo.png" - } - } - - private class Status(val id: String = "is_completed") : Filter.TriState("Completed") - private class Genre(name: String, val id: String = "genres[$name]") : Filter.TriState(name) - private class TextField(name: String, val key: String) : Filter.Text(name) - private class Type : Filter.Select("Type", arrayOf("Any", "Japanese Manga", "Korean Manhwa", "Chinese Manhua")) - private class OrderBy : Filter.Sort("Order by", - arrayOf("Series name", "Rating", "Views", "Total chapters", "Last chapter"), - Filter.Sort.Selection(2, false)) - - private class GenreList(genres: List) : Filter.Group("Genres", genres) - - override fun getFilterList() = FilterList( - TextField("Author", "author"), - TextField("Artist", "artist"), - Type(), - Status(), - OrderBy(), - GenreList(getGenreList()) - ) - - // $('select.genres').map((i,el)=>`Genre("${$(el).next().text().trim()}", "${$(el).attr('name')}")`).get().join(',\n') - // on http://mangafox.me/search.php - private fun getGenreList() = listOf( - Genre("Action"), - Genre("Adult"), - Genre("Adventure"), - Genre("Comedy"), - Genre("Doujinshi"), - Genre("Drama"), - Genre("Ecchi"), - Genre("Fantasy"), - Genre("Gender Bender"), - Genre("Harem"), - Genre("Historical"), - Genre("Horror"), - Genre("Josei"), - Genre("Martial Arts"), - Genre("Mature"), - Genre("Mecha"), - Genre("Mystery"), - Genre("One Shot"), - Genre("Psychological"), - Genre("Romance"), - Genre("School Life"), - Genre("Sci-fi"), - Genre("Seinen"), - Genre("Shoujo"), - Genre("Shoujo Ai"), - Genre("Shounen"), - Genre("Shounen Ai"), - Genre("Slice of Life"), - Genre("Smut"), - Genre("Sports"), - Genre("Supernatural"), - Genre("Tragedy"), - Genre("Webtoons"), - Genre("Yaoi"), - Genre("Yuri") - ) - -} \ No newline at end of file diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/english/Mangahere.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/english/Mangahere.kt deleted file mode 100644 index a9ec1f083b..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/source/online/english/Mangahere.kt +++ /dev/null @@ -1,259 +0,0 @@ -package eu.kanade.tachiyomi.source.online.english - -import eu.kanade.tachiyomi.network.GET -import eu.kanade.tachiyomi.source.model.* -import eu.kanade.tachiyomi.source.online.ParsedHttpSource -import okhttp3.HttpUrl -import okhttp3.Request -import org.jsoup.nodes.Document -import org.jsoup.nodes.Element -import java.security.SecureRandom -import java.security.cert.X509Certificate -import java.text.ParseException -import java.text.SimpleDateFormat -import java.util.* -import javax.net.ssl.SSLContext -import javax.net.ssl.X509TrustManager - -class Mangahere : ParsedHttpSource() { - - override val id: Long = 2 - - override val name = "Mangahere" - - override val baseUrl = "http://www.mangahere.cc" - - override val lang = "en" - - override val supportsLatest = true - - private val trustManager = object : X509TrustManager { - override fun getAcceptedIssuers(): Array { - return emptyArray() - } - - override fun checkClientTrusted(chain: Array, authType: String) { - } - - override fun checkServerTrusted(chain: Array, authType: String) { - } - } - - private val sslContext = SSLContext.getInstance("SSL").apply { - init(null, arrayOf(trustManager), SecureRandom()) - } - - override val client = super.client.newBuilder() - .sslSocketFactory(sslContext.socketFactory, trustManager) - .build() - - override fun popularMangaSelector() = "div.directory_list > ul > li" - - override fun latestUpdatesSelector() = "div.directory_list > ul > li" - - override fun popularMangaRequest(page: Int): Request { - return GET("$baseUrl/directory/$page.htm?views.za", headers) - } - - override fun latestUpdatesRequest(page: Int): Request { - return GET("$baseUrl/directory/$page.htm?last_chapter_time.za", headers) - } - - private fun mangaFromElement(query: String, element: Element): SManga { - val manga = SManga.create() - element.select(query).first().let { - manga.setUrlWithoutDomain(it.attr("href")) - manga.title = if (it.hasAttr("title")) it.attr("title") else if (it.hasAttr("rel")) it.attr("rel") else it.text() - } - return manga - } - - override fun popularMangaFromElement(element: Element): SManga { - return mangaFromElement("div.title > a", element) - } - - override fun latestUpdatesFromElement(element: Element): SManga { - return popularMangaFromElement(element) - } - - override fun popularMangaNextPageSelector() = "div.next-page > a.next" - - override fun latestUpdatesNextPageSelector() = "div.next-page > a.next" - - override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { - val url = HttpUrl.parse("$baseUrl/search.php?name_method=cw&author_method=cw&artist_method=cw&advopts=1")!!.newBuilder().addQueryParameter("name", query) - (if (filters.isEmpty()) getFilterList() else filters).forEach { filter -> - when (filter) { - is Status -> url.addQueryParameter("is_completed", arrayOf("", "1", "0")[filter.state]) - is GenreList -> filter.state.forEach { genre -> url.addQueryParameter(genre.id, genre.state.toString()) } - is TextField -> url.addQueryParameter(filter.key, filter.state) - is Type -> url.addQueryParameter("direction", arrayOf("", "rl", "lr")[filter.state]) - is OrderBy -> { - url.addQueryParameter("sort", arrayOf("name", "rating", "views", "total_chapters", "last_chapter_time")[filter.state!!.index]) - url.addQueryParameter("order", if (filter.state?.ascending == true) "az" else "za") - } - } - } - url.addQueryParameter("page", page.toString()) - return GET(url.toString(), headers) - } - - override fun searchMangaSelector() = "div.result_search > dl:has(dt)" - - override fun searchMangaFromElement(element: Element): SManga { - return mangaFromElement("a.manga_info", element) - } - - override fun searchMangaNextPageSelector() = "div.next-page > a.next" - - override fun mangaDetailsParse(document: Document): SManga { - val detailElement = document.select(".manga_detail_top").first() - val infoElement = detailElement.select(".detail_topText").first() - val licensedElement = document.select(".mt10.color_ff00.mb10").first() - - val manga = SManga.create() - manga.author = infoElement.select("a[href*=author/]").first()?.text() - manga.artist = infoElement.select("a[href*=artist/]").first()?.text() - manga.genre = infoElement.select("li:eq(3)").first()?.text()?.substringAfter("Genre(s):") - manga.description = infoElement.select("#show").first()?.text()?.substringBeforeLast("Show less") - manga.thumbnail_url = detailElement.select("img.img").first()?.attr("src") - - if (licensedElement?.text()?.contains("licensed") == true) { - manga.status = SManga.LICENSED - } else { - manga.status = infoElement.select("li:eq(6)").first()?.text().orEmpty().let { parseStatus(it) } - } - - return manga - } - - private fun parseStatus(status: String) = when { - status.contains("Ongoing") -> SManga.ONGOING - status.contains("Completed") -> SManga.COMPLETED - else -> SManga.UNKNOWN - } - - override fun chapterListSelector() = ".detail_list > ul:not([class]) > li" - - override fun chapterFromElement(element: Element): SChapter { - val parentEl = element.select("span.left").first() - - val urlElement = parentEl.select("a").first() - - var volume = parentEl.select("span.mr6")?.first()?.text()?.trim() ?: "" - if (volume.length > 0) { - volume = " - " + volume - } - - var title = parentEl?.textNodes()?.last()?.text()?.trim() ?: "" - if (title.length > 0) { - title = " - " + title - } - - val chapter = SChapter.create() - chapter.setUrlWithoutDomain(urlElement.attr("href")) - chapter.name = urlElement.text() + volume + title - chapter.date_upload = element.select("span.right").first()?.text()?.let { parseChapterDate(it) } ?: 0 - return chapter - } - - private fun parseChapterDate(date: String): Long { - return if ("Today" in date) { - Calendar.getInstance().apply { - set(Calendar.HOUR_OF_DAY, 0) - set(Calendar.MINUTE, 0) - set(Calendar.SECOND, 0) - set(Calendar.MILLISECOND, 0) - }.timeInMillis - } else if ("Yesterday" in date) { - Calendar.getInstance().apply { - add(Calendar.DATE, -1) - set(Calendar.HOUR_OF_DAY, 0) - set(Calendar.MINUTE, 0) - set(Calendar.SECOND, 0) - set(Calendar.MILLISECOND, 0) - }.timeInMillis - } else { - try { - SimpleDateFormat("MMM d, yyyy", Locale.ENGLISH).parse(date).time - } catch (e: ParseException) { - 0L - } - } - } - - override fun pageListParse(document: Document): List { - val licensedError = document.select(".mangaread_error > .mt10").first() - if (licensedError != null) { - throw Exception(licensedError.text()) - } - - val pages = mutableListOf() - document.select("select.wid60").first()?.getElementsByTag("option")?.forEach { - if (!it.attr("value").contains("featured.html")) { - pages.add(Page(pages.size, "http:" + it.attr("value"))) - } - } - pages.getOrNull(0)?.imageUrl = imageUrlParse(document) - return pages - } - - override fun imageUrlParse(document: Document) = document.getElementById("image").attr("src") - - private class Status : Filter.TriState("Completed") - private class Genre(name: String, val id: String = "genres[$name]") : Filter.TriState(name) - private class TextField(name: String, val key: String) : Filter.Text(name) - private class Type : Filter.Select("Type", arrayOf("Any", "Japanese Manga (read from right to left)", "Korean Manhwa (read from left to right)")) - private class OrderBy : Filter.Sort("Order by", - arrayOf("Series name", "Rating", "Views", "Total chapters", "Last chapter"), - Filter.Sort.Selection(2, false)) - - private class GenreList(genres: List) : Filter.Group("Genres", genres) - - override fun getFilterList() = FilterList( - TextField("Author", "author"), - TextField("Artist", "artist"), - Type(), - Status(), - OrderBy(), - GenreList(getGenreList()) - ) - - // [...document.querySelectorAll("select[id^='genres'")].map((el,i) => `Genre("${el.nextSibling.nextSibling.textContent.trim()}", "${el.getAttribute('name')}")`).join(',\n') - // http://www.mangahere.co/advsearch.htm - private fun getGenreList() = listOf( - Genre("Action"), - Genre("Adventure"), - Genre("Comedy"), - Genre("Doujinshi"), - Genre("Drama"), - Genre("Ecchi"), - Genre("Fantasy"), - Genre("Gender Bender"), - Genre("Harem"), - Genre("Historical"), - Genre("Horror"), - Genre("Josei"), - Genre("Martial Arts"), - Genre("Mature"), - Genre("Mecha"), - Genre("Mystery"), - Genre("One Shot"), - Genre("Psychological"), - Genre("Romance"), - Genre("School Life"), - Genre("Sci-fi"), - Genre("Seinen"), - Genre("Shoujo"), - Genre("Shoujo Ai"), - Genre("Shounen"), - Genre("Shounen Ai"), - Genre("Slice of Life"), - Genre("Sports"), - Genre("Supernatural"), - Genre("Tragedy"), - Genre("Yaoi"), - Genre("Yuri") - ) - -} \ No newline at end of file diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/english/Mangasee.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/english/Mangasee.kt deleted file mode 100644 index a79b356aca..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/source/online/english/Mangasee.kt +++ /dev/null @@ -1,249 +0,0 @@ -package eu.kanade.tachiyomi.source.online.english - -import eu.kanade.tachiyomi.network.POST -import eu.kanade.tachiyomi.source.model.* -import eu.kanade.tachiyomi.source.online.ParsedHttpSource -import okhttp3.FormBody -import okhttp3.Headers -import okhttp3.HttpUrl -import okhttp3.Request -import org.jsoup.nodes.Document -import org.jsoup.nodes.Element -import java.text.SimpleDateFormat -import java.util.regex.Pattern - -class Mangasee : ParsedHttpSource() { - - override val id: Long = 9 - - override val name = "Mangasee" - - override val baseUrl = "http://mangaseeonline.us" - - override val lang = "en" - - override val supportsLatest = true - - private val recentUpdatesPattern = Pattern.compile("(.*?)\\s(\\d+\\.?\\d*)\\s?(Completed)?") - - private val indexPattern = Pattern.compile("-index-(.*?)-") - - private val catalogHeaders = Headers.Builder().apply { - add("User-Agent", "Mozilla/5.0 (Windows NT 6.3; WOW64)") - add("Host", "mangaseeonline.us") - }.build() - - override fun popularMangaSelector() = "div.requested > div.row" - - override fun popularMangaRequest(page: Int): Request { - val (body, requestUrl) = convertQueryToPost(page, "$baseUrl/search/request.php?sortBy=popularity&sortOrder=descending") - return POST(requestUrl, catalogHeaders, body.build()) - } - - override fun popularMangaFromElement(element: Element): SManga { - val manga = SManga.create() - element.select("a.resultLink").first().let { - manga.setUrlWithoutDomain(it.attr("href")) - manga.title = it.text() - } - return manga - } - - override fun popularMangaNextPageSelector() = "button.requestMore" - - override fun searchMangaSelector() = "div.requested > div.row" - - override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { - val url = HttpUrl.parse("$baseUrl/search/request.php")!!.newBuilder() - if (!query.isEmpty()) url.addQueryParameter("keyword", query) - val genres = mutableListOf() - val genresNo = mutableListOf() - for (filter in if (filters.isEmpty()) getFilterList() else filters) { - when (filter) { - is Sort -> { - if (filter.state?.index != 0) - url.addQueryParameter("sortBy", if (filter.state?.index == 1) "dateUpdated" else "popularity") - if (filter.state?.ascending != true) - url.addQueryParameter("sortOrder", "descending") - } - is SelectField -> if (filter.state != 0) url.addQueryParameter(filter.key, filter.values[filter.state]) - is TextField -> if (!filter.state.isEmpty()) url.addQueryParameter(filter.key, filter.state) - is GenreList -> filter.state.forEach { genre -> - when (genre.state) { - Filter.TriState.STATE_INCLUDE -> genres.add(genre.name) - Filter.TriState.STATE_EXCLUDE -> genresNo.add(genre.name) - } - } - } - } - if (genres.isNotEmpty()) url.addQueryParameter("genre", genres.joinToString(",")) - if (genresNo.isNotEmpty()) url.addQueryParameter("genreNo", genresNo.joinToString(",")) - - val (body, requestUrl) = convertQueryToPost(page, url.toString()) - return POST(requestUrl, catalogHeaders, body.build()) - } - - private fun convertQueryToPost(page: Int, url: String): Pair { - val url = HttpUrl.parse(url)!! - val body = FormBody.Builder().add("page", page.toString()) - for (i in 0..url.querySize() - 1) { - body.add(url.queryParameterName(i), url.queryParameterValue(i)) - } - val requestUrl = url.scheme() + "://" + url.host() + url.encodedPath() - return Pair(body, requestUrl) - } - - override fun searchMangaFromElement(element: Element): SManga { - val manga = SManga.create() - element.select("a.resultLink").first().let { - manga.setUrlWithoutDomain(it.attr("href")) - manga.title = it.text() - } - return manga - } - - override fun searchMangaNextPageSelector() = "button.requestMore" - - override fun mangaDetailsParse(document: Document): SManga { - val detailElement = document.select("div.well > div.row").first() - - val manga = SManga.create() - manga.author = detailElement.select("a[href^=/search/?author=]").first()?.text() - manga.genre = detailElement.select("span.details > div.row > div:has(b:contains(Genre(s))) > a").map { it.text() }.joinToString() - manga.description = detailElement.select("strong:contains(Description:) + div").first()?.text() - manga.status = detailElement.select("a[href^=/search/?status=]").first()?.text().orEmpty().let { parseStatus(it) } - manga.thumbnail_url = detailElement.select("div > img").first()?.absUrl("src") - return manga - } - - private fun parseStatus(status: String) = when { - status.contains("Ongoing (Scan)") -> SManga.ONGOING - status.contains("Complete (Scan)") -> SManga.COMPLETED - else -> SManga.UNKNOWN - } - - override fun chapterListSelector() = "div.chapter-list > a" - - override fun chapterFromElement(element: Element): SChapter { - val urlElement = element.select("a").first() - - val chapter = SChapter.create() - chapter.setUrlWithoutDomain(urlElement.attr("href")) - chapter.name = element.select("span.chapterLabel").first().text()?.let { it } ?: "" - chapter.date_upload = element.select("time").first()?.attr("datetime")?.let { parseChapterDate(it) } ?: 0 - return chapter - } - - private fun parseChapterDate(dateAsString: String): Long { - return SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").parse(dateAsString).time - } - - override fun pageListParse(document: Document): List { - val fullUrl = document.baseUri() - val url = fullUrl.substringBeforeLast('/') - - val pages = mutableListOf() - - val series = document.select("input.IndexName").first().attr("value") - val chapter = document.select("span.CurChapter").first().text() - var index = "" - - val m = indexPattern.matcher(fullUrl) - if (m.find()) { - val indexNumber = m.group(1) - index = "-index-$indexNumber" - } - - document.select("div.ContainerNav").first().select("select.PageSelect > option").forEach { - pages.add(Page(pages.size, "$url/$series-chapter-$chapter$index-page-${pages.size + 1}.html")) - } - pages.getOrNull(0)?.imageUrl = imageUrlParse(document) - return pages - } - - override fun imageUrlParse(document: Document): String = document.select("img.CurImage").attr("src") - - override fun latestUpdatesNextPageSelector() = "button.requestMore" - - override fun latestUpdatesSelector(): String = "a.latestSeries" - - override fun latestUpdatesRequest(page: Int): Request { - val url = "http://mangaseeonline.net/home/latest.request.php" - val (body, requestUrl) = convertQueryToPost(page, url) - return POST(requestUrl, catalogHeaders, body.build()) - } - - override fun latestUpdatesFromElement(element: Element): SManga { - val manga = SManga.create() - element.select("a.latestSeries").first().let { - val chapterUrl = it.attr("href") - val indexOfMangaUrl = chapterUrl.indexOf("-chapter-") - val indexOfLastPath = chapterUrl.lastIndexOf("/") - val mangaUrl = chapterUrl.substring(indexOfLastPath, indexOfMangaUrl) - val defaultText = it.select("p.clamp2").text() - val m = recentUpdatesPattern.matcher(defaultText) - val title = if (m.matches()) m.group(1) else defaultText - manga.setUrlWithoutDomain("/manga" + mangaUrl) - manga.title = title - } - return manga - } - - private class Sort : Filter.Sort("Sort", arrayOf("Alphabetically", "Date updated", "Popularity"), Filter.Sort.Selection(2, false)) - private class Genre(name: String) : Filter.TriState(name) - private class TextField(name: String, val key: String) : Filter.Text(name) - private class SelectField(name: String, val key: String, values: Array, state: Int = 0) : Filter.Select(name, values, state) - private class GenreList(genres: List) : Filter.Group("Genres", genres) - - override fun getFilterList() = FilterList( - TextField("Years", "year"), - TextField("Author", "author"), - SelectField("Scan Status", "status", arrayOf("Any", "Complete", "Discontinued", "Hiatus", "Incomplete", "Ongoing")), - SelectField("Publish Status", "pstatus", arrayOf("Any", "Cancelled", "Complete", "Discontinued", "Hiatus", "Incomplete", "Ongoing", "Unfinished")), - SelectField("Type", "type", arrayOf("Any", "Doujinshi", "Manga", "Manhua", "Manhwa", "OEL", "One-shot")), - Sort(), - GenreList(getGenreList()) - ) - - // [...document.querySelectorAll("label.triStateCheckBox input")].map(el => `Filter("${el.getAttribute('name')}", "${el.nextSibling.textContent.trim()}")`).join(',\n') - // http://mangasee.co/advanced-search/ - private fun getGenreList() = listOf( - Genre("Action"), - Genre("Adult"), - Genre("Adventure"), - Genre("Comedy"), - Genre("Doujinshi"), - Genre("Drama"), - Genre("Ecchi"), - Genre("Fantasy"), - Genre("Gender Bender"), - Genre("Harem"), - Genre("Hentai"), - Genre("Historical"), - Genre("Horror"), - Genre("Josei"), - Genre("Lolicon"), - Genre("Martial Arts"), - Genre("Mature"), - Genre("Mecha"), - Genre("Mystery"), - Genre("Psychological"), - Genre("Romance"), - Genre("School Life"), - Genre("Sci-fi"), - Genre("Seinen"), - Genre("Shotacon"), - Genre("Shoujo"), - Genre("Shoujo Ai"), - Genre("Shounen"), - Genre("Shounen Ai"), - Genre("Slice of Life"), - Genre("Smut"), - Genre("Sports"), - Genre("Supernatural"), - Genre("Tragedy"), - Genre("Yaoi"), - Genre("Yuri") - ) - -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/english/Readmangatoday.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/english/Readmangatoday.kt deleted file mode 100644 index 49c10456c1..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/source/online/english/Readmangatoday.kt +++ /dev/null @@ -1,224 +0,0 @@ -package eu.kanade.tachiyomi.source.online.english - -import eu.kanade.tachiyomi.network.GET -import eu.kanade.tachiyomi.network.POST -import eu.kanade.tachiyomi.source.model.* -import eu.kanade.tachiyomi.source.online.ParsedHttpSource -import okhttp3.Headers -import okhttp3.OkHttpClient -import okhttp3.Request -import org.jsoup.nodes.Document -import org.jsoup.nodes.Element -import java.util.* - -class Readmangatoday : ParsedHttpSource() { - - override val id: Long = 8 - - override val name = "ReadMangaToday" - - override val baseUrl = "https://www.readmng.com" - - override val lang = "en" - - override val supportsLatest = true - - override val client: OkHttpClient get() = network.cloudflareClient - - /** - * Search only returns data with this set - */ - override fun headersBuilder() = Headers.Builder().apply { - add("User-Agent", "Mozilla/5.0 (Windows NT 6.3; WOW64)") - add("X-Requested-With", "XMLHttpRequest") - } - - override fun popularMangaRequest(page: Int): Request { - return GET("$baseUrl/hot-manga/$page", headers) - } - - override fun latestUpdatesRequest(page: Int): Request { - return GET("$baseUrl/latest-releases/$page", headers) - } - - override fun popularMangaSelector() = "div.hot-manga > div.style-list > div.box" - - override fun latestUpdatesSelector() = "div.hot-manga > div.style-grid > div.box" - - override fun popularMangaFromElement(element: Element): SManga { - val manga = SManga.create() - element.select("div.title > h2 > a").first().let { - manga.setUrlWithoutDomain(it.attr("href")) - manga.title = it.attr("title") - } - return manga - } - - override fun latestUpdatesFromElement(element: Element): SManga { - return popularMangaFromElement(element) - } - - override fun popularMangaNextPageSelector() = "div.hot-manga > ul.pagination > li > a:contains(»)" - - override fun latestUpdatesNextPageSelector() = "div.hot-manga > ul.pagination > li > a:contains(»)" - - override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { - val builder = okhttp3.FormBody.Builder() - builder.add("manga-name", query) - (if (filters.isEmpty()) getFilterList() else filters).forEach { filter -> - when (filter) { - is TextField -> builder.add(filter.key, filter.state) - is Type -> builder.add("type", arrayOf("all", "japanese", "korean", "chinese")[filter.state]) - is Status -> builder.add("status", arrayOf("both", "completed", "ongoing")[filter.state]) - is GenreList -> filter.state.forEach { genre -> - when (genre.state) { - Filter.TriState.STATE_INCLUDE -> builder.add("include[]", genre.id.toString()) - Filter.TriState.STATE_EXCLUDE -> builder.add("exclude[]", genre.id.toString()) - } - } - } - } - return POST("$baseUrl/service/advanced_search", headers, builder.build()) - } - - override fun searchMangaSelector() = "div.style-list > div.box" - - override fun searchMangaFromElement(element: Element): SManga { - val manga = SManga.create() - element.select("div.title > h2 > a").first().let { - manga.setUrlWithoutDomain(it.attr("href")) - manga.title = it.attr("title") - } - return manga - } - - override fun searchMangaNextPageSelector() = "div.next-page > a.next" - - override fun mangaDetailsParse(document: Document): SManga { - val detailElement = document.select("div.movie-meta").first() - val genreElement = detailElement.select("dl.dl-horizontal > dd:eq(5) a") - - val manga = SManga.create() - manga.author = document.select("ul.cast-list li.director > ul a").first()?.text() - manga.artist = document.select("ul.cast-list li:not(.director) > ul a").first()?.text() - manga.description = detailElement.select("li.movie-detail").first()?.text() - manga.status = detailElement.select("dl.dl-horizontal > dd:eq(3)").first()?.text().orEmpty().let { parseStatus(it) } - manga.thumbnail_url = detailElement.select("img.img-responsive").first()?.attr("src") - - var genres = mutableListOf() - genreElement?.forEach { genres.add(it.text()) } - manga.genre = genres.joinToString(", ") - - return manga - } - - private fun parseStatus(status: String) = when { - status.contains("Ongoing") -> SManga.ONGOING - status.contains("Completed") -> SManga.COMPLETED - else -> SManga.UNKNOWN - } - - override fun chapterListSelector() = "ul.chp_lst > li" - - override fun chapterFromElement(element: Element): SChapter { - val urlElement = element.select("a").first() - - val chapter = SChapter.create() - chapter.setUrlWithoutDomain(urlElement.attr("href")) - chapter.name = urlElement.select("span.val").text() - chapter.date_upload = element.select("span.dte").first()?.text()?.let { parseChapterDate(it) } ?: 0 - return chapter - } - - private fun parseChapterDate(date: String): Long { - val dateWords: List = date.split(" ") - - if (dateWords.size == 3) { - val timeAgo = Integer.parseInt(dateWords[0]) - val date: Calendar = Calendar.getInstance() - - if (dateWords[1].contains("Minute")) { - date.add(Calendar.MINUTE, -timeAgo) - } else if (dateWords[1].contains("Hour")) { - date.add(Calendar.HOUR_OF_DAY, -timeAgo) - } else if (dateWords[1].contains("Day")) { - date.add(Calendar.DAY_OF_YEAR, -timeAgo) - } else if (dateWords[1].contains("Week")) { - date.add(Calendar.WEEK_OF_YEAR, -timeAgo) - } else if (dateWords[1].contains("Month")) { - date.add(Calendar.MONTH, -timeAgo) - } else if (dateWords[1].contains("Year")) { - date.add(Calendar.YEAR, -timeAgo) - } - - return date.timeInMillis - } - - return 0L - } - - override fun pageListParse(document: Document): List { - val pages = mutableListOf() - document.select("ul.list-switcher-2 > li > select.jump-menu").first().getElementsByTag("option").forEach { - pages.add(Page(pages.size, it.attr("value"))) - } - pages.getOrNull(0)?.imageUrl = imageUrlParse(document) - return pages - } - - override fun imageUrlParse(document: Document) = document.select("#chapter_img").first().attr("src") - - private class Status : Filter.TriState("Completed") - private class Genre(name: String, val id: Int) : Filter.TriState(name) - private class TextField(name: String, val key: String) : Filter.Text(name) - private class Type : Filter.Select("Type", arrayOf("All", "Japanese Manga", "Korean Manhwa", "Chinese Manhua")) - private class GenreList(genres: List) : Filter.Group("Genres", genres) - - override fun getFilterList() = FilterList( - TextField("Author", "author-name"), - TextField("Artist", "artist-name"), - Type(), - Status(), - GenreList(getGenreList()) - ) - - // [...document.querySelectorAll("ul.manga-cat span")].map(el => `Genre("${el.nextSibling.textContent.trim()}", ${el.getAttribute('data-id')})`).join(',\n') - // http://www.readmanga.today/advanced-search - private fun getGenreList() = listOf( - Genre("Action", 2), - Genre("Adventure", 4), - Genre("Comedy", 5), - Genre("Doujinshi", 6), - Genre("Drama", 7), - Genre("Ecchi", 8), - Genre("Fantasy", 9), - Genre("Gender Bender", 10), - Genre("Harem", 11), - Genre("Historical", 12), - Genre("Horror", 13), - Genre("Josei", 14), - Genre("Lolicon", 15), - Genre("Martial Arts", 16), - Genre("Mature", 17), - Genre("Mecha", 18), - Genre("Mystery", 19), - Genre("One shot", 20), - Genre("Psychological", 21), - Genre("Romance", 22), - Genre("School Life", 23), - Genre("Sci-fi", 24), - Genre("Seinen", 25), - Genre("Shotacon", 26), - Genre("Shoujo", 27), - Genre("Shoujo Ai", 28), - Genre("Shounen", 29), - Genre("Shounen Ai", 30), - Genre("Slice of Life", 31), - Genre("Smut", 32), - Genre("Sports", 33), - Genre("Supernatural", 34), - Genre("Tragedy", 35), - Genre("Yaoi", 36), - Genre("Yuri", 37) - ) -} \ No newline at end of file diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/german/WieManga.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/german/WieManga.kt deleted file mode 100644 index b680ae9056..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/source/online/german/WieManga.kt +++ /dev/null @@ -1,122 +0,0 @@ -package eu.kanade.tachiyomi.source.online.german - -import eu.kanade.tachiyomi.network.GET -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.Request -import org.jsoup.nodes.Document -import org.jsoup.nodes.Element -import java.text.SimpleDateFormat - -class WieManga : ParsedHttpSource() { - - override val id: Long = 10 - - override val name = "Wie Manga!" - - override val baseUrl = "http://www.wiemanga.com" - - override val lang = "de" - - override val supportsLatest = true - - override fun popularMangaSelector() = ".booklist td > div" - - override fun latestUpdatesSelector() = ".booklist td > div" - - override fun popularMangaRequest(page: Int): Request { - return GET("$baseUrl/list/Hot-Book/", headers) - } - - override fun latestUpdatesRequest(page: Int): Request { - return GET("$baseUrl/list/New-Update/", headers) - } - - override fun popularMangaFromElement(element: Element): SManga { - val image = element.select("dt img") - val title = element.select("dd a:first-child") - - val manga = SManga.create() - manga.setUrlWithoutDomain(title.attr("href")) - manga.title = title.text() - manga.thumbnail_url = image.attr("src") - return manga - } - - override fun latestUpdatesFromElement(element: Element): SManga { - return popularMangaFromElement(element) - } - - override fun popularMangaNextPageSelector() = null - - override fun latestUpdatesNextPageSelector() = null - - override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { - return GET("$baseUrl/search/?wd=$query", headers) - } - - override fun searchMangaSelector() = ".searchresult td > div" - - override fun searchMangaFromElement(element: Element): SManga { - val image = element.select(".resultimg img") - val title = element.select(".resultbookname") - - val manga = SManga.create() - manga.setUrlWithoutDomain(title.attr("href")) - manga.title = title.text() - manga.thumbnail_url = image.attr("src") - return manga - } - - override fun searchMangaNextPageSelector() = ".pagetor a.l" - - override fun mangaDetailsParse(document: Document): SManga { - val imageElement = document.select(".bookmessgae tr > td:nth-child(1)").first() - val infoElement = document.select(".bookmessgae tr > td:nth-child(2)").first() - - val manga = SManga.create() - manga.author = infoElement.select("dd:nth-of-type(2) a").first()?.text() - manga.artist = infoElement.select("dd:nth-of-type(3) a").first()?.text() - manga.description = infoElement.select("dl > dt:last-child").first()?.text()?.replaceFirst("Beschreibung", "") - manga.thumbnail_url = imageElement.select("img").first()?.attr("src") - - if (manga.author == "RSS") - manga.author = null - - if (manga.artist == "RSS") - manga.artist = null - return manga - } - - override fun chapterListSelector() = ".chapterlist tr:not(:first-child)" - - override fun chapterFromElement(element: Element): SChapter { - val urlElement = element.select(".col1 a").first() - val dateElement = element.select(".col3 a").first() - - val chapter = SChapter.create() - chapter.setUrlWithoutDomain(urlElement.attr("href")) - chapter.name = urlElement.text() - chapter.date_upload = dateElement?.text()?.let { parseChapterDate(it) } ?: 0 - return chapter - } - - private fun parseChapterDate(date: String): Long { - return SimpleDateFormat("yyyy-MM-dd hh:mm:ss").parse(date).time - } - - override fun pageListParse(document: Document): List { - val pages = mutableListOf() - - document.select("select#page").first().select("option").forEach { - pages.add(Page(pages.size, it.attr("value"))) - } - return pages - } - - override fun imageUrlParse(document: Document) = document.select("img#comicpic").first().attr("src") - -} \ No newline at end of file diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/russian/Mangachan.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/russian/Mangachan.kt deleted file mode 100644 index 5f7f057f0a..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/source/online/russian/Mangachan.kt +++ /dev/null @@ -1,290 +0,0 @@ -package eu.kanade.tachiyomi.source.online.russian - -import eu.kanade.tachiyomi.network.GET -import eu.kanade.tachiyomi.source.model.* -import eu.kanade.tachiyomi.source.online.ParsedHttpSource -import eu.kanade.tachiyomi.util.asJsoup -import okhttp3.Request -import okhttp3.Response -import org.jsoup.nodes.Document -import org.jsoup.nodes.Element -import java.text.SimpleDateFormat -import java.util.* - -class Mangachan : ParsedHttpSource() { - - override val id: Long = 7 - - override val name = "Mangachan" - - override val baseUrl = "http://mangachan.me" - - override val lang = "ru" - - override val supportsLatest = true - - override fun popularMangaRequest(page: Int): Request = - GET("$baseUrl/mostfavorites?offset=${20 * (page - 1)}", headers) - - override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { - var pageNum = 1 - when { - page < 1 -> pageNum = 1 - page >= 1 -> pageNum = page - } - val url = if (query.isNotEmpty()) { - "$baseUrl/?do=search&subaction=search&story=$query&search_start=$pageNum" - } else { - - var genres = "" - var order = "" - var statusParam = true - var status = "" - for (filter in if (filters.isEmpty()) getFilterList() else filters) { - when (filter) { - is GenreList -> { - filter.state.forEach { f -> - if (!f.isIgnored()) { - genres += (if (f.isExcluded()) "-" else "") + f.id + '+' - } - } - } - is OrderBy -> { - if (filter.state!!.ascending && filter.state!!.index == 0) { - statusParam = false - } - } - is Status -> status = arrayOf("", "all_done", "end", "ongoing", "new_ch")[filter.state] - } - } - - if (genres.isNotEmpty()) { - for (filter in filters) { - when (filter) { - is OrderBy -> { - order = if (filter.state!!.ascending) { - arrayOf("", "&n=favasc", "&n=abcdesc", "&n=chasc")[filter.state!!.index] - } else { - arrayOf("&n=dateasc", "&n=favdesc", "&n=abcasc", "&n=chdesc")[filter.state!!.index] - } - } - } - } - if (statusParam) { - "$baseUrl/tags/${genres.dropLast(1)}$order?offset=${20 * (pageNum - 1)}&status=$status" - } else { - "$baseUrl/tags/$status/${genres.dropLast(1)}/$order?offset=${20 * (pageNum - 1)}" - } - } else { - for (filter in filters) { - when (filter) { - is OrderBy -> { - order = if (filter.state!!.ascending) { - arrayOf("manga/new", "manga/new&n=favasc", "manga/new&n=abcdesc", "manga/new&n=chasc")[filter.state!!.index] - } else { - arrayOf("manga/new&n=dateasc", "mostfavorites", "catalog", "sortch")[filter.state!!.index] - } - } - } - } - if (statusParam) { - "$baseUrl/$order?offset=${20 * (pageNum - 1)}&status=$status" - } else { - "$baseUrl/$order/$status?offset=${20 * (pageNum - 1)}" - } - } - } - return GET(url, headers) - } - - override fun latestUpdatesRequest(page: Int): Request = GET("$baseUrl/newestch?page=$page") - - override fun popularMangaSelector() = "div.content_row" - - override fun latestUpdatesSelector() = "ul.area_rightNews li" - - override fun searchMangaSelector() = popularMangaSelector() - - override fun popularMangaFromElement(element: Element): SManga { - val manga = SManga.create() - manga.thumbnail_url = element.select("div.manga_images img").first().attr("src") - element.select("h2 > a").first().let { - manga.setUrlWithoutDomain(it.attr("href")) - manga.title = it.text() - } - return manga - } - - override fun latestUpdatesFromElement(element: Element): SManga { - val manga = SManga.create() - element.select("a:nth-child(1)").first().let { - manga.setUrlWithoutDomain(it.attr("href")) - manga.title = it.text() - } - return manga - } - - override fun searchMangaFromElement(element: Element): SManga = popularMangaFromElement(element) - - override fun popularMangaNextPageSelector() = "a:contains(Вперед)" - - override fun latestUpdatesNextPageSelector() = popularMangaNextPageSelector() - - override fun searchMangaNextPageSelector() = "a:contains(Далее)" - - private fun searchGenresNextPageSelector() = popularMangaNextPageSelector() - - override fun searchMangaParse(response: Response): MangasPage { - val document = response.asJsoup() - var hasNextPage = false - - val mangas = document.select(searchMangaSelector()).map { element -> - searchMangaFromElement(element) - } - - val nextSearchPage = document.select(searchMangaNextPageSelector()) - if (nextSearchPage.isNotEmpty()) { - val query = document.select("input#searchinput").first().attr("value") - val pageNum = nextSearchPage.let { selector -> - val onClick = selector.attr("onclick") - onClick?.split("""\\d+""") - } - nextSearchPage.attr("href", "$baseUrl/?do=search&subaction=search&story=$query&search_start=$pageNum") - hasNextPage = true - } - - val nextGenresPage = document.select(searchGenresNextPageSelector()) - if (nextGenresPage.isNotEmpty()) { - hasNextPage = true - } - - return MangasPage(mangas, hasNextPage) - } - - override fun mangaDetailsParse(document: Document): SManga { - val infoElement = document.select("table.mangatitle").first() - val descElement = document.select("div#description").first() - val imgElement = document.select("img#cover").first() - - val manga = SManga.create() - manga.author = infoElement.select("tr:eq(2) > td:eq(1)").text() - manga.genre = infoElement.select("tr:eq(5) > td:eq(1)").text() - manga.status = parseStatus(infoElement.select("tr:eq(4) > td:eq(1)").text()) - manga.description = descElement.textNodes().first().text() - manga.thumbnail_url = imgElement.attr("src") - return manga - } - - private fun parseStatus(element: String): Int = when { - element.contains("перевод завершен") -> SManga.COMPLETED - element.contains("перевод продолжается") -> SManga.ONGOING - else -> SManga.UNKNOWN - } - - override fun chapterListSelector() = "table.table_cha tr:gt(1)" - - override fun chapterFromElement(element: Element): SChapter { - val urlElement = element.select("a").first() - - val chapter = SChapter.create() - chapter.setUrlWithoutDomain(urlElement.attr("href")) - chapter.name = urlElement.text() - chapter.date_upload = element.select("div.date").first()?.text()?.let { - SimpleDateFormat("yyyy-MM-dd", Locale.US).parse(it).time - } ?: 0 - return chapter - } - - override fun pageListParse(response: Response): List { - val html = response.body()!!.string() - val beginIndex = html.indexOf("fullimg\":[") + 10 - val endIndex = html.indexOf(",]", beginIndex) - val trimmedHtml = html.substring(beginIndex, endIndex).replace("\"", "") - val pageUrls = trimmedHtml.split(',') - - return pageUrls.mapIndexed { i, url -> Page(i, "", url) } - } - - override fun pageListParse(document: Document): List { - throw Exception("Not used") - } - - override fun imageUrlParse(document: Document) = "" - - private class GenreList(genres: List) : Filter.Group("Тэги", genres) - private class Genre(name: String, val id: String = name.replace(' ', '_')) : Filter.TriState(name) - private class Status : Filter.Select("Статус", arrayOf("Все", "Перевод завершен", "Выпуск завершен", "Онгоинг", "Новые главы")) - private class OrderBy : Filter.Sort("Сортировка", - arrayOf("Дата", "Популярность", "Имя", "Главы"), - Filter.Sort.Selection(1, false)) - - - override fun getFilterList() = FilterList( - Status(), - OrderBy(), - GenreList(getGenreList()) - ) - - - /* [...document.querySelectorAll("li.sidetag > a:nth-child(1)")] - * .map(el => `Genre("${el.getAttribute('href').substr(6)}")`).join(',\n') - * on http://mangachan.me/ - */ - private fun getGenreList() = listOf( - Genre("18_плюс"), - Genre("bdsm"), - Genre("арт"), - Genre("боевик"), - Genre("боевые_искусства"), - Genre("вампиры"), - Genre("веб"), - Genre("гарем"), - Genre("гендерная_интрига"), - Genre("героическое_фэнтези"), - Genre("детектив"), - Genre("дзёсэй"), - Genre("додзинси"), - Genre("драма"), - Genre("игра"), - Genre("инцест"), - Genre("искусство"), - Genre("история"), - Genre("киберпанк"), - Genre("кодомо"), - Genre("комедия"), - Genre("литРПГ"), - Genre("махо-сёдзё"), - Genre("меха"), - Genre("мистика"), - Genre("музыка"), - Genre("научная_фантастика"), - Genre("повседневность"), - Genre("постапокалиптика"), - Genre("приключения"), - Genre("психология"), - Genre("романтика"), - Genre("самурайский_боевик"), - Genre("сборник"), - Genre("сверхъестественное"), - Genre("сказка"), - Genre("спорт"), - Genre("супергерои"), - Genre("сэйнэн"), - Genre("сёдзё"), - Genre("сёдзё-ай"), - Genre("сёнэн"), - Genre("сёнэн-ай"), - Genre("тентакли"), - Genre("трагедия"), - Genre("триллер"), - Genre("ужасы"), - Genre("фантастика"), - Genre("фурри"), - Genre("фэнтези"), - Genre("школа"), - Genre("эротика"), - Genre("юри"), - Genre("яой"), - Genre("ёнкома") - ) -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/russian/Mintmanga.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/russian/Mintmanga.kt deleted file mode 100644 index 6a1b68e359..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/source/online/russian/Mintmanga.kt +++ /dev/null @@ -1,251 +0,0 @@ -package eu.kanade.tachiyomi.source.online.russian - -import eu.kanade.tachiyomi.network.GET -import eu.kanade.tachiyomi.source.model.* -import eu.kanade.tachiyomi.source.online.ParsedHttpSource -import okhttp3.Headers -import okhttp3.HttpUrl -import okhttp3.Request -import okhttp3.Response -import org.jsoup.nodes.Document -import org.jsoup.nodes.Element -import java.text.SimpleDateFormat -import java.util.* -import java.util.regex.Pattern - -class Mintmanga : ParsedHttpSource() { - - override val id: Long = 6 - - override val name = "Mintmanga" - - override val baseUrl = "http://mintmanga.com" - - override val lang = "ru" - - override val supportsLatest = true - - override fun popularMangaRequest(page: Int): Request = - GET("$baseUrl/list?sortType=rate&offset=${70 * (page - 1)}&max=70", headers) - - override fun latestUpdatesRequest(page: Int): Request = - GET("$baseUrl/list?sortType=updated&offset=${70 * (page - 1)}&max=70", headers) - - override fun popularMangaSelector() = "div.tile" - - override fun latestUpdatesSelector() = "div.tile" - - override fun popularMangaFromElement(element: Element): SManga { - val manga = SManga.create() - manga.thumbnail_url = element.select("img.lazy").first()?.attr("data-original") - element.select("h3 > a").first().let { - manga.setUrlWithoutDomain(it.attr("href")) - manga.title = it.attr("title") - } - return manga - } - - override fun latestUpdatesFromElement(element: Element): SManga = - popularMangaFromElement(element) - - override fun popularMangaNextPageSelector() = "a.nextLink" - - override fun latestUpdatesNextPageSelector() = "a.nextLink" - - override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { - val url = HttpUrl.parse("$baseUrl/search/advanced")!!.newBuilder() - (if (filters.isEmpty()) getFilterList() else filters).forEach { filter -> - when (filter) { - is GenreList -> filter.state.forEach { genre -> - if (genre.state != Filter.TriState.STATE_IGNORE) { - url.addQueryParameter(genre.id, arrayOf("=", "=in", "=ex")[genre.state]) - } - } - is Category -> filter.state.forEach { category -> - if (category.state != Filter.TriState.STATE_IGNORE) { - url.addQueryParameter(category.id, arrayOf("=", "=in", "=ex")[category.state]) - } - } - } - } - if (!query.isEmpty()) { - url.addQueryParameter("q", query) - } - return GET(url.toString().replace("=%3D", "="), headers) - } - - override fun searchMangaSelector() = popularMangaSelector() - - override fun searchMangaFromElement(element: Element): SManga = popularMangaFromElement(element) - - // max 200 results - override fun searchMangaNextPageSelector(): Nothing? = null - - override fun mangaDetailsParse(document: Document): SManga { - val infoElement = document.select("div.leftContent").first() - - val manga = SManga.create() - manga.author = infoElement.select("span.elem_author").first()?.text() - manga.genre = infoElement.select("span.elem_genre").text().replace(" ,", ",") - manga.description = infoElement.select("div.manga-description").text() - manga.status = parseStatus(infoElement.html()) - manga.thumbnail_url = infoElement.select("img").attr("data-full") - return manga - } - - private fun parseStatus(element: String): Int = when { - element.contains("

Запрещена публикация произведения по копирайту

") -> SManga.LICENSED - element.contains("

Сингл") || element.contains("Перевод: завершен") -> SManga.COMPLETED - element.contains("Перевод: продолжается") -> SManga.ONGOING - else -> SManga.UNKNOWN - } - - override fun chapterListSelector() = "div.chapters-link tbody tr" - - override fun chapterFromElement(element: Element): SChapter { - val urlElement = element.select("a").first() - val urlText = urlElement.text() - - val chapter = SChapter.create() - chapter.setUrlWithoutDomain(urlElement.attr("href") + "?mtr=1") - if (urlText.endsWith(" новое")) { - chapter.name = urlText.dropLast(6) - } else { - chapter.name = urlText - } - chapter.date_upload = element.select("td.hidden-xxs").last()?.text()?.let { - SimpleDateFormat("dd/MM/yy", Locale.US).parse(it).time - } ?: 0 - return chapter - } - - override fun prepareNewChapter(chapter: SChapter, manga: SManga) { - val basic = Regex("""\s*([0-9]+)(\s-\s)([0-9]+)\s*""") - val extra = Regex("""\s*([0-9]+\sЭкстра)\s*""") - val single = Regex("""\s*Сингл\s*""") - when { - basic.containsMatchIn(chapter.name) -> { - basic.find(chapter.name)?.let { - val number = it.groups[3]?.value!! - chapter.chapter_number = number.toFloat() - } - } - extra.containsMatchIn(chapter.name) -> // Extra chapters doesn't contain chapter number - chapter.chapter_number = -2f - single.containsMatchIn(chapter.name) -> // Oneshoots, doujinshi and other mangas with one chapter - chapter.chapter_number = 1f - } - } - - override fun pageListParse(response: Response): List { - val html = response.body()!!.string() - val beginIndex = html.indexOf("rm_h.init( [") - val endIndex = html.indexOf("], 0, false);", beginIndex) - val trimmedHtml = html.substring(beginIndex, endIndex) - - val p = Pattern.compile("'.*?','.*?',\".*?\"") - val m = p.matcher(trimmedHtml) - - val pages = mutableListOf() - - var i = 0 - while (m.find()) { - val urlParts = m.group().replace("[\"\']+".toRegex(), "").split(',') - val url = if (urlParts[1].isEmpty() && urlParts[2].startsWith("/static/")) { - baseUrl + urlParts[2] - } else { - urlParts[1] + urlParts[0] + urlParts[2] - } - pages.add(Page(i++, "", url)) - } - return pages - } - - override fun pageListParse(document: Document): List { - throw Exception("Not used") - } - - override fun imageUrlParse(document: Document) = "" - - override fun imageRequest(page: Page): Request { - val imgHeader = Headers.Builder().apply { - add("User-Agent", "Mozilla/5.0 (Windows NT 6.3; WOW64)") - add("Referer", baseUrl) - }.build() - return GET(page.imageUrl!!, imgHeader) - } - - private class Genre(name: String, val id: String) : Filter.TriState(name) - private class GenreList(genres: List) : Filter.Group("Genres", genres) - private class Category(categories: List) : Filter.Group("Category", categories) - - /* [...document.querySelectorAll("tr.advanced_option:nth-child(1) > td:nth-child(3) span.js-link")] - * .map(el => `Genre("${el.textContent.trim()}", "${el.getAttribute('onclick') - * .substr(31,el.getAttribute('onclick').length-33)"})`).join(',\n') - * on http://mintmanga.com/search/advanced - */ - override fun getFilterList() = FilterList( - Category(getCategoryList()), - GenreList(getGenreList()) - ) - - private fun getCategoryList() = listOf( - Genre("В цвете", "el_4614"), - Genre("Веб", "el_1355"), - Genre("Выпуск приостановлен", "el_5232"), - Genre("Ёнкома", "el_2741"), - Genre("Комикс западный", "el_1903"), - Genre("Комикс русский", "el_2173"), - Genre("Манхва", "el_1873"), - Genre("Маньхуа", "el_1875"), - Genre("Не Яой", "el_1874"), - Genre("Ранобэ", "el_5688"), - Genre("Сборник", "el_1348") - ) - - private fun getGenreList() = listOf( - Genre("арт", "el_2220"), - Genre("бара", "el_1353"), - Genre("боевик", "el_1346"), - Genre("боевые искусства", "el_1334"), - Genre("вампиры", "el_1339"), - Genre("гарем", "el_1333"), - Genre("гендерная интрига", "el_1347"), - Genre("героическое фэнтези", "el_1337"), - Genre("детектив", "el_1343"), - Genre("дзёсэй", "el_1349"), - Genre("додзинси", "el_1332"), - Genre("драма", "el_1310"), - Genre("игра", "el_5229"), - Genre("история", "el_1311"), - Genre("киберпанк", "el_1351"), - Genre("комедия", "el_1328"), - Genre("меха", "el_1318"), - Genre("мистика", "el_1324"), - Genre("научная фантастика", "el_1325"), - Genre("омегаверс", "el_5676"), - Genre("повседневность", "el_1327"), - Genre("постапокалиптика", "el_1342"), - Genre("приключения", "el_1322"), - Genre("психология", "el_1335"), - Genre("романтика", "el_1313"), - Genre("самурайский боевик", "el_1316"), - Genre("сверхъестественное", "el_1350"), - Genre("сёдзё", "el_1314"), - Genre("сёдзё-ай", "el_1320"), - Genre("сёнэн", "el_1326"), - Genre("сёнэн-ай", "el_1330"), - Genre("спорт", "el_1321"), - Genre("сэйнэн", "el_1329"), - Genre("трагедия", "el_1344"), - Genre("триллер", "el_1341"), - Genre("ужасы", "el_1317"), - Genre("фантастика", "el_1331"), - Genre("фэнтези", "el_1323"), - Genre("школа", "el_1319"), - Genre("эротика", "el_1340"), - Genre("этти", "el_1354"), - Genre("юри", "el_1315"), - Genre("яой", "el_1336") - ) -} \ No newline at end of file diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/online/russian/Readmanga.kt b/app/src/main/java/eu/kanade/tachiyomi/source/online/russian/Readmanga.kt deleted file mode 100644 index 3929c543f4..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/source/online/russian/Readmanga.kt +++ /dev/null @@ -1,247 +0,0 @@ -package eu.kanade.tachiyomi.source.online.russian - -import eu.kanade.tachiyomi.network.GET -import eu.kanade.tachiyomi.source.model.* -import eu.kanade.tachiyomi.source.online.ParsedHttpSource -import okhttp3.Headers -import okhttp3.HttpUrl -import okhttp3.Request -import okhttp3.Response -import org.jsoup.nodes.Document -import org.jsoup.nodes.Element -import java.text.SimpleDateFormat -import java.util.* -import java.util.regex.Pattern - -class Readmanga : ParsedHttpSource() { - - override val id: Long = 5 - - override val name = "Readmanga" - - override val baseUrl = "http://readmanga.me" - - override val lang = "ru" - - override val supportsLatest = true - - override fun popularMangaSelector() = "div.tile" - - override fun latestUpdatesSelector() = "div.tile" - - override fun popularMangaRequest(page: Int): Request = - GET("$baseUrl/list?sortType=rate&offset=${70 * (page - 1)}&max=70", headers) - - override fun latestUpdatesRequest(page: Int): Request = - GET("$baseUrl/list?sortType=updated&offset=${70 * (page - 1)}&max=70", headers) - - override fun popularMangaFromElement(element: Element): SManga { - val manga = SManga.create() - manga.thumbnail_url = element.select("img.lazy").first()?.attr("data-original") - element.select("h3 > a").first().let { - manga.setUrlWithoutDomain(it.attr("href")) - manga.title = it.attr("title") - } - return manga - } - - override fun latestUpdatesFromElement(element: Element): SManga = - popularMangaFromElement(element) - - override fun popularMangaNextPageSelector() = "a.nextLink" - - override fun latestUpdatesNextPageSelector() = "a.nextLink" - - override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { - val url = HttpUrl.parse("$baseUrl/search/advanced")!!.newBuilder() - (if (filters.isEmpty()) getFilterList() else filters).forEach { filter -> - when (filter) { - is GenreList -> filter.state.forEach { genre -> - if (genre.state != Filter.TriState.STATE_IGNORE) { - url.addQueryParameter(genre.id, arrayOf("=", "=in", "=ex")[genre.state]) - } - } - is Category -> filter.state.forEach { category -> - if (category.state != Filter.TriState.STATE_IGNORE) { - url.addQueryParameter(category.id, arrayOf("=", "=in", "=ex")[category.state]) - } - } - } - } - if (!query.isEmpty()) { - url.addQueryParameter("q", query) - } - return GET(url.toString().replace("=%3D", "="), headers) - } - - override fun searchMangaSelector() = popularMangaSelector() - - override fun searchMangaFromElement(element: Element): SManga = popularMangaFromElement(element) - - // max 200 results - override fun searchMangaNextPageSelector(): Nothing? = null - - override fun mangaDetailsParse(document: Document): SManga { - val infoElement = document.select("div.leftContent").first() - - val manga = SManga.create() - manga.author = infoElement.select("span.elem_author").first()?.text() - manga.genre = infoElement.select("span.elem_genre").text().replace(" ,", ",") - manga.description = infoElement.select("div.manga-description").text() - manga.status = parseStatus(infoElement.html()) - manga.thumbnail_url = infoElement.select("img").attr("data-full") - return manga - } - - private fun parseStatus(element: String): Int = when { - element.contains("

Запрещена публикация произведения по копирайту

") -> SManga.LICENSED - element.contains("

Сингл") || element.contains("Перевод: завершен") -> SManga.COMPLETED - element.contains("Перевод: продолжается") -> SManga.ONGOING - else -> SManga.UNKNOWN - } - - override fun chapterListSelector() = "div.chapters-link tbody tr" - - override fun chapterFromElement(element: Element): SChapter { - val urlElement = element.select("a").first() - val urlText = urlElement.text() - - val chapter = SChapter.create() - chapter.setUrlWithoutDomain(urlElement.attr("href") + "?mtr=1") - if (urlText.endsWith(" новое")) { - chapter.name = urlText.dropLast(6) - } else { - chapter.name = urlText - } - chapter.date_upload = element.select("td.hidden-xxs").last()?.text()?.let { - SimpleDateFormat("dd/MM/yy", Locale.US).parse(it).time - } ?: 0 - return chapter - } - - override fun prepareNewChapter(chapter: SChapter, manga: SManga) { - val basic = Regex("""\s*([0-9]+)(\s-\s)([0-9]+)\s*""") - val extra = Regex("""\s*([0-9]+\sЭкстра)\s*""") - val single = Regex("""\s*Сингл\s*""") - when { - basic.containsMatchIn(chapter.name) -> { - basic.find(chapter.name)?.let { - val number = it.groups[3]?.value!! - chapter.chapter_number = number.toFloat() - } - } - extra.containsMatchIn(chapter.name) -> // Extra chapters doesn't contain chapter number - chapter.chapter_number = -2f - single.containsMatchIn(chapter.name) -> // Oneshoots, doujinshi and other mangas with one chapter - chapter.chapter_number = 1f - } - } - - override fun pageListParse(response: Response): List { - val html = response.body()!!.string() - val beginIndex = html.indexOf("rm_h.init( [") - val endIndex = html.indexOf("], 0, false);", beginIndex) - val trimmedHtml = html.substring(beginIndex, endIndex) - - val p = Pattern.compile("'.*?','.*?',\".*?\"") - val m = p.matcher(trimmedHtml) - - val pages = mutableListOf() - - var i = 0 - while (m.find()) { - val urlParts = m.group().replace("[\"\']+".toRegex(), "").split(',') - val url = if (urlParts[1].isEmpty() && urlParts[2].startsWith("/static/")) { - baseUrl + urlParts[2] - } else { - urlParts[1] + urlParts[0] + urlParts[2] - } - pages.add(Page(i++, "", url)) - } - return pages - } - - override fun pageListParse(document: Document): List { - throw Exception("Not used") - } - - override fun imageUrlParse(document: Document) = "" - - override fun imageRequest(page: Page): Request { - val imgHeader = Headers.Builder().apply { - add("User-Agent", "Mozilla/5.0 (Windows NT 6.3; WOW64)") - add("Referer", baseUrl) - }.build() - return GET(page.imageUrl!!, imgHeader) - } - - private class Genre(name: String, val id: String) : Filter.TriState(name) - private class GenreList(genres: List) : Filter.Group("Genres", genres) - private class Category(categories: List) : Filter.Group("Category", categories) - - /* [...document.querySelectorAll("tr.advanced_option:nth-child(1) > td:nth-child(3) span.js-link")] - * .map(el => `Genre("${el.textContent.trim()}", $"{el.getAttribute('onclick') - * .substr(31,el.getAttribute('onclick').length-33)"})`).join(',\n') - * on http://readmanga.me/search/advanced - */ - override fun getFilterList() = FilterList( - Category(getCategoryList()), - GenreList(getGenreList()) - ) - - private fun getCategoryList() = listOf( - Genre("В цвете", "el_7290"), - Genre("Веб", "el_2160"), - Genre("Выпуск приостановлен", "el_8033"), - Genre("Ёнкома", "el_2161"), - Genre("Комикс западный", "el_3515"), - Genre("Манхва", "el_3001"), - Genre("Маньхуа", "el_3002"), - Genre("Ранобэ", "el_8575"), - Genre("Сборник", "el_2157") - ) - - private fun getGenreList() = listOf( - Genre("арт", "el_5685"), - Genre("боевик", "el_2155"), - Genre("боевые искусства", "el_2143"), - Genre("вампиры", "el_2148"), - Genre("гарем", "el_2142"), - Genre("гендерная интрига", "el_2156"), - Genre("героическое фэнтези", "el_2146"), - Genre("детектив", "el_2152"), - Genre("дзёсэй", "el_2158"), - Genre("додзинси", "el_2141"), - Genre("драма", "el_2118"), - Genre("игра", "el_2154"), - Genre("история", "el_2119"), - Genre("киберпанк", "el_8032"), - Genre("кодомо", "el_2137"), - Genre("комедия", "el_2136"), - Genre("махо-сёдзё", "el_2147"), - Genre("меха", "el_2126"), - Genre("мистика", "el_2132"), - Genre("научная фантастика", "el_2133"), - Genre("повседневность", "el_2135"), - Genre("постапокалиптика", "el_2151"), - Genre("приключения", "el_2130"), - Genre("психология", "el_2144"), - Genre("романтика", "el_2121"), - Genre("самурайский боевик", "el_2124"), - Genre("сверхъестественное", "el_2159"), - Genre("сёдзё", "el_2122"), - Genre("сёдзё-ай", "el_2128"), - Genre("сёнэн", "el_2134"), - Genre("сёнэн-ай", "el_2139"), - Genre("спорт", "el_2129"), - Genre("сэйнэн", "el_2138"), - Genre("трагедия", "el_2153"), - Genre("триллер", "el_2150"), - Genre("ужасы", "el_2125"), - Genre("фантастика", "el_2140"), - Genre("фэнтези", "el_2131"), - Genre("школа", "el_2127"), - Genre("этти", "el_2149"), - Genre("юри", "el_2123") - ) -} \ No newline at end of file