diff --git a/src/all/mangadex/build.gradle b/src/all/mangadex/build.gradle new file mode 100644 index 000000000..719bdb8e0 --- /dev/null +++ b/src/all/mangadex/build.gradle @@ -0,0 +1,17 @@ +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' + +ext { + appName = 'Tachiyomi: MangaDex' + pkgNameSuffix = "all.mangadex" + extClass = '.MangadexFactory' + extVersionCode = 4 + extVersionSuffix = 4 + libVersion = '1.2' +} + +dependencies { + +} + +apply from: "$rootDir/common.gradle" diff --git a/src/en/mangadex/src/eu/kanade/tachiyomi/extension/en/mangadex/Mangadex.kt b/src/all/mangadex/src/eu/kanade/tachiyomi/extension/all/mangadex/Mangadex.kt similarity index 68% rename from src/en/mangadex/src/eu/kanade/tachiyomi/extension/en/mangadex/Mangadex.kt rename to src/all/mangadex/src/eu/kanade/tachiyomi/extension/all/mangadex/Mangadex.kt index 987c53798..a855501e4 100644 --- a/src/en/mangadex/src/eu/kanade/tachiyomi/extension/en/mangadex/Mangadex.kt +++ b/src/all/mangadex/src/eu/kanade/tachiyomi/extension/all/mangadex/Mangadex.kt @@ -1,16 +1,19 @@ -package eu.kanade.tachiyomi.extension.en.mangadex +package eu.kanade.tachiyomi.extension.all.mangadex import eu.kanade.tachiyomi.network.GET +import eu.kanade.tachiyomi.network.asObservableSuccess import eu.kanade.tachiyomi.source.model.* import eu.kanade.tachiyomi.source.online.ParsedHttpSource import okhttp3.HttpUrl +import okhttp3.OkHttpClient import okhttp3.Request import org.jsoup.nodes.Document import org.jsoup.nodes.Element +import rx.Observable import java.net.URLEncoder import java.text.SimpleDateFormat -class Mangadex : ParsedHttpSource() { +open class Mangadex(override val lang: String, private val internalLang: String, val pageStart: Int) : ParsedHttpSource() { override val name = "MangaDex" @@ -18,44 +21,40 @@ class Mangadex : ParsedHttpSource() { override val supportsLatest = true - override val lang = "en" + override val client = clientBuilder(ALL) - private val internalLang = "gb" - - override val client = network.cloudflareClient.newBuilder() + private fun clientBuilder(r18Toggle: Int): OkHttpClient = network.cloudflareClient.newBuilder() .addNetworkInterceptor { chain -> val newReq = chain .request() .newBuilder() - .addHeader("Cookie", cookiesHeader) + .addHeader("Cookie", cookiesHeader(r18Toggle)) .build() - chain.proceed(newReq) }.build()!! - private val cookiesHeader by lazy { + private fun cookiesHeader(r18Toggle: Int): String { val cookies = mutableMapOf() - cookies.put("mangadex_h_toggle", "1") - buildCookies(cookies) + cookies.put("mangadex_h_toggle", r18Toggle.toString()) + return buildCookies(cookies) } - private fun buildCookies(cookies: Map) - = cookies.entries.map { + private fun buildCookies(cookies: Map) = cookies.entries.joinToString(separator = "; ", postfix = ";") { "${URLEncoder.encode(it.key, "UTF-8")}=${URLEncoder.encode(it.value, "UTF-8")}" - }.joinToString(separator = "; ", postfix = ";") + } override fun popularMangaSelector() = ".table-responsive tbody tr" override fun latestUpdatesSelector() = ".table-responsive tbody tr a.manga_title[href*=manga]" override fun popularMangaRequest(page: Int): Request { - val pageStr = if (page != 1) "//" + ((page * 100) - 100) else "" + val pageStr = if (page != 1) "/" + ((page * 100) - 100) else "" return GET("$baseUrl/titles$pageStr", headers) } override fun latestUpdatesRequest(page: Int): Request { - val pageStr = if (page != 1) ((page * 20) - 20) else "" - return GET("$baseUrl/1/$page", headers) + val pageStr = if (page != 1) "/" + ((page * 20)) else "" + return GET("$baseUrl/$pageStart$pageStr", headers) } override fun popularMangaFromElement(element: Element): SManga { @@ -83,6 +82,32 @@ class Mangadex : ParsedHttpSource() { override fun searchMangaNextPageSelector() = ".pagination li:not(.disabled) span[title*=last page]:not(disabled)" + override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable { + return getSearchClient(filters).newCall(searchMangaRequest(page, query, filters)) + .asObservableSuccess() + .map { response -> + searchMangaParse(response) + } + } + + /* get search client based off r18 filter. This will always return default client builder now until r18 solution is found or login is add + */ + private fun getSearchClient(filters: FilterList): OkHttpClient { + filters.forEach { filter -> + when (filter) { + is R18 -> { + return when { + filter.isExcluded() -> clientBuilder(NO_R18) + filter.isIncluded() -> clientBuilder(ONLY_R18) + else -> clientBuilder(ALL) + + } + } + } + } + return clientBuilder(ALL) + } + override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { val byGenre = filters.find { it is GenreList } val genres = mutableListOf() @@ -96,8 +121,9 @@ class Mangadex : ParsedHttpSource() { } //do browse by letter if set val byLetter = filters.find { it is ByLetter } - if (byLetter != null && (byLetter as ByLetter).state != 0) { - val s = byLetter.values[byLetter.state] + + if (byLetter != null && (byLetter as ByLetter).state.first().state != 0) { + val s = byLetter.state.first().values[byLetter.state.first().state] val pageStr = if (page != 1) (((page - 1) * 100)).toString() else "0" val url = HttpUrl.parse("$baseUrl/titles/")!!.newBuilder().addPathSegment(s).addPathSegment(pageStr) return GET(url.toString(), headers) @@ -124,15 +150,14 @@ class Mangadex : ParsedHttpSource() { override fun mangaDetailsParse(document: Document): SManga { val manga = SManga.create() - val imageElement = document.select(".table-condensed").first() - val infoElement = document.select(".table.table-condensed.edit").first() + val infoElement = document.select(".row.edit").first() val genreElement = infoElement.select("tr:eq(3) td .genre") manga.author = infoElement.select("tr:eq(1) td").first()?.text() manga.artist = infoElement.select("tr:eq(2) td").first()?.text() manga.status = parseStatus(infoElement.select("tr:eq(5) td").first()?.text()) manga.description = infoElement.select("tr:eq(7) td").first()?.text() - manga.thumbnail_url = imageElement.select("img").first()?.attr("src").let { baseUrl + "/" + it } + manga.thumbnail_url = infoElement.select("img").first()?.attr("src").let { baseUrl + "/" + it } var genres = mutableListOf() genreElement?.forEach { genres.add(it.text()) } manga.genre = genres.joinToString(", ") @@ -162,30 +187,21 @@ class Mangadex : ParsedHttpSource() { override fun pageListParse(document: Document): List { val pages = mutableListOf() val url = document.baseUri() - val select = document.select("#jump_page") - //if its a regular manga get the pages from the drop down selector - if (select.isNotEmpty()) { - select.first().select("option").forEach { - pages.add(Page(pages.size, url + "/" + it.attr("value"))) - } - } else { - //webtoon get all the image urls on the one page - document.select(".edit.webtoon").forEach { - pages.add(Page(pages.size, "", it.attr("src"))) - } + + val dataUrl = document.select("script").last().html().substringAfter("dataurl = '").substringBefore("';") + val imageUrl = document.select("script").last().html().substringAfter("page_array = [").substringBefore("];") + val listImageUrls = imageUrl.replace("'", "").split(",") + val server = document.select("script").last().html().substringAfter("server = '").substringBefore("';") + + listImageUrls.filter { it.isNotBlank() }.forEach { + val url = "$server$dataUrl/$it" + pages.add(Page(pages.size, "", getImageUrl(url))) } return pages } - override fun imageUrlParse(document: Document): String { - val attr = document.select("#current_page").first().attr("src") - //some images are hosted elsewhere - if (attr.startsWith("http")) { - return attr - } - return baseUrl + attr - } + override fun imageUrlParse(document: Document): String = "" private fun parseStatus(status: String?) = when { status == null -> SManga.UNKNOWN @@ -195,19 +211,28 @@ class Mangadex : ParsedHttpSource() { else -> SManga.UNKNOWN } + fun getImageUrl(attr: String): String { + //some images are hosted elsewhere + if (attr.startsWith("http")) { + return attr + } + return baseUrl + attr + } + private class TextField(name: String, val key: String) : Filter.Text(name) private class Genre(val id: String, name: String) : Filter.CheckBox(name) private class GenreList(genres: List) : Filter.Group("Genres", genres) - private class ByLetter : Filter.Select("Browse By Letter", arrayOf("", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z")) - + private class R18(name: String) : Filter.TriState(name) + private class ByLetter(letters: List) : Filter.Group("Browse by Letter only", letters) + private class Letters : Filter.Select("Letter", arrayOf("", "~", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z")) override fun getFilterList() = FilterList( TextField("Author", "author"), TextField("Artist", "artist"), + //R18("Show R18+"), GenreList(getGenreList()), - Filter.Header("Note: Browsing by Letter"), - Filter.Header("Ignores other Search Fields"), - ByLetter()) + ByLetter(listOf(Letters())) + ) private fun getGenreList() = listOf( @@ -252,4 +277,10 @@ class Mangadex : ParsedHttpSource() { Genre("39", "[no chapters]"), Genre("40", "Game") ) + + companion object { + const val NO_R18 = 0 + const val ALL = 1 + const val ONLY_R18 = 2 + } } \ No newline at end of file diff --git a/src/all/mangadex/src/eu/kanade/tachiyomi/extension/all/mangadex/MangadexFactory.kt b/src/all/mangadex/src/eu/kanade/tachiyomi/extension/all/mangadex/MangadexFactory.kt new file mode 100644 index 000000000..aeb668f11 --- /dev/null +++ b/src/all/mangadex/src/eu/kanade/tachiyomi/extension/all/mangadex/MangadexFactory.kt @@ -0,0 +1,11 @@ +package eu.kanade.tachiyomi.extension.all.mangadex + +import eu.kanade.tachiyomi.source.Source +import eu.kanade.tachiyomi.source.SourceFactory + +/** + * Created by Carlos on 2/8/2018. + */ +class MangadexFactory : SourceFactory { + override fun createSources(): List = getAllMangaDexLanguages() +} diff --git a/src/all/mangadex/src/eu/kanade/tachiyomi/extension/all/mangadex/MangadexLanguages.kt b/src/all/mangadex/src/eu/kanade/tachiyomi/extension/all/mangadex/MangadexLanguages.kt new file mode 100644 index 000000000..87f34b970 --- /dev/null +++ b/src/all/mangadex/src/eu/kanade/tachiyomi/extension/all/mangadex/MangadexLanguages.kt @@ -0,0 +1,36 @@ +package eu.kanade.tachiyomi.extension.all.mangadex + +/** + * Mangadex languages + */ + +class MangaDexPolish : Mangadex("pl", "pl", 3) +class MangaDexItalian : Mangadex("it", "it", 6) +class MangaDexRussian : Mangadex("ru", "ru", 7) +class MangaDexGerman : Mangadex("de", "de", 8) +class MangaDexFrench : Mangadex("fr", "fr", 10) +class MangaDexVietnamese : Mangadex("vi", "vn", 12) +class MangaDexSpanishSpain : Mangadex("es", "es", 15) +class MangaDexPortuguese : Mangadex("pt", "br", 16) +class MangaDexSwedish : Mangadex("sv", "se", 18) +class MangaDexTurkish : Mangadex("tr", "tr", 26) +class MangaDexIndonesian : Mangadex("id", "id", 27) +class MangaDexSpanishLTAM : Mangadex("es-419", "mx", 29) +class MangaDexCatalan : Mangadex("ca", "ct", 33) + +fun getAllMangaDexLanguages() = listOf( + MangaDexEnglish(), + MangaDexPolish(), + MangaDexItalian(), + MangaDexRussian(), + MangaDexGerman(), + MangaDexFrench(), + MangaDexVietnamese(), + MangaDexSpanishSpain(), + MangaDexPortuguese(), + MangaDexSwedish(), + MangaDexTurkish(), + MangaDexIndonesian(), + MangaDexSpanishLTAM(), + MangaDexCatalan() +) \ No newline at end of file diff --git a/src/all/mangadex/src/eu/kanade/tachiyomi/extension/en/mangadex/MangaDexEnglish.kt b/src/all/mangadex/src/eu/kanade/tachiyomi/extension/en/mangadex/MangaDexEnglish.kt new file mode 100644 index 000000000..be03df6d2 --- /dev/null +++ b/src/all/mangadex/src/eu/kanade/tachiyomi/extension/en/mangadex/MangaDexEnglish.kt @@ -0,0 +1,3 @@ +package eu.kanade.tachiyomi.extension.all.mangadex + +class MangaDexEnglish : Mangadex("en", "gb", 1) diff --git a/src/en/mangadex/build.gradle b/src/en/mangadex/build.gradle deleted file mode 100644 index a1949f314..000000000 --- a/src/en/mangadex/build.gradle +++ /dev/null @@ -1,19 +0,0 @@ -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' - - -ext { - appName = 'Tachiyomi: MangaDex' - pkgNameSuffix = "en.mangadex" - extClass = '.Mangadex' - extVersionCode = 3 - extVersionSuffix = 3 - libVersion = '1.2' -} - -dependencies { - provided "com.google.code.gson:gson:2.8.0" - provided "com.github.salomonbrys.kotson:kotson:2.5.0" -} - -apply from: "$rootDir/common.gradle"