diff --git a/src/all/ciayo/build.gradle b/src/all/ciayo/build.gradle new file mode 100644 index 000000000..007c4bf0f --- /dev/null +++ b/src/all/ciayo/build.gradle @@ -0,0 +1,17 @@ +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' + +ext { + appName = 'Tachiyomi: Ciayo Comics' + pkgNameSuffix = 'all.ciayo' + extClass = '.CiayoFactory' + extVersionCode = 1 + libVersion = '1.2' +} + +dependencies { + compileOnly 'com.google.code.gson:gson:2.8.2' + compileOnly 'com.github.salomonbrys.kotson:kotson:2.5.0' +} + +apply from: "$rootDir/common.gradle" diff --git a/src/all/ciayo/res/mipmap-hdpi/ic_launcher.png b/src/all/ciayo/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 000000000..c04c55feb Binary files /dev/null and b/src/all/ciayo/res/mipmap-hdpi/ic_launcher.png differ diff --git a/src/all/ciayo/res/mipmap-mdpi/ic_launcher.png b/src/all/ciayo/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 000000000..2b083069a Binary files /dev/null and b/src/all/ciayo/res/mipmap-mdpi/ic_launcher.png differ diff --git a/src/all/ciayo/res/mipmap-xhdpi/ic_launcher.png b/src/all/ciayo/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 000000000..a03528bc4 Binary files /dev/null and b/src/all/ciayo/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/src/all/ciayo/res/mipmap-xxhdpi/ic_launcher.png b/src/all/ciayo/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..727a7ddb7 Binary files /dev/null and b/src/all/ciayo/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/src/all/ciayo/res/mipmap-xxxhdpi/ic_launcher.png b/src/all/ciayo/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 000000000..556893b56 Binary files /dev/null and b/src/all/ciayo/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/src/all/ciayo/res/web_hi_res_512.png b/src/all/ciayo/res/web_hi_res_512.png new file mode 100644 index 000000000..3f9c9904c Binary files /dev/null and b/src/all/ciayo/res/web_hi_res_512.png differ diff --git a/src/all/ciayo/src/eu/kanade/tachiyomi/extension/all/ciayo/Ciayo.kt b/src/all/ciayo/src/eu/kanade/tachiyomi/extension/all/ciayo/Ciayo.kt new file mode 100644 index 000000000..0cc7bbee9 --- /dev/null +++ b/src/all/ciayo/src/eu/kanade/tachiyomi/extension/all/ciayo/Ciayo.kt @@ -0,0 +1,187 @@ +package eu.kanade.tachiyomi.extension.all.ciayo + +import com.github.salomonbrys.kotson.get +import com.github.salomonbrys.kotson.long +import com.github.salomonbrys.kotson.nullString +import com.github.salomonbrys.kotson.string +import com.google.gson.JsonElement +import com.google.gson.JsonParser +import eu.kanade.tachiyomi.network.GET +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.HttpSource +import eu.kanade.tachiyomi.util.asJsoup +import okhttp3.Request +import okhttp3.Response +import org.jsoup.nodes.Element + +abstract class Ciayo(override val lang: String) : HttpSource() { + + //Info + override val name: String = "Ciayo Comics" + override val baseUrl: String = "https://www.ciayo.com" + private val apiUrl = "https://vueserion.ciayo.com/3.3/comics" + override val supportsLatest: Boolean = true + + //Page Helpers + private var next: String? = "" + private var previous: String? = "" + + //Popular + override fun popularMangaParse(response: Response): MangasPage { + val body = response.body()!!.string() + val json = JsonParser().parse(body)["c"] + val data = json["data"].asJsonArray + + val mangas = data.map { jsonObject -> + popularMangaFromJson(jsonObject) + } + + previous = next + next = json["meta"]["cursor"]["next"].nullString + + val hasNextPage = json["meta"]["more"].string == "true" + + return MangasPage(mangas, hasNextPage) + } + + override fun popularMangaRequest(page: Int): Request { + when (page) { + 1 -> { + previous = "" + next = "" + } + 2 -> previous = "null" + } + val url = + "$apiUrl/?current=$next&previous=$previous&app=desktop&type=comic&count=15&language=$lang&with=image,genres" + return GET(url) + } + + private fun popularMangaFromJson(json: JsonElement): SManga = SManga.create().apply { + title = json["title"].string + setUrlWithoutDomain(json["share_url"].string) + thumbnail_url = json["image"]["cover"].string + } + + //Latest + + override fun latestUpdatesParse(response: Response): MangasPage { + val body = response.body()!!.string() + val json = JsonParser().parse(body)["c"] + val data = json["data"].asJsonArray + + val mangas = data.map { jsonObject -> + latestUpdatesFromJson(jsonObject) + } + + previous = next + next = json["meta"]["cursor"]["next"].nullString + + val hasNextPage = json["meta"]["more"].string == "true" + + return MangasPage(mangas, hasNextPage) + } + + override fun latestUpdatesRequest(page: Int): Request { + when (page) { + 1 -> { + previous = "" + next = "" + } + 2 -> previous = "null" + } + val url = + "$apiUrl/new-release?app=desktop&language=$lang¤t=$next&previous=$previous&count=10&with=image,genres&type=comic" + return GET(url) + } + + private fun latestUpdatesFromJson(json: JsonElement): SManga = popularMangaFromJson(json) + + //Search + + override fun searchMangaParse(response: Response): MangasPage { + val document = response.asJsoup() + + val mangas = document.select(searchMangaSelector()).map { element -> + searchMangaFromElement(element) + } + + val hasNextPage = searchMangaNextPageSelector().let { selector -> + document.select(selector).first() + } != null + + return MangasPage(mangas, hasNextPage) + + } + + private fun searchMangaSelector() = "div.ais-Hits li.ais-Hits-item" + private fun searchMangaNextPageSelector() = "a[aria-label=Next page]" + private fun searchMangaFromElement(element: Element): SManga = SManga.create().apply { + thumbnail_url = element.select("img").attr("abs:src") + element.select("a.comic-link").apply { + title = this.text().trim() + url = this.attr("href") + } + + } + + override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { + return GET("$baseUrl/$lang/search?query=$query&page=$page") + } + + //Details + + override fun mangaDetailsParse(response: Response): SManga { + val document = response.asJsoup() + val script = document.select("script:containsdata(NEXT_DATA)").html() + val data = script.substringAfter("__NEXT_DATA__ =").substringBefore("};").trim() + "}" + val json = JsonParser().parse(data)["props"]["pageProps"]["comicProfile"] + return SManga.create().apply { + title = json["title"].string + author = json["author"].string + artist = author + description = json["description"].string + genre = json["genres"].asJsonArray.joinToString(", ") { it["name"].string } + thumbnail_url = json["image"]["cover"].string + } + } + + //Chapters + + override fun chapterListRequest(manga: SManga): Request { + val slug = manga.url.substringAfterLast("/") + return GET("$apiUrl/$slug/chapters?current=&count=999&app=desktop&language=$lang&with=image,comic&sort=desc") + } + + override fun chapterListParse(response: Response): List { + val body = response.body()!!.string() + val json = JsonParser().parse(body)["c"] + val data = json["data"].asJsonArray + return data.filterNot { it["status"].string == "coming-soon" }.map { + SChapter.create().apply { + name = "${it["episode"].string} - ${it["name"].string}" + scanlator = "[${it["status"].string}]" + setUrlWithoutDomain(it["share_url"].string) + date_upload = it["release_date"].long * 1000 + } + } + + } + + //Pages + + override fun pageListParse(response: Response): List = mutableListOf().apply { + val document = response.asJsoup() + document.select("div.chapterViewer img").forEach { + add(Page(size, "", it.attr("abs:src"))) + } + + } + + override fun imageUrlParse(response: Response): String = throw Exception("ImgParse Not Used") + +} diff --git a/src/all/ciayo/src/eu/kanade/tachiyomi/extension/all/ciayo/CiayoFactory.kt b/src/all/ciayo/src/eu/kanade/tachiyomi/extension/all/ciayo/CiayoFactory.kt new file mode 100644 index 000000000..993504149 --- /dev/null +++ b/src/all/ciayo/src/eu/kanade/tachiyomi/extension/all/ciayo/CiayoFactory.kt @@ -0,0 +1,17 @@ +package eu.kanade.tachiyomi.extension.all.ciayo + +import eu.kanade.tachiyomi.source.Source +import eu.kanade.tachiyomi.source.SourceFactory + +class CiayoFactory : SourceFactory { + override fun createSources(): List = listOf( + CiayoID(), + CiayoEN() + ) +} + +class CiayoID : Ciayo("id") + +class CiayoEN : Ciayo("en") + +