diff --git a/multisrc/overrides/dooplay/jetanime/additional.gradle b/multisrc/overrides/dooplay/jetanime/additional.gradle new file mode 100644 index 000000000..fb3fc5e35 --- /dev/null +++ b/multisrc/overrides/dooplay/jetanime/additional.gradle @@ -0,0 +1,4 @@ +dependencies { + implementation "dev.datlag.jsunpacker:jsunpacker:1.0.1" + implementation(project(':lib-playlist-utils')) +} diff --git a/multisrc/overrides/dooplay/jetanime/res/mipmap-hdpi/ic_launcher.png b/multisrc/overrides/dooplay/jetanime/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 000000000..5b363c624 Binary files /dev/null and b/multisrc/overrides/dooplay/jetanime/res/mipmap-hdpi/ic_launcher.png differ diff --git a/multisrc/overrides/dooplay/jetanime/res/mipmap-mdpi/ic_launcher.png b/multisrc/overrides/dooplay/jetanime/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 000000000..a37039a10 Binary files /dev/null and b/multisrc/overrides/dooplay/jetanime/res/mipmap-mdpi/ic_launcher.png differ diff --git a/multisrc/overrides/dooplay/jetanime/res/mipmap-xhdpi/ic_launcher.png b/multisrc/overrides/dooplay/jetanime/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 000000000..c4fa0f693 Binary files /dev/null and b/multisrc/overrides/dooplay/jetanime/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/multisrc/overrides/dooplay/jetanime/res/mipmap-xxhdpi/ic_launcher.png b/multisrc/overrides/dooplay/jetanime/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..d838b9ff4 Binary files /dev/null and b/multisrc/overrides/dooplay/jetanime/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/multisrc/overrides/dooplay/jetanime/res/mipmap-xxxhdpi/ic_launcher.png b/multisrc/overrides/dooplay/jetanime/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 000000000..c1b91cf00 Binary files /dev/null and b/multisrc/overrides/dooplay/jetanime/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/multisrc/overrides/dooplay/jetanime/res/web_hi_res_512.png b/multisrc/overrides/dooplay/jetanime/res/web_hi_res_512.png new file mode 100644 index 000000000..b219ab1b9 Binary files /dev/null and b/multisrc/overrides/dooplay/jetanime/res/web_hi_res_512.png differ diff --git a/multisrc/overrides/dooplay/jetanime/src/JetAnime.kt b/multisrc/overrides/dooplay/jetanime/src/JetAnime.kt new file mode 100644 index 000000000..c87a2f82a --- /dev/null +++ b/multisrc/overrides/dooplay/jetanime/src/JetAnime.kt @@ -0,0 +1,170 @@ +package eu.kanade.tachiyomi.animeextension.fr.jetanime + +import eu.kanade.tachiyomi.animeextension.fr.jetanime.extractors.HdsplayExtractor +import eu.kanade.tachiyomi.animeextension.fr.jetanime.extractors.SentinelExtractor +import eu.kanade.tachiyomi.animesource.model.AnimeFilter +import eu.kanade.tachiyomi.animesource.model.AnimeFilterList +import eu.kanade.tachiyomi.animesource.model.AnimesPage +import eu.kanade.tachiyomi.animesource.model.SAnime +import eu.kanade.tachiyomi.animesource.model.Video +import eu.kanade.tachiyomi.multisrc.dooplay.DooPlay +import eu.kanade.tachiyomi.network.GET +import eu.kanade.tachiyomi.util.asJsoup +import okhttp3.Response +import org.jsoup.nodes.Element + +class JetAnime : DooPlay( + "fr", + "JetAnime", + "https://ssl.jetanimes.com", +) { + + // ============================== Popular =============================== + + override fun popularAnimeRequest(page: Int) = GET(baseUrl, headers) + + override fun popularAnimeSelector(): String = "aside#dtw_content_views-2 div.dtw_content > article" + + override fun popularAnimeNextPageSelector() = null + + // =============================== Latest =============================== + + override fun latestUpdatesFromElement(element: Element): SAnime { + return SAnime.create().apply { + val img = element.selectFirst("img")!! + val url = element.selectFirst("a")?.attr("href") ?: element.attr("href") + val slug = url.substringAfter("/episodes/") + setUrlWithoutDomain("/serie/${slug.substringBeforeLast("-episode").substringBeforeLast("-saison")}") + title = img.attr("alt") + thumbnail_url = img.getImageUrl() + } + } + + override fun latestUpdatesNextPageSelector(): String = "div.pagination > span.current + a" + + // =============================== Search =============================== + + override fun searchAnimeParse(response: Response): AnimesPage { + val document = response.asJsoup() + val url = response.request.url.toString() + + val animeList = when { + "/?s=" in url -> { // Search by name. + document.select(searchSelector()) + .map(::searchAnimeFromElement) + } + "/annee/" in url -> { // Search by year + document.select(searchYearSelector()) + .map(::popularAnimeFromElement) + } + else -> { // Search by some kind of filter, like genres or popularity. + document.select(searchAnimeSelector()) + .map(::popularAnimeFromElement) + } + } + + val hasNextPage = document.selectFirst(searchAnimeNextPageSelector()) != null + return AnimesPage(animeList, hasNextPage) + } + + private fun searchSelector() = "div.search-page > div.result-item div.image a" + + private fun searchYearSelector() = "div.content > div.items > article div.poster" + + override fun searchAnimeSelector() = "div#archive-content > article > div.poster" + + // ============================== Filters =============================== + + override val fetchGenres = false + + override fun getFilterList(): AnimeFilterList = AnimeFilterList( + AnimeFilter.Header("Text search ignores filters"), + AnimeFilter.Header("Only one filter at a time works"), + SubPageFilter(), + YearFilter(), + ) + + private class SubPageFilter : UriPartFilter( + "Sub-page", + arrayOf( + Pair("", ""), + Pair("2023", "/annee/2023"), + Pair("2022", "/annee/2022"), + Pair("2021", "/annee/2021"), + Pair("2020", "/annee/2020"), + Pair("2019", "/annee/2019"), + Pair("2018", "/annee/2018"), + Pair("2017", "/annee/2017"), + Pair("2016", "/annee/2016"), + Pair("2015", "/annee/2015"), + Pair("2014", "/annee/2014"), + Pair("2013", "/annee/2013"), + Pair("2012", "/annee/2012"), + Pair("2011", "/annee/2011"), + Pair("2010", "/annee/2010"), + Pair("2009", "/annee/2009"), + ), + ) + + // ============================ Video Links ============================= + + private val noRedirects = client.newBuilder() + .followRedirects(false) + .followSslRedirects(false) + .build() + + override fun videoListParse(response: Response): List