diff --git a/src/fr/japscan/build.gradle b/src/fr/japscan/build.gradle index 18a6bcafa..aae980637 100644 --- a/src/fr/japscan/build.gradle +++ b/src/fr/japscan/build.gradle @@ -5,8 +5,13 @@ ext { appName = 'Tachiyomi: Japscan' pkgNameSuffix = 'fr.japscan' extClass = '.Japscan' - extVersionCode = 4 + extVersionCode = 5 libVersion = '1.2' } apply from: "$rootDir/common.gradle" + +dependencies { + implementation 'com.google.code.gson:gson:2.8.5' + implementation 'org.apache.commons:commons-lang3:3.8.1' +} \ No newline at end of file diff --git a/src/fr/japscan/src/eu/kanade/tachiyomi/extension/fr/japscan/Japscan.kt b/src/fr/japscan/src/eu/kanade/tachiyomi/extension/fr/japscan/Japscan.kt index 8b7265e2d..dca3d6d91 100644 --- a/src/fr/japscan/src/eu/kanade/tachiyomi/extension/fr/japscan/Japscan.kt +++ b/src/fr/japscan/src/eu/kanade/tachiyomi/extension/fr/japscan/Japscan.kt @@ -5,17 +5,23 @@ package eu.kanade.tachiyomi.extension.fr.japscan * @brief Defines class Japscan for french source Japscan * @date 2018-09-02 * @version 1.0 - * - * There is no research page on this source, so searching just returns all mangas from the source - * There are also no thumbnails for mangas */ +import com.google.gson.JsonObject +import com.google.gson.JsonParser import eu.kanade.tachiyomi.network.GET +import eu.kanade.tachiyomi.network.POST import eu.kanade.tachiyomi.source.model.* import eu.kanade.tachiyomi.source.online.ParsedHttpSource +import okhttp3.FormBody import okhttp3.Request +import okhttp3.Response +import okhttp3.OkHttpClient import org.jsoup.nodes.Document import org.jsoup.nodes.Element +import java.text.ParseException +import java.text.SimpleDateFormat +import org.apache.commons.lang3.StringUtils class Japscan : ParsedHttpSource() { @@ -29,13 +35,21 @@ class Japscan : ParsedHttpSource() { override val supportsLatest = true - override fun popularMangaSelector() = "ul.increment-list > li" + override val client: OkHttpClient = network.cloudflareClient + + companion object { + val dateFormat by lazy { + SimpleDateFormat("dd MMM yyyy") + } + } + + override fun popularMangaSelector() = "#top_mangas_week li > span" override fun popularMangaRequest(page: Int): Request { return GET("$baseUrl", headers) } - override fun latestUpdatesSelector() = "#dernieres_sorties > div.manga" + override fun latestUpdatesSelector() = "#chapters > div:eq(0) > h3.text-truncate" override fun latestUpdatesRequest(page: Int): Request { return GET("$baseUrl", headers) @@ -46,46 +60,71 @@ class Japscan : ParsedHttpSource() { element.select("a").first().let { manga.setUrlWithoutDomain(it.attr("href")) manga.title = it.text() + + val s = StringUtils.stripAccents(it.text()) + .replace("[\\W]".toRegex(), "-") + .replace("[-]{2,}".toRegex(), "-") + .replace("^-|-$".toRegex(), "") + manga.thumbnail_url = "$baseUrl/imgs/mangas/$s.jpg" } return manga } - override fun latestUpdatesFromElement(element: Element): SManga { - return popularMangaFromElement(element) - } + override fun latestUpdatesFromElement(element: Element): SManga = popularMangaFromElement(element) override fun popularMangaNextPageSelector() = "#theresnone" override fun latestUpdatesNextPageSelector() = "#theresnone" override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { - return GET("$baseUrl/mangas/", headers) - } - - override fun searchMangaSelector() = "div#liste_mangas > div.row" - - override fun searchMangaFromElement(element: Element): SManga { - val manga = SManga.create() - element.select("a").first().let { - manga.setUrlWithoutDomain(it.attr("href")) - manga.title = it.text() + val form = FormBody.Builder().apply { + add("search", StringUtils.stripAccents(query)) } - return manga + return POST("$baseUrl/search/", headers, form.build()) } + override fun searchMangaParse(response: Response): MangasPage { + val result = JsonParser().parse(response.body()!!.string()).asJsonArray + + if (!result!!.isJsonArray) + return MangasPage(emptyList(), false) + + val searchMangas = result.map { + searchMangaItemParse(it.asJsonObject) + } + + return MangasPage(searchMangas, false) + } + + private fun searchMangaItemParse(obj: JsonObject) = SManga.create().apply { + title = obj["name"]!!.asString + thumbnail_url = "$baseUrl/${obj["image"]!!.asString}" + url = obj["url"]!!.asString + } + + override fun searchMangaSelector() = "#theresnone" + + override fun searchMangaFromElement(element: Element) = popularMangaFromElement(element) + override fun searchMangaNextPageSelector() = "#theresnone" override fun mangaDetailsParse(document: Document): SManga { - val infoElement = document.select("div.content").first() - val rowElement = infoElement.select("div.table > div.row").first() + val infoElement = document.select("div#main > .card > .card-body").first() val manga = SManga.create() - manga.author = rowElement.select("div:eq(0)").first()?.text() - manga.artist = rowElement.select("div:eq(0)").first()?.text() - manga.genre = rowElement.select("div:eq(2)").first()?.text() - manga.description = infoElement.select("div#synopsis").text() - - manga.status = rowElement.select("div:eq(4)").first()?.text().orEmpty().let { parseStatus(it) } + manga.thumbnail_url = "$baseUrl/${infoElement.select(".d-flex > div.m-2:eq(0) > img").attr("src")}" + + infoElement.select(".d-flex > div.m-2:eq(1) > p.mb-2").forEachIndexed { _, el -> + when (el.select("span").text().trim()) { + "Auteur(s):" -> manga.author = el.text().replace("Auteur(s):", "").trim() + "Artiste(s):" -> manga.artist = el.text().replace("Artiste(s):", "").trim() + "Genre(s):" -> manga.genre = el.text().replace("Genre(s):", "").trim() + "Statut:" -> manga.status = el.text().replace("Statut:", "").trim().let { + parseStatus(it) + } + } + } + manga.description = infoElement.select("> p").text().orEmpty() return manga } @@ -96,29 +135,36 @@ class Japscan : ParsedHttpSource() { else -> SManga.UNKNOWN } - override fun chapterListSelector() = "div#liste_chapitres > ul > li" + override fun chapterListSelector() = "div#chapters_list > div.collapse > div.chapters_list" 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 = 0 + chapter.name = urlElement.text().replace(" VUS", "") + chapter.date_upload = element.select("> span").text().trim().let { parseChapterDate(it) } return chapter } + private fun parseChapterDate(date: String): Long { + return try { + dateFormat.parse(date).time + } catch (e: ParseException) { + 0L + } + } + override fun pageListParse(document: Document): List { val pages = mutableListOf() + val imagePath = "(.*\\/).*".toRegex().find(document.select("#image").attr("data-src")) + document.select("select#pages").first()?.select("option")?.forEach { - pages.add(Page(pages.size, "$baseUrl${it.attr("value")}")) + pages.add(Page(pages.size, "", "${imagePath?.groupValues?.get(1)}${it.attr("data-img")}")) } return pages } - override fun imageUrlParse(document: Document): String { - val url = document.getElementById("image").attr("src") - return url - } + override fun imageUrlParse(document: Document): String = "" }