package com.lagradost import com.fasterxml.jackson.annotation.JsonProperty import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer import com.lagradost.cloudstream3.mvvm.safeApiCall import com.lagradost.cloudstream3.utils.AppUtils.parseJson import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.M3u8Helper import com.lagradost.cloudstream3.utils.Qualities import com.lagradost.cloudstream3.utils.loadExtractor import org.jsoup.Jsoup class GomunimeProvider : MainAPI() { override var mainUrl = "https://185.231.223.76" override var name = "Gomunime" override val hasMainPage = true override var lang = "id" override val hasDownloadSupport = true override val supportedTypes = setOf( TvType.Anime, TvType.AnimeMovie, TvType.OVA ) companion object { private const val mainServer = "https://path.onicdn.xyz/app/rapi.php" fun getType(t: String): TvType { return if (t.contains("OVA") || t.contains("Special")) TvType.OVA else if (t.contains("Movie")) TvType.AnimeMovie else TvType.Anime } fun getStatus(t: String): ShowStatus { return when (t) { "Completed" -> ShowStatus.Completed "Ongoing" -> ShowStatus.Ongoing else -> ShowStatus.Completed } } } override val mainPage = mainPageOf( "e" to "Episode Baru", "c" to "Completed", "la" to "Live Action", "t" to "Trending" ) override suspend fun getMainPage( page: Int, request: MainPageRequest ): HomePageResponse { val home = Jsoup.parse( (app.post( url = "$mainUrl/wp-admin/admin-ajax.php/wp-admin/admin-ajax.php", headers = mapOf("Referer" to mainUrl), data = mapOf( "action" to "home_ajax", "fungsi" to request.data, "pag" to "$page" ) ).parsedSafe()?.html ?: throw ErrorLoadingException("Invalid Json reponse")) ).select("li").mapNotNull { val title = it.selectFirst("a.name")?.text()?.trim() ?: return@mapNotNull null val href = getProperAnimeLink(it.selectFirst("a")!!.attr("href")) val posterUrl = it.selectFirst("img")?.attr("src") val type = getType(it.selectFirst(".taglist > span")!!.text().trim()) val epNum = it.select(".tag.ep").text().replace(Regex("[^0-9]"), "").trim() .toIntOrNull() newAnimeSearchResponse(title, href, type) { this.posterUrl = posterUrl addSub(epNum) } } return newHomePageResponse(request.name, home) } private fun getProperAnimeLink(uri: String): String { return if (uri.contains("-episode")) { val href = "$mainUrl/anime/" + Regex("\\w\\d/(.*)-episode.*").find(uri)?.groupValues?.get(1) .toString() when { href.contains("pokemon") -> href.replace(Regex("-[0-9]+"), "") else -> href } } else { uri } } override suspend fun search(query: String): List { val link = "$mainUrl/?s=$query" val document = app.get(link).document return document.select(".anime-list > li").map { val title = it.selectFirst("a.name")!!.text() val poster = it.selectFirst("img")!!.attr("src") val tvType = getType(it.selectFirst(".taglist > span")?.text().toString()) val href = fixUrl(it.selectFirst("a.name")!!.attr("href")) newAnimeSearchResponse(title, href, tvType) { this.posterUrl = poster addDubStatus(dubExist = false, subExist = true) } } } override suspend fun load(url: String): LoadResponse { val document = app.get(url).document val title = document.selectFirst(".entry-title")?.text().toString() val poster = document.selectFirst(".thumbposter > img")?.attr("data-lazy-src") val tags = document.select(".genxed > a").map { it.text() } val year = Regex("\\d, ([0-9]*)").find( document.select("time[itemprop = datePublished]").text() )?.groupValues?.get(1)?.toIntOrNull() val status = getStatus(document.selectFirst(".spe > span")!!.ownText()) val description = document.select("div[itemprop = description] > p").text() val trailer = document.selectFirst("div.embed-responsive noscript iframe")?.attr("src") val episodes = parseJson>( Regex("var episodelist = (\\[.*])").find( document.select(".bixbox.bxcl.epcheck > script").toString().trim() )?.groupValues?.get(1).toString().replace(Regex("""\\"""), "").trim() ).map { val name = Regex("(Episode\\s?[0-9]+)").find(it.epTitle.toString())?.groupValues?.getOrNull(0) ?: it.epTitle val link = it.epLink Episode(link, name) }.reversed() return newAnimeLoadResponse(title, url, TvType.Anime) { engName = title posterUrl = poster this.year = year addEpisodes(DubStatus.Subbed, episodes) showStatus = status plot = description this.tags = tags addTrailer(trailer) } } override suspend fun loadLinks( data: String, isCasting: Boolean, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit ): Boolean { val document = app.get(data).document val scriptData = document.select("aside.sidebar > script").dataNodes().toString() val key = scriptData.substringAfter("var a_ray = '").substringBefore("';") val title = scriptData.substringAfter("var judul_postingan = \"").substringBefore("\";") .replace(" ", "+") val image = document.select("img#tempvid").last()?.attr("src").toString() val sources: List> = app.post( url = mainServer, data = mapOf("data" to key, "gambar" to image, "judul" to title, "func" to "mirror"), referer = "$mainUrl/" ).document.select("div.gomunime-server-mirror").map { Pair( it.attr("data-vhash"), it.attr("data-type") ) } sources.apmap { safeApiCall { when { it.second.contains("frame") -> { loadExtractor(it.first, mainUrl, subtitleCallback, callback) } // Skip for now // it.second.contains("hls") -> { // app.post( // url = mainServer, // data = mapOf("fid" to it.first, "func" to "hls") // ).text.let { link -> // M3u8Helper.generateM3u8( // this.name, // link, // "$mainUrl/", // headers = mapOf("Origin" to mainUrl) // ).forEach(callback) // } // } it.second.contains("mp4") -> { app.post( url = mainServer, data = mapOf("data" to it.first, "func" to "blogs") ).parsed>().map { callback.invoke( ExtractorLink( source = name, name = "Mobi SD", url = it.file, referer = "$mainUrl/", quality = Qualities.P360.value ) ) } } else -> null } } } return true } private data class Response( @JsonProperty("status") val status: Boolean, @JsonProperty("html") val html: String ) data class MobiSource( @JsonProperty("file") val file: String, @JsonProperty("label") val label: String, @JsonProperty("type") val type: String ) private data class EpisodeElement( @JsonProperty("data-index") val dataIndex: Long?, @JsonProperty("ep-num") val epNum: String?, @JsonProperty("ep-title") val epTitle: String?, @JsonProperty("ep-link") val epLink: String, @JsonProperty("ep-date") val epDate: String? ) }