diff --git a/src/all/batoto/AndroidManifest.xml b/src/all/batoto/AndroidManifest.xml index 30deb7f79..88d434029 100644 --- a/src/all/batoto/AndroidManifest.xml +++ b/src/all/batoto/AndroidManifest.xml @@ -1,2 +1,23 @@ - + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/all/batoto/build.gradle b/src/all/batoto/build.gradle index ce51ef55a..0dc98db63 100644 --- a/src/all/batoto/build.gradle +++ b/src/all/batoto/build.gradle @@ -5,7 +5,7 @@ ext { extName = 'Bato.to' pkgNameSuffix = 'all.batoto' extClass = '.BatoToFactory' - extVersionCode = 9 + extVersionCode = 10 libVersion = '1.2' containsNsfw = true } diff --git a/src/all/batoto/src/eu/kanade/tachiyomi/extension/all/batoto/BatoTo.kt b/src/all/batoto/src/eu/kanade/tachiyomi/extension/all/batoto/BatoTo.kt index a85bb0c16..ac1f3468e 100644 --- a/src/all/batoto/src/eu/kanade/tachiyomi/extension/all/batoto/BatoTo.kt +++ b/src/all/batoto/src/eu/kanade/tachiyomi/extension/all/batoto/BatoTo.kt @@ -2,12 +2,15 @@ package eu.kanade.tachiyomi.extension.all.batoto import com.squareup.duktape.Duktape import eu.kanade.tachiyomi.network.GET +import eu.kanade.tachiyomi.network.asObservableSuccess import eu.kanade.tachiyomi.source.model.Filter import eu.kanade.tachiyomi.source.model.FilterList +import eu.kanade.tachiyomi.source.model.MangasPage import eu.kanade.tachiyomi.source.model.Page import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.online.ParsedHttpSource +import eu.kanade.tachiyomi.util.asJsoup import okhttp3.HttpUrl.Companion.toHttpUrlOrNull import okhttp3.OkHttpClient import okhttp3.Request @@ -17,6 +20,8 @@ import org.jsoup.nodes.Document import org.jsoup.nodes.Element import java.util.Calendar import java.util.concurrent.TimeUnit +import okhttp3.Response +import rx.Observable open class BatoTo( override val lang: String, @@ -67,76 +72,108 @@ open class BatoTo( override fun popularMangaNextPageSelector() = latestUpdatesNextPageSelector() - override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { - return if (query.isNotBlank()) { - GET("$baseUrl/search?word=$query&page=$page") - } else { - val url = "$baseUrl/browse".toHttpUrlOrNull()!!.newBuilder() - url.addQueryParameter("page", page.toString()) - url.addQueryParameter("langs", siteLang) - filters.forEach { filter -> - when (filter) { - is OriginFilter -> { - val originToInclude = mutableListOf() - filter.state.forEach { content -> - if (content.state) { - originToInclude.add(content.name) - } - } - if (originToInclude.isNotEmpty()) { - url.addQueryParameter( - "origs", - originToInclude - .joinToString(",") - ) - } + override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable { + return when { + query.startsWith("ID:") -> { + val id = query.substringAfter("ID:") + client.newCall(GET("https://bato.to/series/$id", headers)).asObservableSuccess() + .map { response -> + queryIDParse(response, id) } - is StatusFilter -> { - if (filter.state != 0) { - url.addQueryParameter("release", filter.toUriPart()) - } + } + query.isNotBlank() -> { + val url = "$baseUrl/search".toHttpUrlOrNull()!!.newBuilder() + val letterFilter = filters.findInstance()!! + url.addQueryParameter("word", query) + url.addQueryParameter("page", "$page") + if (letterFilter.state){ + url.addQueryParameter("mode", "letter") + } + client.newCall(GET(url.build().toString(), headers)).asObservableSuccess() + .map { response -> + queryParse(response) } - is GenreFilter -> { - val genreToInclude = filter.state - .filter { it.isIncluded() } - .map { it.name } + } - val genreToExclude = filter.state - .filter { it.isExcluded() } - .map { it.name } + else -> { + val sortFilter = filters.findInstance()!! + val reverseSortFilter = filters.findInstance()!! + val statusFilter = filters.findInstance()!! + val langFilter = filters.findInstance()!! + val originFilter = filters.findInstance()!! + val genreFilter = filters.findInstance()!! + val minChapterFilter = filters.findInstance()!! + val maxChapterFilter = filters.findInstance()!! + val url = "$baseUrl/browse".toHttpUrlOrNull()!!.newBuilder() + url.addQueryParameter("page", page.toString()) - if (genreToInclude.isNotEmpty() || genreToExclude.isNotEmpty()) { - url.addQueryParameter( - "genres", - genreToInclude - .joinToString(",") + - "|" + - genreToExclude - .joinToString(",") - ) - } - } - is ChapterFilter -> { - if (filter.state != 0) { - url.addQueryParameter("chapters", filter.toUriPart()) - } - } - is SortBy -> { - if (filter.state != 0) { - url.addQueryParameter("sort", filter.toUriPart()) - } + with (langFilter) { + if (this.selected.isEmpty()) { + url.addQueryParameter("langs", siteLang) + } else { + val selection = "${this.selected.joinToString(",")},$siteLang" + url.addQueryParameter("langs", selection) } } + + with (genreFilter) { + url.addQueryParameter("genres", included.joinToString(",") + "|" + excluded.joinToString(",") + ) + } + + with (statusFilter) { + url.addQueryParameter("release", this.selected) + } + + with (sortFilter) { + if (reverseSortFilter.state) { + url.addQueryParameter("sort","${this.selected}.az") + } else { + url.addQueryParameter("sort","${this.selected}.za") + } + } + + if (originFilter.selected.isNotEmpty()) { + url.addQueryParameter("origs", originFilter.selected.joinToString(",")) + } + + if (maxChapterFilter.state.isNotEmpty() or minChapterFilter.state.isNotEmpty()) { + url.addQueryParameter("chapters", minChapterFilter.state + "-" + maxChapterFilter.state) + } + + client.newCall(GET(url.build().toString(), headers)).asObservableSuccess() + .map { response -> + queryParse(response) + } } - GET(url.build().toString(), headers) } } - override fun searchMangaSelector() = latestUpdatesSelector() + private fun queryIDParse(response: Response, id: String): MangasPage { + val document = response.asJsoup() + val infoElement = document.select("div#mainer div.container-fluid") + val manga = SManga.create() + manga.title = infoElement.select("h3").text() + manga.thumbnail_url = document.select("div.attr-cover img") + .attr("abs:src") + manga.url = infoElement.select("h3 a").attr("abs:href") + return MangasPage(listOf(manga), false) + } - override fun searchMangaFromElement(element: Element) = latestUpdatesFromElement(element) + private fun queryParse(response: Response): MangasPage { + val mangas = mutableListOf() + val document = response.asJsoup() + document.select(latestUpdatesSelector()).forEach { element -> + mangas.add(latestUpdatesFromElement(element)) + } + val nextPage = document.select(latestUpdatesNextPageSelector()) != null + return MangasPage(mangas, nextPage) + } - override fun searchMangaNextPageSelector() = latestUpdatesNextPageSelector() + override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request = throw UnsupportedOperationException("Not used") + override fun searchMangaSelector() = throw UnsupportedOperationException("Not used") + override fun searchMangaFromElement(element: Element) = throw UnsupportedOperationException("Not used") + override fun searchMangaNextPageSelector() = throw UnsupportedOperationException("Not used") override fun mangaDetailsRequest(manga: SManga): Request { if (manga.url.startsWith("http")) { @@ -315,206 +352,401 @@ open class BatoTo( override fun imageUrlParse(document: Document): String = throw UnsupportedOperationException("Not used") - private class OriginFilter(genres: List) : Filter.Group("Origin", genres) - private class GenreFilter(genres: List) : Filter.Group("Genres", genres) - - private class ChapterFilter : UriPartFilter( - "Chapters", - arrayOf( - Pair("", ""), - Pair("A-Z", "title.az"), - Pair("Z-A", "title"), - Pair("Last Updated", "update"), - Pair("Oldest Updated", "updated.az"), - Pair("Newest Added", "create"), - Pair("Oldest Added", "create.az"), - Pair("Most Views Totally", "views_a"), - Pair("Most Views 365 days", "views_y"), - Pair("Most Views 30 days", "views_m"), - Pair("Most Views 7 days", "views_w"), - Pair("Most Views 24 hours", "views_d"), - Pair("Most Views 60 minutes", "views_h"), - Pair("Least Views Totally", "views_a.az"), - Pair("Least Views 365 days", "views_y.az"), - Pair("Least Views 30 days", "views_m.az"), - Pair("Least Views 7 days", "views_w.az"), - Pair("Least Views 24 hours", "views_d.az"), - Pair("Least Views 60 minutes", "views_h.az") - ) - ) - - private class StatusFilter : UriPartFilter( - "Status", - arrayOf( - Pair("