From 1e272a089399caeac20b6ac5ef5d0bf961cb1a01 Mon Sep 17 00:00:00 2001 From: ghost Date: Thu, 13 Jul 2023 13:27:01 +0700 Subject: [PATCH] fix some providers: Anichi, Layarkaca, Anroll, Movierulzhd --- Anichi/build.gradle.kts | 2 +- Anichi/src/main/kotlin/com/hexated/Anichi.kt | 120 +++++++++++++++--- Anroll/build.gradle.kts | 2 +- Anroll/src/main/kotlin/com/hexated/Anroll.kt | 8 +- LayarKacaProvider/build.gradle.kts | 2 +- .../kotlin/com/hexated/LayarKacaProvider.kt | 52 ++++---- .../com/hexated/LayarKacaProviderPlugin.kt | 1 + .../src/main/kotlin/com/hexated/Extractors.kt | 5 + .../kotlin/com/hexated/MovierulzhdPlugin.kt | 1 + 9 files changed, 143 insertions(+), 50 deletions(-) diff --git a/Anichi/build.gradle.kts b/Anichi/build.gradle.kts index 24eea240..103eac72 100644 --- a/Anichi/build.gradle.kts +++ b/Anichi/build.gradle.kts @@ -1,7 +1,7 @@ import org.jetbrains.kotlin.konan.properties.Properties // use an integer for version numbers -version = 4 +version = 5 android { defaultConfig { diff --git a/Anichi/src/main/kotlin/com/hexated/Anichi.kt b/Anichi/src/main/kotlin/com/hexated/Anichi.kt index 02d0fe98..301fec66 100644 --- a/Anichi/src/main/kotlin/com/hexated/Anichi.kt +++ b/Anichi/src/main/kotlin/com/hexated/Anichi.kt @@ -2,12 +2,12 @@ package com.hexated import com.fasterxml.jackson.annotation.JsonProperty import com.lagradost.cloudstream3.* -import com.lagradost.cloudstream3.APIHolder.getTracker import com.lagradost.cloudstream3.LoadResponse.Companion.addActors import com.lagradost.cloudstream3.LoadResponse.Companion.addAniListId import com.lagradost.cloudstream3.LoadResponse.Companion.addMalId import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer import com.lagradost.cloudstream3.extractors.helper.GogoHelper +import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.cloudstream3.mvvm.safeApiCall import com.lagradost.cloudstream3.utils.* import com.lagradost.cloudstream3.utils.AppUtils.parseJson @@ -32,14 +32,6 @@ class Anichi : MainAPI() { } } - private fun getType(t: String?): TvType { - return when { - t.equals("OVA", true) || t.equals("Special") -> TvType.OVA - t.equals("Movie", true) -> TvType.AnimeMovie - else -> TvType.Anime - } - } - override val supportedTypes = setOf(TvType.Anime, TvType.AnimeMovie) private val popularTitle = "Popular" @@ -141,7 +133,6 @@ class Anichi : MainAPI() { val title = showData.name val description = showData.description val poster = showData.thumbnail - val type = getType(showData.type ?: "") val episodes = showData.availableEpisodesDetail.let { if (it == null) return@let Pair(null, null) @@ -164,13 +155,12 @@ class Anichi : MainAPI() { Pair(Actor(name, image), role) } - val names = showData.altNames?.plus(title)?.filterNotNull() ?: emptyList() - val trackers = getTracker(names, TrackerType.getTypes(type), showData.airedStart?.year) + val trackers = getTracker(title, showData.altNames?.firstOrNull(), showData.airedStart?.year, showData.season?.quarter, showData.type) return newAnimeLoadResponse(title ?: "", url, TvType.Anime) { engName = showData.altNames?.firstOrNull() - posterUrl = trackers?.image ?: poster - backgroundPosterUrl = trackers?.cover ?: showData.banner + posterUrl = trackers?.coverImage?.extraLarge ?: trackers?.coverImage?.large ?: poster + backgroundPosterUrl = trackers?.bannerImage ?: showData.banner rating = showData.averageScore?.times(100) tags = showData.genres year = showData.airedStart?.year @@ -184,8 +174,8 @@ class Anichi : MainAPI() { //this.recommendations = recommendations showStatus = getStatus(showData.status.toString()) - addMalId(trackers?.malId) - addAniListId(trackers?.aniId?.toIntOrNull()) + addMalId(trackers?.idMal) + addAniListId(trackers?.id) plot = description?.replace(Regex("""<(.*?)>"""), "") } } @@ -273,6 +263,14 @@ class Anichi : MainAPI() { isDash = server.resolutionStr == "Dash 1" ) ) + server.subtitles?.map { sub -> + subtitleCallback.invoke( + SubtitleFile( + SubtitleHelper.fromTwoLettersToLanguage(sub.lang ?: "") ?: sub.lang ?: "", + httpsify(sub.src ?: return@map) + ) + ) + } } } } @@ -315,7 +313,8 @@ class Anichi : MainAPI() { return meta.map { eps -> Episode( AnichiLoadData(id, lang, eps).toJson(), - "Ep $eps" + "Ep $eps", + episode = eps.toIntOrNull() ) }.reversed() } @@ -382,6 +381,69 @@ class Anichi : MainAPI() { } } + private suspend fun getTracker(name: String?, altName: String?, year: Int?, season: String?, type: String?): AniMedia? { + val ids = fetchId(name, year, season, type) + return if (ids?.id == null && ids?.idMal == null) fetchId( + altName, + year, + season, + type + ) else ids + } + + private suspend fun fetchId(title: String?, year: Int?, season: String?, type: String?): AniMedia? { + val query = """ + query ( + ${'$'}page: Int = 1 + ${'$'}search: String + ${'$'}sort: [MediaSort] = [POPULARITY_DESC, SCORE_DESC] + ${'$'}type: MediaType + ${'$'}season: MediaSeason + ${'$'}year: String + ${'$'}format: [MediaFormat] + ) { + Page(page: ${'$'}page, perPage: 20) { + media( + search: ${'$'}search + sort: ${'$'}sort + type: ${'$'}type + season: ${'$'}season + startDate_like: ${'$'}year + format_in: ${'$'}format + ) { + id + idMal + coverImage { extraLarge large } + bannerImage + } + } + } + """.trimIndent().trim() + + val variables = mapOf( + "search" to title, + "sort" to "SEARCH_MATCH", + "type" to "ANIME", + "season" to if(type.equals("ona", true)) "" else season?.uppercase(), + "year" to "$year%", + "format" to listOf(type?.uppercase()) + ).filterValues { value -> value != null && value.toString().isNotEmpty() } + + val data = mapOf( + "query" to query, + "variables" to variables + ).toJson().toRequestBody(RequestBodyTypes.JSON.toMediaTypeOrNull()) + + return try { + app.post("https://graphql.anilist.co", requestBody = data) + .parsedSafe()?.data?.Page?.media?.firstOrNull() + } catch (t: Throwable) { + logError(t) + null + } + + } + companion object { private const val apiUrl = BuildConfig.ANICHI_API private const val serverUrl = BuildConfig.ANICHI_SERVER @@ -406,6 +468,30 @@ class Anichi : MainAPI() { val episode: String ) + data class CoverImage( + @JsonProperty("extraLarge") var extraLarge: String? = null, + @JsonProperty("large") var large: String? = null, + ) + + data class AniMedia( + @JsonProperty("id") var id: Int? = null, + @JsonProperty("idMal") var idMal: Int? = null, + @JsonProperty("coverImage") var coverImage: CoverImage? = null, + @JsonProperty("bannerImage") var bannerImage: String? = null, + ) + + data class AniPage( + @JsonProperty("media") var media: ArrayList = arrayListOf() + ) + + data class AniData( + @JsonProperty("Page") var Page: AniPage? = AniPage() + ) + + data class AniSearch( + @JsonProperty("data") var data: AniData? = AniData() + ) + data class AkIframe( @JsonProperty("idUrl") val idUrl: String? = null, ) diff --git a/Anroll/build.gradle.kts b/Anroll/build.gradle.kts index bbbb0839..7d575610 100644 --- a/Anroll/build.gradle.kts +++ b/Anroll/build.gradle.kts @@ -1,5 +1,5 @@ // use an integer for version numbers -version = 1 +version = 2 cloudstream { language = "pt-pt" diff --git a/Anroll/src/main/kotlin/com/hexated/Anroll.kt b/Anroll/src/main/kotlin/com/hexated/Anroll.kt index 178db598..d397caa0 100644 --- a/Anroll/src/main/kotlin/com/hexated/Anroll.kt +++ b/Anroll/src/main/kotlin/com/hexated/Anroll.kt @@ -35,7 +35,7 @@ class Anroll : MainAPI() { ): HomePageResponse { val document = app.get("$mainUrl/home").document val home = mutableListOf() - document.select("div.sc-f5d5b250-1.iJHcsI").map { div -> + document.select("div.hAbQAe").map { div -> val header = div.selectFirst("h2")?.text() ?: return@map val child = HomePageList( header, @@ -91,11 +91,11 @@ class Anroll : MainAPI() { val fixUrl = getProperAnimeLink(url) ?: throw ErrorLoadingException() val document = app.get(fixUrl).document - val article = document.selectFirst("article.sc-f5d5b250-9") ?: return null + val article = document.selectFirst("article.animedetails") ?: return null val title = article.selectFirst("h2")?.text() ?: return null - val poster = fixUrlNull(document.select("article.sc-f5d5b250-8 img").attr("src")) + val poster = fixUrlNull(document.select("section.animecontent img").attr("src")) val tags = article.select("div#generos a").map { it.text() } - val year = article.selectFirst("div.sc-f5d5b250-4")?.nextElementSibling()?.text() + val year = article.selectFirst("div.dfuefM")?.nextElementSibling()?.text() ?.toIntOrNull() val description = document.select("div.sinopse").text().trim() val type = if (fixUrl.contains("/a/")) TvType.Anime else TvType.AnimeMovie diff --git a/LayarKacaProvider/build.gradle.kts b/LayarKacaProvider/build.gradle.kts index 1f1549b9..b1cd5e23 100644 --- a/LayarKacaProvider/build.gradle.kts +++ b/LayarKacaProvider/build.gradle.kts @@ -1,5 +1,5 @@ // use an integer for version numbers -version = 13 +version = 14 cloudstream { diff --git a/LayarKacaProvider/src/main/kotlin/com/hexated/LayarKacaProvider.kt b/LayarKacaProvider/src/main/kotlin/com/hexated/LayarKacaProvider.kt index 8b7c03a5..535214aa 100644 --- a/LayarKacaProvider/src/main/kotlin/com/hexated/LayarKacaProvider.kt +++ b/LayarKacaProvider/src/main/kotlin/com/hexated/LayarKacaProvider.kt @@ -6,11 +6,10 @@ import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer import com.lagradost.cloudstream3.utils.* import org.jsoup.nodes.Element import java.net.URLDecoder -import java.net.URI class LayarKacaProvider : MainAPI() { - override var mainUrl = "https://d21.fun" - private var seriesUrl = "https://tv.nontondrama.click" + override var mainUrl = "https://tv.lk21official.pro" + private var seriesUrl = "https://tv1.nontondrama.click" override var name = "LayarKaca" override val hasMainPage = true override var lang = "id" @@ -57,7 +56,7 @@ class LayarKacaProvider : MainAPI() { private fun Element.toSearchResult(): SearchResponse? { val title = this.selectFirst("h1.grid-title > a")?.ownText()?.trim() ?: return null val href = fixUrl(this.selectFirst("a")!!.attr("href")) - val posterUrl = fixUrlNull(this.selectFirst(".grid-poster > a > img")?.attr("src")) + val posterUrl = fixUrlNull(this.selectFirst("img")?.attr("src")) val type = if (this.selectFirst("div.last-episode") == null) TvType.Movie else TvType.TvSeries return if (type == TvType.TvSeries) { @@ -176,33 +175,34 @@ class LayarKacaProvider : MainAPI() { it } } - invokeCast(link, callback) + loadExtractor(link, bananalicious, subtitleCallback, callback) } return true } - private suspend fun invokeCast( - url: String, - callback: (ExtractorLink) -> Unit - ) { - val response = app.get(url, referer = bananalicious).document - response.select("script[type=text/javascript]").map { script -> - if (script.data().contains(Regex("eval\\(function\\(p,a,c,k,e,[rd]"))) { - val unpackedscript = getAndUnpack(script.data()) - val m3u8Regex = Regex("file.\"(.*?m3u8.*?)\"") - val m3u8 = m3u8Regex.find(unpackedscript)?.destructured?.component1() ?: "" - if (m3u8.isNotEmpty()) { - M3u8Helper.generateM3u8( - fixTitle(URI(url).host).substringBefore("."), - m3u8, - mainUrl - ).forEach(callback) - } - } - } - } - private fun decode(input: String): String = URLDecoder.decode(input, "utf-8").replace(" ", "%20") } + +open class Emturbovid : ExtractorApi() { + override val name = "Emturbovid" + override val mainUrl = "https://emturbovid.com" + override val requiresReferer = true + + override suspend fun getUrl( + url: String, + referer: String?, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit + ) { + val response = app.get(url, referer = referer) + val m3u8 = Regex("[\"'](.*?master\\.m3u8.*?)[\"']").find(response.text)?.groupValues?.getOrNull(1) + M3u8Helper.generateM3u8( + name, + m3u8 ?: return, + mainUrl + ).forEach(callback) + } + +} diff --git a/LayarKacaProvider/src/main/kotlin/com/hexated/LayarKacaProviderPlugin.kt b/LayarKacaProvider/src/main/kotlin/com/hexated/LayarKacaProviderPlugin.kt index 9743b456..bd3389cb 100644 --- a/LayarKacaProvider/src/main/kotlin/com/hexated/LayarKacaProviderPlugin.kt +++ b/LayarKacaProvider/src/main/kotlin/com/hexated/LayarKacaProviderPlugin.kt @@ -10,5 +10,6 @@ class LayarKacaProviderPlugin: Plugin() { override fun load(context: Context) { // All providers should be added in this manner. Please don't edit the providers list directly. registerMainAPI(LayarKacaProvider()) + registerExtractorAPI(Emturbovid()) } } \ No newline at end of file diff --git a/Movierulzhd/src/main/kotlin/com/hexated/Extractors.kt b/Movierulzhd/src/main/kotlin/com/hexated/Extractors.kt index d30ef49b..87ae7b6d 100644 --- a/Movierulzhd/src/main/kotlin/com/hexated/Extractors.kt +++ b/Movierulzhd/src/main/kotlin/com/hexated/Extractors.kt @@ -11,6 +11,11 @@ import kotlin.random.Random const val twoEmbedAPI = "https://www.2embed.to" +class Sbnmp : Sbflix() { + override val name = "Sbnmp" + override var mainUrl = "https://sbnmp.bar" +} + class Sbrulz : Sbflix() { override val name = "Sbrulz" override var mainUrl = "https://sbrulz.xyz" diff --git a/Movierulzhd/src/main/kotlin/com/hexated/MovierulzhdPlugin.kt b/Movierulzhd/src/main/kotlin/com/hexated/MovierulzhdPlugin.kt index fb2bf567..21710b9d 100644 --- a/Movierulzhd/src/main/kotlin/com/hexated/MovierulzhdPlugin.kt +++ b/Movierulzhd/src/main/kotlin/com/hexated/MovierulzhdPlugin.kt @@ -13,5 +13,6 @@ class MovierulzhdPlugin: Plugin() { registerExtractorAPI(Sbflix()) registerExtractorAPI(Sbrulz()) registerExtractorAPI(Sbmiz()) + registerExtractorAPI(Sbnmp()) } } \ No newline at end of file