diff --git a/src/en/kissmanga/build.gradle b/src/en/kissmanga/build.gradle deleted file mode 100644 index c12ac974e..000000000 --- a/src/en/kissmanga/build.gradle +++ /dev/null @@ -1,17 +0,0 @@ -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' - -ext { - appName = 'Tachiyomi: Kissmanga' - pkgNameSuffix = 'en.kissmanga' - extClass = '.Kissmanga' - extVersionCode = 17 - libVersion = '1.2' -} - -dependencies { - implementation project(':lib-ratelimit') - compileOnly project(':duktape-stub') -} - -apply from: "$rootDir/common.gradle" diff --git a/src/en/kissmanga/res/mipmap-hdpi/ic_launcher.png b/src/en/kissmanga/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index 10690a6af..000000000 Binary files a/src/en/kissmanga/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/src/en/kissmanga/res/mipmap-mdpi/ic_launcher.png b/src/en/kissmanga/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index 1b85f4218..000000000 Binary files a/src/en/kissmanga/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/src/en/kissmanga/res/mipmap-xhdpi/ic_launcher.png b/src/en/kissmanga/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index 0ea437a89..000000000 Binary files a/src/en/kissmanga/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/src/en/kissmanga/res/mipmap-xxhdpi/ic_launcher.png b/src/en/kissmanga/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index 4a42484fa..000000000 Binary files a/src/en/kissmanga/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/src/en/kissmanga/res/mipmap-xxxhdpi/ic_launcher.png b/src/en/kissmanga/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index d5fd47da7..000000000 Binary files a/src/en/kissmanga/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/src/en/kissmanga/res/web_hi_res_512.png b/src/en/kissmanga/res/web_hi_res_512.png deleted file mode 100644 index 0b95deb9a..000000000 Binary files a/src/en/kissmanga/res/web_hi_res_512.png and /dev/null differ 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 deleted file mode 100644 index 5efbe3f6b..000000000 --- a/src/en/kissmanga/src/eu/kanade/tachiyomi/extension/en/kissmanga/Kissmanga.kt +++ /dev/null @@ -1,273 +0,0 @@ -package eu.kanade.tachiyomi.extension.en.kissmanga - -import com.squareup.duktape.Duktape -import eu.kanade.tachiyomi.lib.ratelimit.RateLimitInterceptor -import eu.kanade.tachiyomi.network.GET -import eu.kanade.tachiyomi.network.POST -import eu.kanade.tachiyomi.source.model.Filter -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 java.text.SimpleDateFormat -import java.util.regex.Pattern -import okhttp3.FormBody -import okhttp3.Headers -import okhttp3.OkHttpClient -import okhttp3.Request -import okhttp3.Response -import org.jsoup.Jsoup -import org.jsoup.nodes.Document -import org.jsoup.nodes.Element - -class Kissmanga : ParsedHttpSource() { - - override val id: Long = 4 - - override val name = "Kissmanga" - - override val baseUrl = "https://kissmanga.com" - - override val lang = "en" - - override val supportsLatest = true - - override val client: OkHttpClient = network.cloudflareClient.newBuilder() - .addNetworkInterceptor(RateLimitInterceptor(5)) - .build() - - override fun headersBuilder(): Headers.Builder { - return Headers.Builder() - .add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.113 Safari/537.36") - } - - 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("$baseUrl/MangaList/LatestUpdate?page=$page", headers) - } - - override fun popularMangaFromElement(element: Element): SManga { - val manga = SManga.create() - manga.thumbnail_url = Jsoup.parseBodyFragment(element.select("td").attr("title")).select("img").attr("abs:src") - 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 - 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 { - for (filter in filters) { - when (filter) { - is SortTrending -> if (filter.state) return GET("$baseUrl/MangaList/Trending?page=$page", headers) - is NewManga -> if (filter.state) return GET("$baseUrl/MangaList/Newest?page=$page", headers) - } - } - 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("""lst[A-Z]+.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) - private class SortTrending : Filter.CheckBox("View Trending Manga") - private class NewManga : Filter.CheckBox("View New Manga") - - override fun getFilterList() = FilterList( - Author(), - Status(), - GenreList(getGenreList()), - Filter.Separator(), - Filter.Header("Change Manga List"), - SortTrending(), - NewManga() - ) - - // $("select[name=\"genres\"]").map((i,el) => `Genre("${$(el).next().text().trim()}", ${i})`).get().join(',\n') - // on https://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("Isekai"), - 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") - ) -}