diff --git a/src/en/artlapsa/build.gradle b/src/en/artlapsa/build.gradle new file mode 100644 index 000000000..32836cf80 --- /dev/null +++ b/src/en/artlapsa/build.gradle @@ -0,0 +1,10 @@ +ext { + extName = 'Art Lapsa' + extClass = '.ArtLapsa' + themePkg = 'keyoapp' + baseUrl = 'https://artlapsa.com' + overrideVersionCode = 0 + isNsfw = false +} + +apply from: "$rootDir/common.gradle" diff --git a/src/en/artlapsa/res/mipmap-hdpi/ic_launcher.png b/src/en/artlapsa/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 000000000..e8e17260b Binary files /dev/null and b/src/en/artlapsa/res/mipmap-hdpi/ic_launcher.png differ diff --git a/src/en/artlapsa/res/mipmap-mdpi/ic_launcher.png b/src/en/artlapsa/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 000000000..e6d1aecc3 Binary files /dev/null and b/src/en/artlapsa/res/mipmap-mdpi/ic_launcher.png differ diff --git a/src/en/artlapsa/res/mipmap-xhdpi/ic_launcher.png b/src/en/artlapsa/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 000000000..fc545de1d Binary files /dev/null and b/src/en/artlapsa/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/src/en/artlapsa/res/mipmap-xxhdpi/ic_launcher.png b/src/en/artlapsa/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..7405ccf39 Binary files /dev/null and b/src/en/artlapsa/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/src/en/artlapsa/res/mipmap-xxxhdpi/ic_launcher.png b/src/en/artlapsa/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 000000000..0d1a27ce0 Binary files /dev/null and b/src/en/artlapsa/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/src/en/artlapsa/src/eu/kanade/tachiyomi/extension/en/artlapsa/ArtLapsa.kt b/src/en/artlapsa/src/eu/kanade/tachiyomi/extension/en/artlapsa/ArtLapsa.kt new file mode 100644 index 000000000..1de49b4ba --- /dev/null +++ b/src/en/artlapsa/src/eu/kanade/tachiyomi/extension/en/artlapsa/ArtLapsa.kt @@ -0,0 +1,104 @@ +package eu.kanade.tachiyomi.extension.en.artlapsa + +import eu.kanade.tachiyomi.multisrc.keyoapp.Keyoapp +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.util.asJsoup +import keiyoushi.utils.parseAs +import kotlinx.serialization.Serializable +import okhttp3.HttpUrl.Companion.toHttpUrl +import okhttp3.Request +import okhttp3.Response +import org.jsoup.nodes.Document +import java.net.URLDecoder + +class ArtLapsa : Keyoapp("Art Lapsa", "https://artlapsa.com", "en") { + + override fun popularMangaParse(response: Response): MangasPage { + val mangas = super.popularMangaParse(response).mangas + .distinctBy { it.url } + + return MangasPage(mangas, false) + } + + override fun genresRequest() = GET("$baseUrl/search/", headers) + + override fun parseGenres(document: Document): List { + return document.select("[x-data*=genre] button").map { + val name = it.text() + val id = it.attr("wire:key") + + Genre(name, id) + } + } + + override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { + val url = "$baseUrl/search".toHttpUrl().newBuilder().apply { + if (query.isNotBlank()) { + addQueryParameter("title", query) + } + filters.firstOrNull { it is GenreList }?.also { + val filter = it as GenreList + filter.state + .filter { it.state } + .forEach { genre -> + addQueryParameter("genre", genre.id) + } + } + }.build() + + return GET(url, headers) + } + + override fun searchMangaSelector() = "[wire:snapshot*=pages.search] button[tags]" + + override fun searchMangaParse(response: Response): MangasPage { + runCatching { fetchGenres() } + + val mangas = response.asJsoup() + .select(searchMangaSelector()) + .map(::searchMangaFromElement) + + return MangasPage(mangas, false) + } + + override val descriptionSelector = "#expand_content" + override val statusSelector = "[alt=Status]" + override val genreSelector = "[alt=Type]" + + override fun chapterListSelector(): String { + if (!preferences.showPaidChapters) { + return "#chapters > a:not(:has(.text-sm span:matches(Upcoming))):not(:has(img[src*=star-circle]))" + } + return "#chapters > a:not(:has(.text-sm span:matches(Upcoming)))" + } + + override fun pageListParse(document: Document): List { + val (pages, baseLink) = document.selectFirst("[x-data]")!!.attr("x-data") + .replace(spaces, "") + .let { + val pages = pagesRegex.find(it)!!.groupValues[1] + .let { encoded -> URLDecoder.decode(encoded, "UTF-8") } + .parseAs>() + + val baseLink = linkRegex.find(it)!!.groupValues[2] + + pages to baseLink + } + + return pages.mapIndexed { i, img -> + Page(i, document.location(), baseLink + img.path) + } + } +} + +private val spaces = Regex("\\s") +private val pagesRegex = Regex("pages:(\\[[^]]+])") +private val linkRegex = """baseLink:(["'])(.+?)\1""".toRegex() + +@Serializable +class Path( + val path: String, +)