diff --git a/src/id/oploverz/build.gradle b/src/id/oploverz/build.gradle index 978e7cdeee..df492cc72d 100644 --- a/src/id/oploverz/build.gradle +++ b/src/id/oploverz/build.gradle @@ -5,7 +5,7 @@ ext { extName = 'Oploverz' pkgNameSuffix = 'id.oploverz' extClass = '.Oploverz' - extVersionCode = 16 + extVersionCode = 17 libVersion = '13' } diff --git a/src/id/oploverz/res/mipmap-hdpi/ic_launcher.png b/src/id/oploverz/res/mipmap-hdpi/ic_launcher.png index b9e963713c..9639d6f3a0 100644 Binary files a/src/id/oploverz/res/mipmap-hdpi/ic_launcher.png and b/src/id/oploverz/res/mipmap-hdpi/ic_launcher.png differ diff --git a/src/id/oploverz/res/mipmap-mdpi/ic_launcher.png b/src/id/oploverz/res/mipmap-mdpi/ic_launcher.png index edc11714ea..456ed83ca1 100644 Binary files a/src/id/oploverz/res/mipmap-mdpi/ic_launcher.png and b/src/id/oploverz/res/mipmap-mdpi/ic_launcher.png differ diff --git a/src/id/oploverz/res/mipmap-xhdpi/ic_launcher.png b/src/id/oploverz/res/mipmap-xhdpi/ic_launcher.png index f19e639016..461049d409 100644 Binary files a/src/id/oploverz/res/mipmap-xhdpi/ic_launcher.png and b/src/id/oploverz/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/src/id/oploverz/res/mipmap-xxhdpi/ic_launcher.png b/src/id/oploverz/res/mipmap-xxhdpi/ic_launcher.png index 7a3d08c3e4..ec6b148e4e 100644 Binary files a/src/id/oploverz/res/mipmap-xxhdpi/ic_launcher.png and b/src/id/oploverz/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/src/id/oploverz/res/mipmap-xxxhdpi/ic_launcher.png b/src/id/oploverz/res/mipmap-xxxhdpi/ic_launcher.png index fdc32d03fb..7419537eeb 100644 Binary files a/src/id/oploverz/res/mipmap-xxxhdpi/ic_launcher.png and b/src/id/oploverz/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/src/id/oploverz/res/web_hi_res_512.png b/src/id/oploverz/res/web_hi_res_512.png index 4d668b41bd..f6e7473a05 100644 Binary files a/src/id/oploverz/res/web_hi_res_512.png and b/src/id/oploverz/res/web_hi_res_512.png differ diff --git a/src/id/oploverz/src/eu/kanade/tachiyomi/animeextension/id/oploverz/Oploverz.kt b/src/id/oploverz/src/eu/kanade/tachiyomi/animeextension/id/oploverz/Oploverz.kt index d5226a22cd..ebaba9eb58 100644 --- a/src/id/oploverz/src/eu/kanade/tachiyomi/animeextension/id/oploverz/Oploverz.kt +++ b/src/id/oploverz/src/eu/kanade/tachiyomi/animeextension/id/oploverz/Oploverz.kt @@ -6,234 +6,230 @@ import androidx.preference.ListPreference import androidx.preference.PreferenceScreen import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource 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.SEpisode import eu.kanade.tachiyomi.animesource.model.Video -import eu.kanade.tachiyomi.animesource.online.ParsedAnimeHttpSource +import eu.kanade.tachiyomi.animesource.online.AnimeHttpSource import eu.kanade.tachiyomi.network.GET +import eu.kanade.tachiyomi.network.POST import eu.kanade.tachiyomi.util.asJsoup +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.async +import kotlinx.coroutines.awaitAll +import kotlinx.coroutines.runBlocking +import okhttp3.FormBody import okhttp3.Request import okhttp3.Response +import org.json.JSONObject import org.jsoup.nodes.Document import org.jsoup.nodes.Element import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get -import java.lang.Exception -import java.lang.RuntimeException -import java.lang.StringBuilder import java.text.SimpleDateFormat import java.util.Locale -class Oploverz : ConfigurableAnimeSource, ParsedAnimeHttpSource() { - override val baseUrl: String = "https://oploverz.fit" - override val lang: String = "id" +class Oploverz : ConfigurableAnimeSource, AnimeHttpSource() { override val name: String = "Oploverz" + override val baseUrl: String = "https://oploverz.red" + override val lang: String = "id" override val supportsLatest: Boolean = true private val preferences: SharedPreferences by lazy { Injekt.get().getSharedPreferences("source_$id", 0x0000) } - override fun animeDetailsParse(document: Document): SAnime { - val anime = SAnime.create() - val infox = document.select("div.bigcontent > div.infox") - val status = parseStatus(infox.select("div > div.info-content > div.spe > span:nth-child(1)").text().replace("Status: ", "")) - anime.title = infox.select("h1").text().replace("Judul: ", "") - anime.genre = infox.select("div > div.info-content > div.genxed > a").joinToString(", ") { it.text() } - anime.status = status - anime.artist = infox.select("div > div.info-content > div.spe > span:nth-child(2)").text() - - // Others - // Jap title - anime.author = when { - infox.select("div > span.alter").isNullOrEmpty() -> "Alternative = -" - else -> "Alternative = " + infox.select("div > span.alter").text() - } - // Score - anime.description = "\n" + document.select("div.bigcontent > div.thumbook > div.rt > div.rating > strong").text() - // Total Episode - anime.description = anime.description + "\n" + document.select("div > div.info-content > div.spe > span:nth-child(7)").text() - // Synopsis - anime.description = anime.description + "\n\n\nSynopsis: \n" + document.select("div.bixbox.synp > div.entry-content > p").joinToString("\n\n") { it.text() } - return anime - } + // ============================== Popular =============================== - private fun parseStatus(statusString: String): Int { - return when (statusString.toLowerCase(Locale.US)) { - "ongoing" -> SAnime.ONGOING - "completed" -> SAnime.COMPLETED - else -> SAnime.UNKNOWN - } - } + override fun popularAnimeRequest(page: Int): Request = + GET("$baseUrl/anime-list/page/$page/?order=popular") - override fun episodeFromElement(element: Element): SEpisode { - val episode = SEpisode.create() - val epsNum = getNumberFromEpsString(element.select(".epl-num").text()) - episode.setUrlWithoutDomain(element.select("a").attr("href")) - episode.episode_number = when { - epsNum.isNotEmpty() -> epsNum.toFloatOrNull() ?: 1F - else -> 1F + override fun popularAnimeParse(response: Response): AnimesPage { + val doc = response.asJsoup() + val animes = doc.select("div.relat > article").map { + getAnimeFromAnimeElement(it) } - episode.name = element.select(".epl-title").text() - episode.date_upload = reconstructDate(element.select(".epl-date").text()) - - return episode + return AnimesPage(animes, hasNextPage(doc)) } - private fun getNumberFromEpsString(epsStr: String): String { - return epsStr.filter { it.isDigit() } - } - private fun reconstructDate(Str: String): Long { - val pattern = SimpleDateFormat("MMMM d yyyy", Locale.US) - return pattern.parse(Str.replace(",", " "))!!.time - } - override fun episodeListSelector(): String = "div.bixbox.bxcl.epcheck > div.eplister > ul > li" + // =============================== Latest =============================== - override fun latestUpdatesFromElement(element: Element): SAnime = getAnimeFromAnimeElement(element) + override fun latestUpdatesRequest(page: Int): Request = + GET("$baseUrl/anime-list/page/$page/?order=latest") - private fun getAnimeFromAnimeElement(element: Element): SAnime { - val anime = SAnime.create() - anime.setUrlWithoutDomain(element.selectFirst("div > a")!!.attr("href")) - anime.thumbnail_url = element.selectFirst("div > a > div.limit > img")!!.attr("src") - anime.title = element.select("div > a > div.tt > h2").text() - return anime + override fun latestUpdatesParse(response: Response): AnimesPage { + val doc = response.asJsoup() + val animes = doc.select("div.relat > article").map { + getAnimeFromAnimeElement(it) + } + return AnimesPage(animes, hasNextPage(doc)) } - override fun latestUpdatesNextPageSelector(): String = "div.hpage > a.r" - override fun latestUpdatesRequest(page: Int): Request = GET("$baseUrl/anime/?page=$page&status=ongoing&sub=&order=update") + // =============================== Search =============================== - override fun latestUpdatesSelector(): String = "div.listupd > article" + override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request = + GET("$baseUrl/page/$page/?s=$query") - override fun popularAnimeFromElement(element: Element): SAnime = getAnimeFromAnimeElement(element) + override fun searchAnimeParse(response: Response): AnimesPage { + val doc = response.asJsoup() + val animes = doc.select("main.site-main.relat > article").map { + getAnimeFromAnimeElement(it) + } + return AnimesPage(animes, hasNextPage(doc)) + } - override fun popularAnimeNextPageSelector(): String = "div.hpage > a.r" + // =========================== Anime Details ============================ + + override fun animeDetailsParse(response: Response): SAnime { + val doc = response.asJsoup() + val detail = doc.selectFirst("div.infox > div.spe")!! + return SAnime.create().apply { + author = detail.getInfo("Studio") + status = parseStatus(doc.selectFirst("div.alternati > span:nth-child(2)")!!.text()) + title = doc.selectFirst("div.title > h1.entry-title")!!.text() + thumbnail_url = + doc.selectFirst("div.infoanime.widget_senction > div.thumb > img")!! + .attr("src") + description = + doc.select("div.entry-content.entry-content-single > p") + .joinToString("\n\n") { it.text() } + } + } - override fun popularAnimeRequest(page: Int): Request = GET("$baseUrl/anime/?page=$page") + // ============================== Episodes ============================== + + override fun episodeListParse(response: Response): List { + val doc = response.asJsoup() + return doc.select("div.lstepsiode.listeps > ul.scrolling > li").map { + val episode = it.selectFirst("span.eps > a")!! + SEpisode.create().apply { + setUrlWithoutDomain(episode.attr("href")) + episode_number = episode.text().trim().toFloatOrNull() ?: 1F + name = it.selectFirst("span.lchx > a")!!.text() + date_upload = it.selectFirst("span.date")!!.text().toDate() + } + } + } - override fun popularAnimeSelector(): String = "div.listupd > article" + // ============================ Video Links ============================= - override fun searchAnimeFromElement(element: Element): SAnime = getAnimeFromAnimeElement(element) + override fun videoListParse(response: Response): List