diff --git a/build.gradle b/build.gradle index 4d8c7944d..0566460c9 100644 --- a/build.gradle +++ b/build.gradle @@ -4,7 +4,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:2.2.3' + classpath 'com.android.tools.build:gradle:2.3.1' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 04e285f34..f7660310d 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Mon Dec 28 10:00:20 PST 2015 +#Thu Jun 01 17:09:13 CEST 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip diff --git a/lib/duktape-stub/build.gradle b/lib/duktape-stub/build.gradle new file mode 100644 index 000000000..cb2c10792 --- /dev/null +++ b/lib/duktape-stub/build.gradle @@ -0,0 +1,14 @@ +apply plugin: 'java' + +sourceSets { + main { + java.srcDirs = ['src'] + } +} + +dependencies { + +} + +sourceCompatibility = "1.6" +targetCompatibility = "1.6" diff --git a/lib/duktape-stub/src/com/squareup/duktape/Duktape.java b/lib/duktape-stub/src/com/squareup/duktape/Duktape.java new file mode 100644 index 000000000..d3d75cb02 --- /dev/null +++ b/lib/duktape-stub/src/com/squareup/duktape/Duktape.java @@ -0,0 +1,22 @@ +package com.squareup.duktape; + +import java.io.Closeable; +import java.io.IOException; + +@SuppressWarnings("all") +public class Duktape implements Closeable { + + public static Duktape create() { + throw new RuntimeException("Stub!"); + } + + @Override + public synchronized void close() throws IOException { + throw new RuntimeException("Stub!"); + } + + public synchronized Object evaluate(String script) { + throw new RuntimeException("Stub!"); + } + +} \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 5b93b59bc..b8a9c2a7e 100644 --- a/settings.gradle +++ b/settings.gradle @@ -4,4 +4,6 @@ new File(rootDir, "src").eachDir { dir -> include name project(name).projectDir = new File("src/${dir.name}/${subdir.name}") } -} \ No newline at end of file +} +include ':duktape-stub' +project(':duktape-stub').projectDir = new File("lib/duktape-stub") \ No newline at end of file diff --git a/src/en/kissmanga/build.gradle b/src/en/kissmanga/build.gradle index 732dbc58c..19e760094 100644 --- a/src/en/kissmanga/build.gradle +++ b/src/en/kissmanga/build.gradle @@ -6,8 +6,12 @@ ext { pkgNameSuffix = "en.kissmanga" extClass = '.Kissmanga' extVersionCode = 1 - extVersionSuffix = 1 + extVersionSuffix = 2 libVersion = '1.0' } +dependencies { + provided project(':duktape-stub') +} + apply from: "$rootDir/common.gradle" \ No newline at end of file diff --git a/src/en/kissmanga/src/eu/kanade/tachiyomi/extension/en/kissmanga/Kissmanga.kt b/src/en/kissmanga/src/eu/kanade/tachiyomi/extension/en/kissmanga/Kissmanga.kt index 3a74d3afa..6d895ae19 100644 --- a/src/en/kissmanga/src/eu/kanade/tachiyomi/extension/en/kissmanga/Kissmanga.kt +++ b/src/en/kissmanga/src/eu/kanade/tachiyomi/extension/en/kissmanga/Kissmanga.kt @@ -1,5 +1,6 @@ package eu.kanade.tachiyomi.extension.en.kissmanga +import com.squareup.duktape.Duktape import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.POST import eu.kanade.tachiyomi.source.model.* @@ -114,15 +115,37 @@ class Kissmanga : ParsedHttpSource() { override fun pageListRequest(chapter: SChapter) = POST(baseUrl + chapter.url, headers) override fun pageListParse(response: Response): List { - val pages = mutableListOf() - //language=RegExp - val p = Pattern.compile("""lstImages.push\("(.+?)"""") - val m = p.matcher(response.body().string()) + val body = response.body()!!.string() - var i = 0 - while (m.find()) { - pages.add(Page(i++, "", m.group(1))) + 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("(.*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 } diff --git a/src/en/mangafox/src/eu/kanade/tachiyomi/extension/en/mangafox/Mangafox.kt b/src/en/mangafox/src/eu/kanade/tachiyomi/extension/en/mangafox/Mangafox.kt index b93a81280..270c2a9f5 100644 --- a/src/en/mangafox/src/eu/kanade/tachiyomi/extension/en/mangafox/Mangafox.kt +++ b/src/en/mangafox/src/eu/kanade/tachiyomi/extension/en/mangafox/Mangafox.kt @@ -55,7 +55,7 @@ class Mangafox : ParsedHttpSource() { 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) + 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()) @@ -168,7 +168,7 @@ class Mangafox : ParsedHttpSource() { 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"), - Selection(2, false)) + Filter.Sort.Selection(2, false)) private class GenreList(genres: List) : Filter.Group("Genres", genres) override fun getFilterList() = FilterList( diff --git a/src/en/mangahere/build.gradle b/src/en/mangahere/build.gradle index ac3a703ac..2ae99d755 100644 --- a/src/en/mangahere/build.gradle +++ b/src/en/mangahere/build.gradle @@ -6,7 +6,7 @@ ext { pkgNameSuffix = "en.mangahere" extClass = '.Mangahere' extVersionCode = 1 - extVersionSuffix = 1 + extVersionSuffix = 2 libVersion = '1.0' } diff --git a/src/en/mangahere/src/eu/kanade/tachiyomi/extension/en/mangahere/Mangahere.kt b/src/en/mangahere/src/eu/kanade/tachiyomi/extension/en/mangahere/Mangahere.kt index 2fc871a14..4bc8b2594 100644 --- a/src/en/mangahere/src/eu/kanade/tachiyomi/extension/en/mangahere/Mangahere.kt +++ b/src/en/mangahere/src/eu/kanade/tachiyomi/extension/en/mangahere/Mangahere.kt @@ -57,7 +57,7 @@ class Mangahere : ParsedHttpSource() { 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) + 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]) @@ -152,6 +152,11 @@ class Mangahere : ParsedHttpSource() { } 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 { pages.add(Page(pages.size, it.attr("value"))) @@ -168,7 +173,7 @@ class Mangahere : ParsedHttpSource() { 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"), - Selection(2, false)) + Filter.Sort.Selection(2, false)) private class GenreList(genres: List) : Filter.Group("Genres", genres) override fun getFilterList() = FilterList( diff --git a/src/en/mangasee/build.gradle b/src/en/mangasee/build.gradle index 1bf931df3..dc708c92d 100644 --- a/src/en/mangasee/build.gradle +++ b/src/en/mangasee/build.gradle @@ -6,7 +6,7 @@ ext { pkgNameSuffix = "en.mangasee" extClass = '.Mangasee' extVersionCode = 1 - extVersionSuffix = 1 + extVersionSuffix = 2 libVersion = '1.0' } diff --git a/src/en/mangasee/src/eu/kanade/tachiyomi/extension/en/mangasee/Mangasee.kt b/src/en/mangasee/src/eu/kanade/tachiyomi/extension/en/mangasee/Mangasee.kt index 5a7d9e229..a6cdfb8b4 100644 --- a/src/en/mangasee/src/eu/kanade/tachiyomi/extension/en/mangasee/Mangasee.kt +++ b/src/en/mangasee/src/eu/kanade/tachiyomi/extension/en/mangasee/Mangasee.kt @@ -4,6 +4,7 @@ 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 @@ -27,11 +28,16 @@ class Mangasee : ParsedHttpSource() { 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, headers, body.build()) + return POST(requestUrl, catalogHeaders, body.build()) } override fun popularMangaFromElement(element: Element): SManga { @@ -48,7 +54,7 @@ class Mangasee : ParsedHttpSource() { 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() + val url = HttpUrl.parse("$baseUrl/search/request.php")!!.newBuilder() if (!query.isEmpty()) url.addQueryParameter("keyword", query) val genres = mutableListOf() val genresNo = mutableListOf() @@ -74,11 +80,11 @@ class Mangasee : ParsedHttpSource() { if (genresNo.isNotEmpty()) url.addQueryParameter("genreNo", genresNo.joinToString(",")) val (body, requestUrl) = convertQueryToPost(page, url.toString()) - return POST(requestUrl, headers, body.build()) + return POST(requestUrl, catalogHeaders, body.build()) } private fun convertQueryToPost(page: Int, url: String): Pair { - val url = HttpUrl.parse(url) + 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)) @@ -164,7 +170,7 @@ class Mangasee : ParsedHttpSource() { override fun latestUpdatesRequest(page: Int): Request { val url = "http://mangaseeonline.net/home/latest.request.php" val (body, requestUrl) = convertQueryToPost(page, url) - return POST(requestUrl, headers, body.build()) + return POST(requestUrl, catalogHeaders, body.build()) } override fun latestUpdatesFromElement(element: Element): SManga { diff --git a/src/ru/mangachan/build.gradle b/src/ru/mangachan/build.gradle index d008a7914..976129ec4 100644 --- a/src/ru/mangachan/build.gradle +++ b/src/ru/mangachan/build.gradle @@ -6,7 +6,7 @@ ext { pkgNameSuffix = "ru.mangachan" extClass = '.Mangachan' extVersionCode = 1 - extVersionSuffix = 1 + extVersionSuffix = 2 libVersion = '1.0' } diff --git a/src/ru/mangachan/src/eu/kanade/tachiyomi/extension/ru/mangachan/Mangachan.kt b/src/ru/mangachan/src/eu/kanade/tachiyomi/extension/ru/mangachan/Mangachan.kt index 37195f185..2093917fb 100644 --- a/src/ru/mangachan/src/eu/kanade/tachiyomi/extension/ru/mangachan/Mangachan.kt +++ b/src/ru/mangachan/src/eu/kanade/tachiyomi/extension/ru/mangachan/Mangachan.kt @@ -28,16 +28,21 @@ class Mangachan : ParsedHttpSource() { } 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" + "$baseUrl/?do=search&subaction=search&story=$query&search_start=$pageNum" } else { val filt = filters.filterIsInstance().filter { !it.isIgnored() } if (filt.isNotEmpty()) { var genres = "" filt.forEach { genres += (if (it.isExcluded()) "-" else "") + it.id + '+' } - "$baseUrl/tags/${genres.dropLast(1)}" + "$baseUrl/tags/${genres.dropLast(1)}?offset=${20 * (pageNum - 1)}" } else { - "$baseUrl/?do=search&subaction=search&story=$query" + "$baseUrl/?do=search&subaction=search&story=$query&search_start=$pageNum" } } return GET(url, headers) @@ -85,28 +90,29 @@ class Mangachan : ParsedHttpSource() { override fun searchMangaParse(response: Response): MangasPage { val document = response.asJsoup() + var hasNextPage = false + val mangas = document.select(searchMangaSelector()).map { element -> searchMangaFromElement(element) } - // FIXME -// val allIgnore = filters.all { it.state == Filter.TriState.STATE_IGNORE } -// searchMangaNextPageSelector().let { selector -> -// if (page.nextPageUrl.isNullOrEmpty() && allIgnore) { -// val onClick = document.select(selector).first()?.attr("onclick") -// val pageNum = onClick?.substring(23, onClick.indexOf("); return(false)")) -// page.nextPageUrl = searchMangaInitialUrl(query, emptyList()) + "&search_start=" + pageNum -// } -// } -// -// searchGenresNextPageSelector().let { selector -> -// if (page.nextPageUrl.isNullOrEmpty() && !allIgnore) { -// val url = document.select(selector).first()?.attr("href") -// page.nextPageUrl = searchMangaInitialUrl(query, filters) + url -// } -// } + 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 + } - return MangasPage(mangas, false) + val nextGenresPage = document.select(searchGenresNextPageSelector()) + if (nextGenresPage.isNotEmpty()) { + hasNextPage = true + } + + return MangasPage(mangas, hasNextPage) } override fun mangaDetailsParse(document: Document): SManga { @@ -146,7 +152,7 @@ class Mangachan : ParsedHttpSource() { } override fun pageListParse(response: Response): List { - val html = response.body().string() + val html = response.body()!!.string() val beginIndex = html.indexOf("fullimg\":[") + 10 val endIndex = html.indexOf(",]", beginIndex) val trimmedHtml = html.substring(beginIndex, endIndex).replace("\"", "") diff --git a/src/ru/mintmanga/build.gradle b/src/ru/mintmanga/build.gradle index 153937d9c..4c246d056 100644 --- a/src/ru/mintmanga/build.gradle +++ b/src/ru/mintmanga/build.gradle @@ -6,7 +6,7 @@ ext { pkgNameSuffix = "ru.mintmanga" extClass = '.Mintmanga' extVersionCode = 1 - extVersionSuffix = 1 + extVersionSuffix = 2 libVersion = '1.0' } diff --git a/src/ru/mintmanga/src/eu/kanade/tachiyomi/extension/ru/mintmanga/Mintmanga.kt b/src/ru/mintmanga/src/eu/kanade/tachiyomi/extension/ru/mintmanga/Mintmanga.kt index 39c1fc5bf..2ad105c97 100644 --- a/src/ru/mintmanga/src/eu/kanade/tachiyomi/extension/ru/mintmanga/Mintmanga.kt +++ b/src/ru/mintmanga/src/eu/kanade/tachiyomi/extension/ru/mintmanga/Mintmanga.kt @@ -102,11 +102,25 @@ class Mintmanga : ParsedHttpSource() { } override fun prepareNewChapter(chapter: SChapter, manga: SManga) { - chapter.chapter_number = -2f + 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 html = response.body()!!.string() val beginIndex = html.indexOf("rm_h.init( [") val endIndex = html.indexOf("], 0, false);", beginIndex) val trimmedHtml = html.substring(beginIndex, endIndex) diff --git a/src/ru/readmanga/build.gradle b/src/ru/readmanga/build.gradle index 67d70272e..a4b90b6cc 100644 --- a/src/ru/readmanga/build.gradle +++ b/src/ru/readmanga/build.gradle @@ -6,7 +6,7 @@ ext { pkgNameSuffix = "ru.readmanga" extClass = '.Readmanga' extVersionCode = 1 - extVersionSuffix = 1 + extVersionSuffix = 2 libVersion = '1.0' } diff --git a/src/ru/readmanga/src/eu/kanade/tachiyomi/extension/ru/readmanga/Readmanga.kt b/src/ru/readmanga/src/eu/kanade/tachiyomi/extension/ru/readmanga/Readmanga.kt index 89b4f9cd9..d8140174f 100644 --- a/src/ru/readmanga/src/eu/kanade/tachiyomi/extension/ru/readmanga/Readmanga.kt +++ b/src/ru/readmanga/src/eu/kanade/tachiyomi/extension/ru/readmanga/Readmanga.kt @@ -102,11 +102,25 @@ class Readmanga : ParsedHttpSource() { } override fun prepareNewChapter(chapter: SChapter, manga: SManga) { - chapter.chapter_number = -2f + 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 html = response.body()!!.string() val beginIndex = html.indexOf("rm_h.init( [") val endIndex = html.indexOf("], 0, false);", beginIndex) val trimmedHtml = html.substring(beginIndex, endIndex)