From 1e272a089399caeac20b6ac5ef5d0bf961cb1a01 Mon Sep 17 00:00:00 2001 From: ghost Date: Thu, 13 Jul 2023 13:27:01 +0700 Subject: [PATCH 01/17] 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 From 69852f9e5b8e8b0a8cabecadbe847433233dad6c Mon Sep 17 00:00:00 2001 From: Suraj <29368267+geekboysuraj@users.noreply.github.com> Date: Thu, 13 Jul 2023 11:57:38 +0530 Subject: [PATCH 02/17] Updated movierulzhd URL (#176) * updated Movierulez URL * Updated movierulzHd URL * Update Movierulzhd URL --- Movierulzhd/build.gradle.kts | 2 +- Movierulzhd/src/main/kotlin/com/hexated/Movierulzhd.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Movierulzhd/build.gradle.kts b/Movierulzhd/build.gradle.kts index e25e9c0e..1d596ef2 100644 --- a/Movierulzhd/build.gradle.kts +++ b/Movierulzhd/build.gradle.kts @@ -1,5 +1,5 @@ // use an integer for version numbers -version = 36 +version = 37 cloudstream { diff --git a/Movierulzhd/src/main/kotlin/com/hexated/Movierulzhd.kt b/Movierulzhd/src/main/kotlin/com/hexated/Movierulzhd.kt index 26bc47d1..263375b7 100644 --- a/Movierulzhd/src/main/kotlin/com/hexated/Movierulzhd.kt +++ b/Movierulzhd/src/main/kotlin/com/hexated/Movierulzhd.kt @@ -12,7 +12,7 @@ import org.jsoup.nodes.Element import java.net.URI class Movierulzhd : MainAPI() { - override var mainUrl = "https://movierulzhd.trade" + override var mainUrl = "https://movierulzhd.help" private var directUrl = mainUrl override var name = "Movierulzhd" override val hasMainPage = true From a4714873944996744da6d691bf88a5d89d570e84 Mon Sep 17 00:00:00 2001 From: tuan041 <30403510+tuan041@users.noreply.github.com> Date: Thu, 13 Jul 2023 13:27:48 +0700 Subject: [PATCH 03/17] Fix Tocanime (#178) * bump * fix --- TocanimeProvider/build.gradle.kts | 6 +- .../kotlin/com/hexated/TocanimeProvider.kt | 60 ++++++------------- 2 files changed, 21 insertions(+), 45 deletions(-) diff --git a/TocanimeProvider/build.gradle.kts b/TocanimeProvider/build.gradle.kts index d7be42c7..dd3551a8 100644 --- a/TocanimeProvider/build.gradle.kts +++ b/TocanimeProvider/build.gradle.kts @@ -1,5 +1,5 @@ // use an integer for version numbers -version = 1 +version = 2 cloudstream { @@ -7,7 +7,7 @@ cloudstream { // All of these properties are optional, you can safely remove them // description = "Lorem Ipsum" - authors = listOf("Hexated") + authors = listOf("Hexated, TuaSan") /** * Status int as the following: @@ -24,4 +24,4 @@ cloudstream { ) iconUrl = "https://www.google.com/s2/favicons?domain=tocanime.co&sz=%size%" -} \ No newline at end of file +} diff --git a/TocanimeProvider/src/main/kotlin/com/hexated/TocanimeProvider.kt b/TocanimeProvider/src/main/kotlin/com/hexated/TocanimeProvider.kt index 90a0f590..96728eda 100644 --- a/TocanimeProvider/src/main/kotlin/com/hexated/TocanimeProvider.kt +++ b/TocanimeProvider/src/main/kotlin/com/hexated/TocanimeProvider.kt @@ -29,14 +29,6 @@ class TocanimeProvider : MainAPI() { else -> TvType.Anime } } - - fun getStatus(t: String): ShowStatus { - return when (t) { - "Đã hoàn thành" -> ShowStatus.Completed - "Chưa hoàn thành" -> ShowStatus.Ongoing - else -> ShowStatus.Completed - } - } } override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse { @@ -51,7 +43,6 @@ class TocanimeProvider : MainAPI() { } if (items.isNotEmpty()) homePageList.add(HomePageList(header, items)) } - return HomePageResponse(homePageList) } @@ -71,43 +62,38 @@ class TocanimeProvider : MainAPI() { this.posterUrl = posterUrl addSub(epNum) } - } override suspend fun search(query: String): List { val document = app.get("$mainUrl/content/search?t=kw&q=$query").document - return document.select("div.col-lg-3.col-md-4.col-6").map { it.toSearchResult() } - } override suspend fun load(url: String): LoadResponse? { val document = app.get(url).document val title = document.selectFirst("h1.title")?.text() ?: return null - val type = - if (document.select("div.me-list.scroller a").size == 1) TvType.AnimeMovie else TvType.Anime - val episodes = document.select("div.me-list.scroller a").mapNotNull { - Episode(fixUrl(it.attr("href")), it.text()) - }.reversed() + val poster = fixUrlNull(document.selectFirst("img.mb20")?.attr("data-original")) val trailer = document.selectFirst("div#trailer script")?.data()?.substringAfter("