From a6c2ed3aaec50f76ed3d1db374a4946cd3da12c1 Mon Sep 17 00:00:00 2001 From: Mike <51273546+SnakeDoc83@users.noreply.github.com> Date: Sun, 10 May 2020 17:47:38 -0400 Subject: [PATCH] Myreadingmanga - add more languages (#3088) * working * integration * cleanup, finalization --- src/all/myreadingmanga/build.gradle | 2 +- .../all/myreadingmanga/MyReadingManga.kt | 184 ++++++------------ .../myreadingmanga/MyReadingMangaFactory.kt | 42 +++- .../myreadingmanga/MyReadingMangaLanguages.kt | 11 -- 4 files changed, 102 insertions(+), 137 deletions(-) delete mode 100644 src/all/myreadingmanga/src/eu/kanade/tachiyomi/extension/all/myreadingmanga/MyReadingMangaLanguages.kt diff --git a/src/all/myreadingmanga/build.gradle b/src/all/myreadingmanga/build.gradle index cdfcd4934..d448b7f62 100644 --- a/src/all/myreadingmanga/build.gradle +++ b/src/all/myreadingmanga/build.gradle @@ -5,7 +5,7 @@ ext { appName = 'Tachiyomi: MyReadingManga' pkgNameSuffix = 'all.myreadingmanga' extClass = '.MyReadingMangaFactory' - extVersionCode = 33 + extVersionCode = 34 libVersion = '1.2' } diff --git a/src/all/myreadingmanga/src/eu/kanade/tachiyomi/extension/all/myreadingmanga/MyReadingManga.kt b/src/all/myreadingmanga/src/eu/kanade/tachiyomi/extension/all/myreadingmanga/MyReadingManga.kt index 8b15b3c1a..ff72b564e 100644 --- a/src/all/myreadingmanga/src/eu/kanade/tachiyomi/extension/all/myreadingmanga/MyReadingManga.kt +++ b/src/all/myreadingmanga/src/eu/kanade/tachiyomi/extension/all/myreadingmanga/MyReadingManga.kt @@ -1,5 +1,6 @@ package eu.kanade.tachiyomi.extension.all.myreadingmanga +import android.annotation.SuppressLint import android.net.Uri import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.asObservableSuccess @@ -22,11 +23,11 @@ import org.jsoup.nodes.Document import org.jsoup.nodes.Element import rx.Observable -open class MyReadingManga(override val lang: String) : ParsedHttpSource() { +open class MyReadingManga(override val lang: String, private val siteLang: String, private val latestLang: String) : ParsedHttpSource() { // Basic Info override val name = "MyReadingManga" - override val baseUrl = "https://myreadingmanga.info" + final override val baseUrl = "https://myreadingmanga.info" override val client: OkHttpClient = network.cloudflareClient.newBuilder() .connectTimeout(1, TimeUnit.MINUTES) .readTimeout(1, TimeUnit.MINUTES) @@ -37,106 +38,57 @@ open class MyReadingManga(override val lang: String) : ParsedHttpSource() { // Popular - Random override fun popularMangaRequest(page: Int): Request { - return GET("$baseUrl/search/?wpsolr_sort=sort_by_random&wpsolr_page=$page", headers) // Random Manga as returned by search + return GET("$baseUrl/search/?wpsolr_sort=sort_by_random&wpsolr_page=$page&wpsolr_fq[0]=lang_str:$siteLang", headers) // Random Manga as returned by search } - override fun popularMangaNextPageSelector() = searchMangaNextPageSelector() - override fun popularMangaSelector() = searchMangaSelector() - override fun popularMangaParse(response: Response) = searchMangaParse(response) - override fun popularMangaFromElement(element: Element) = searchMangaFromElement(element) + override fun popularMangaParse(response: Response): MangasPage { + if (!filtersCached) { + cachedPagesUrls.onEach { filterAssist(it.value) } + filtersCached = true + } + return searchMangaParse(response) + } + override fun popularMangaNextPageSelector() = throw Exception("Not used") + override fun popularMangaSelector() = throw Exception("Not used") + override fun popularMangaFromElement(element: Element) = throw Exception("Not used") // Latest + @SuppressLint("DefaultLocale") override fun latestUpdatesRequest(page: Int): Request { - return GET("$baseUrl/page/$page/", headers) // Home Page - Latest Manga + return GET("$baseUrl/lang/${latestLang.toLowerCase()}" + if (page > 1) "/page/$page/" else "", headers) // Home Page - Latest Manga } override fun latestUpdatesNextPageSelector() = "li.pagination-next" override fun latestUpdatesSelector() = "article" - override fun latestUpdatesParse(response: Response): MangasPage { - val document = response.asJsoup() - val mangas = mutableListOf() - val list = document.select(latestUpdatesSelector()).filter { element -> - val select = element.select("a[rel=bookmark]") - select.text().contains("[$lang", true) - } - for (element in list) { - mangas.add(latestUpdatesFromElement(element)) - } - - val hasNextPage = latestUpdatesNextPageSelector().let { selector -> - document.select(selector).first() - } != null - - return MangasPage(mangas, hasNextPage) - } - override fun latestUpdatesFromElement(element: Element) = buildManga(element.select("a[rel]").first(), element.select("a.entry-image-link img").first()) // Search override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { - val uri = if (query.isNotBlank()) { - Uri.parse("$baseUrl/search/").buildUpon() - .appendQueryParameter("search", query) - .appendQueryParameter("wpsolr_page", page.toString()) - } else { - val uri = Uri.parse("$baseUrl/").buildUpon() - // Append uri filters - filters.forEach { - if (it is UriFilter) - it.addToUri(uri) + var fqIndex = 0 + val uri = Uri.parse("$baseUrl/search/").buildUpon() + .appendQueryParameter("wpsolr_q", query) + .appendQueryParameter("wpsolr_fq[$fqIndex]", "lang_str:$siteLang") + .appendQueryParameter("wpsolr_page", page.toString()) + filters.forEach { + if (it is UriFilter) { + fqIndex++ + it.addToUri(uri, "wpsolr_fq[$fqIndex]") } - uri.appendPath("page").appendPath("$page") } return GET(uri.toString(), headers) } - override fun searchMangaNextPageSelector(): String? = null + override fun searchMangaNextPageSelector(): String? = throw Exception("Not used") override fun searchMangaSelector() = "div.results-by-facets div[id*=res]" + private var mangaParsedSoFar = 0 override fun searchMangaParse(response: Response): MangasPage { - // Filter Assist - Caches Pages required for filter parsing - if (!filtersCached) { - filterAssist(baseUrl) - filterAssist("$baseUrl/cats/") - filterAssist("$baseUrl/pairing/") - filterAssist("$baseUrl/group/") - filtersCached = true - } - val document = response.asJsoup() - val mangas = mutableListOf() - // Process Search Results - if (document.baseUri().contains("search", true)) { - val elements = document.select(searchMangaSelector()) - for (element in elements) { - if (element.text().contains("[$lang", true)) { - mangas.add(searchMangaFromElement(element)) - } - } - val hasNextPage = searchMangaSelector().let { selector -> - document.select(selector).first() - } != null - - return MangasPage(mangas, hasNextPage) - } - // Process Filter Results / Same theme as home page - else { - // return popularMangaParse(response) - val list = document.select(latestUpdatesSelector()).filter { element -> - val select = element.select("a[rel=bookmark]") - select.text().contains("[$lang", true) - } - for (element in list) { - mangas.add(latestUpdatesFromElement(element)) - } - - val hasNextPage = latestUpdatesNextPageSelector().let { selector -> - document.select(selector).first() - } != null - - return MangasPage(mangas, hasNextPage) - } + if (document.location().contains("page=1")) mangaParsedSoFar = 0 + val mangas = document.select(searchMangaSelector()).map { searchMangaFromElement(it) } + .also { mangaParsedSoFar += it.count() } + val totalResults = Regex("""(\d+)""").find(document.select("div.res_info").text())?.groupValues?.get(1)?.toIntOrNull() ?: 0 + return MangasPage(mangas, mangaParsedSoFar < totalResults) } - override fun searchMangaFromElement(element: Element) = buildManga(element.select("a").first(), element.select("img")?.first()) // Build Manga From Element @@ -184,8 +136,7 @@ open class MyReadingManga(override val lang: String) : ParsedHttpSource() { val manga = SManga.create() manga.author = cleanAuthor(document.select("h1").text()) manga.artist = cleanAuthor(document.select("h1").text()) - val glist = document.select(".entry-header p a[href*=genre]").map { it.text() } - manga.genre = glist.joinToString(", ") + manga.genre = document.select(".entry-header p a[href*=genre]").joinToString(", ") { it.text() } val extendedDescription = document.select(".entry-content p:not(p:containsOwn(|)):not(.chapter-class + p)")?.joinToString("\n") { it.text() } manga.description = document.select("h1").text() + if (extendedDescription.isNullOrEmpty()) "" else "\n\n$extendedDescription" manga.status = when (document.select("a[href*=status]")?.first()?.text()) { @@ -207,6 +158,7 @@ open class MyReadingManga(override val lang: String) : ParsedHttpSource() { // Start Chapter Get override fun chapterListSelector() = ".entry-pagination a" + @SuppressLint("DefaultLocale") override fun chapterListParse(response: Response): List { val document = response.asJsoup() val chapters = mutableListOf() @@ -285,63 +237,53 @@ open class MyReadingManga(override val lang: String) : ParsedHttpSource() { } // Parses page for filter - private fun returnFilter(document: Document?, css: String, attributekey: String): Array> { - return document?.select(css)?.map { Pair(it.attr(attributekey).substringBeforeLast("/").substringAfterLast("/"), it.text()) }?.toTypedArray() - ?: arrayOf(Pair("", "Press 'Reset' to try again")) + private fun returnFilter(document: Document?, css: String): Array { + return document?.select(css)?.map { it.text() }?.toTypedArray() + ?: arrayOf("Press 'Reset' to try again") } + // URLs for the pages we need to cache + private val cachedPagesUrls = hashMapOf( + Pair("genres", baseUrl), + Pair("tags", baseUrl), + Pair("categories", "$baseUrl/cats/"), + Pair("pairings", "$baseUrl/pairing/"), + Pair("groups", "$baseUrl/group/") + ) + // Generates the filter lists for app override fun getFilterList(): FilterList { return FilterList( - // MRM does not support genre filtering and text search at the same time - Filter.Header("NOTE: Filters are ignored if using text search."), - Filter.Header("Only one filter can be used at a time."), - GenreFilter(returnFilter(getCache(baseUrl), ".tagcloud a[href*=/genre/]", "href")), - TagFilter(returnFilter(getCache(baseUrl), ".tagcloud a[href*=/tag/]", "href")), - CatFilter(returnFilter(getCache("$baseUrl/cats/"), ".links a", "abs:href")), - PairingFilter(returnFilter(getCache("$baseUrl/pairing/"), ".links a", "abs:href")), - ScanGroupFilter(returnFilter(getCache("$baseUrl/group/"), ".links a", "abs:href")) + GenreFilter(returnFilter(getCache(cachedPagesUrls["genres"]!!), ".tagcloud a[href*=/genre/]")), + TagFilter(returnFilter(getCache(cachedPagesUrls["tags"]!!), ".tagcloud a[href*=/tag/]")), + CatFilter(returnFilter(getCache(cachedPagesUrls["categories"]!!), ".links a")), + PairingFilter(returnFilter(getCache(cachedPagesUrls["pairings"]!!), ".links a")), + ScanGroupFilter(returnFilter(getCache(cachedPagesUrls["groups"]!!), ".links a")) ) } - private class GenreFilter(GENRES: Array>) : UriSelectFilterPath("Genre", "genre", arrayOf(Pair("", "Any"), *GENRES)) - private class TagFilter(POPTAG: Array>) : UriSelectFilterPath("Popular Tags", "tag", arrayOf(Pair("", "Any"), *POPTAG)) - private class CatFilter(CATID: Array>) : UriSelectFilterShortPath("Categories", "cat", arrayOf(Pair("", "Any"), *CATID)) - private class PairingFilter(PAIR: Array>) : UriSelectFilterPath("Pairing", "pairing", arrayOf(Pair("", "Any"), *PAIR)) - private class ScanGroupFilter(GROUP: Array>) : UriSelectFilterPath("Scanlation Group", "group", arrayOf(Pair("", "Any"), *GROUP)) + private class GenreFilter(GENRES: Array) : UriSelectFilter("Genre", "genre_str", arrayOf("Any", *GENRES)) + private class TagFilter(POPTAG: Array) : UriSelectFilter("Popular Tags", "tags", arrayOf("Any", *POPTAG)) + private class CatFilter(CATID: Array) : UriSelectFilter("Categories", "categories", arrayOf("Any", *CATID)) + private class PairingFilter(PAIR: Array) : UriSelectFilter("Pairing", "pairing_str", arrayOf("Any", *PAIR)) + private class ScanGroupFilter(GROUP: Array) : UriSelectFilter("Scanlation Group", "group_str", arrayOf("Any", *GROUP)) /** * Class that creates a select filter. Each entry in the dropdown has a name and a display name. * If an entry is selected it is appended as a query parameter onto the end of the URI. * If `firstIsUnspecified` is set to true, if the first entry is selected, nothing will be appended on the the URI. */ - // vals: - private open class UriSelectFilterPath( + private open class UriSelectFilter( displayName: String, - val uriParam: String, - val vals: Array>, + val uriValuePrefix: String, + val vals: Array, val firstIsUnspecified: Boolean = true, defaultValue: Int = 0 ) : - Filter.Select(displayName, vals.map { it.second }.toTypedArray(), defaultValue), UriFilter { - override fun addToUri(uri: Uri.Builder) { + Filter.Select(displayName, vals.map { it }.toTypedArray(), defaultValue), UriFilter { + override fun addToUri(uri: Uri.Builder, uriParam: String) { if (state != 0 || !firstIsUnspecified) - uri.appendPath(uriParam) - .appendPath(vals[state].first) - } - } - - private open class UriSelectFilterShortPath( - displayName: String, - val uriParam: String, - val vals: Array>, - val firstIsUnspecified: Boolean = true, - defaultValue: Int = 0 - ) : - Filter.Select(displayName, vals.map { it.second }.toTypedArray(), defaultValue), UriFilter { - override fun addToUri(uri: Uri.Builder) { - if (state != 0 || !firstIsUnspecified) - uri.appendPath(vals[state].first) + uri.appendQueryParameter(uriParam, "$uriValuePrefix:${vals[state]}") } } @@ -349,6 +291,6 @@ open class MyReadingManga(override val lang: String) : ParsedHttpSource() { * Represents a filter that is able to modify a URI. */ private interface UriFilter { - fun addToUri(uri: Uri.Builder) + fun addToUri(uri: Uri.Builder, uriParam: String) } } diff --git a/src/all/myreadingmanga/src/eu/kanade/tachiyomi/extension/all/myreadingmanga/MyReadingMangaFactory.kt b/src/all/myreadingmanga/src/eu/kanade/tachiyomi/extension/all/myreadingmanga/MyReadingMangaFactory.kt index 1d19231c0..658c90c5c 100644 --- a/src/all/myreadingmanga/src/eu/kanade/tachiyomi/extension/all/myreadingmanga/MyReadingMangaFactory.kt +++ b/src/all/myreadingmanga/src/eu/kanade/tachiyomi/extension/all/myreadingmanga/MyReadingMangaFactory.kt @@ -3,9 +3,43 @@ package eu.kanade.tachiyomi.extension.all.myreadingmanga import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.source.SourceFactory -/** - * - */ class MyReadingMangaFactory : SourceFactory { - override fun createSources(): List = getAllMyReadingMangaLanguages() + override fun createSources(): List = languageList.map { MyReadingManga(it.tachiLang, it.siteLang, it.latestLang) } } + +private data class Source(val tachiLang: String, val siteLang: String, val latestLang: String = siteLang) + +// These should all be valid. Add a language code and uncomment to enable +private val languageList = listOf( + Source("ar", "Arabic"), +// Source("", "Bahasa"), + Source("id", "Indonesia"), +// Source("", "Bulgarian"), + Source("zh", "Chinese"), +// Source("", "Croatian"), +// Source("", "Czech"), + Source("en", "English"), +// Source("", "Filipino"), +// Source("", "Finnish"), +// Source("", "Flemish", "flemish-dutch"), +// Source("", "Dutch"), + Source("fr", "French"), + Source("de", "German"), +// Source("", "Greek"), +// Source("", "Hebrew"), +// Source("", "Hindi"), +// Source("", "Hungarian"), + Source("it", "Italian"), + Source("ja", "Japanese", "jp"), + Source("ko", "Korean"), +// Source("", "Polish"), + Source("pt-BR", "Portuguese"), +// Source("", "Romanian"), + Source("ru", "Russian"), +// Source("", "Slovak"), + Source("es", "Spanish"), +// Source("", "Swedish"), +// Source("", "Thai"), + Source("tr", "Turkish"), + Source("vi", "Vietnamese") +) diff --git a/src/all/myreadingmanga/src/eu/kanade/tachiyomi/extension/all/myreadingmanga/MyReadingMangaLanguages.kt b/src/all/myreadingmanga/src/eu/kanade/tachiyomi/extension/all/myreadingmanga/MyReadingMangaLanguages.kt deleted file mode 100644 index 0c6a9ea85..000000000 --- a/src/all/myreadingmanga/src/eu/kanade/tachiyomi/extension/all/myreadingmanga/MyReadingMangaLanguages.kt +++ /dev/null @@ -1,11 +0,0 @@ -package eu.kanade.tachiyomi.extension.all.myreadingmanga - -/** - * MyReadingManga languages - */ - -class MyReadingMangaEnglish : MyReadingManga("en") - -fun getAllMyReadingMangaLanguages() = listOf( - MyReadingMangaEnglish() -)