From c1d59c7f8e727e40df7c61bc214051922e8079da Mon Sep 17 00:00:00 2001 From: hexated Date: Mon, 24 Jul 2023 21:25:57 +0700 Subject: [PATCH] sora: fixed ask4movies --- Nimegami/build.gradle.kts | 27 +++ Nimegami/src/main/AndroidManifest.xml | 2 + .../src/main/kotlin/com/hexated/Extractors.kt | 60 ++++++ .../src/main/kotlin/com/hexated/Nimegami.kt | 197 ++++++++++++++++++ .../main/kotlin/com/hexated/NimegamiPlugin.kt | 15 ++ NontonAnimeIDProvider/build.gradle.kts | 2 +- .../com/hexated/NontonAnimeIDProvider.kt | 2 +- .../main/kotlin/com/hexated/SoraExtractor.kt | 10 +- .../src/main/kotlin/com/hexated/SoraParser.kt | 8 +- .../src/main/kotlin/com/hexated/SoraStream.kt | 2 +- .../src/main/kotlin/com/hexated/SoraUtils.kt | 2 +- .../src/main/kotlin/com/hexated/Extractors.kt | 37 ---- .../com/hexated/YomoviesProviderPlugin.kt | 1 - 13 files changed, 316 insertions(+), 49 deletions(-) create mode 100644 Nimegami/build.gradle.kts create mode 100644 Nimegami/src/main/AndroidManifest.xml create mode 100644 Nimegami/src/main/kotlin/com/hexated/Extractors.kt create mode 100644 Nimegami/src/main/kotlin/com/hexated/Nimegami.kt create mode 100644 Nimegami/src/main/kotlin/com/hexated/NimegamiPlugin.kt delete mode 100644 YomoviesProvider/src/main/kotlin/com/hexated/Extractors.kt diff --git a/Nimegami/build.gradle.kts b/Nimegami/build.gradle.kts new file mode 100644 index 00000000..82d96dc1 --- /dev/null +++ b/Nimegami/build.gradle.kts @@ -0,0 +1,27 @@ +// use an integer for version numbers +version = 1 + + +cloudstream { + language = "id" + // All of these properties are optional, you can safely remove them + + // description = "Lorem Ipsum" + authors = listOf("Hexated") + + /** + * Status int as the following: + * 0: Down + * 1: Ok + * 2: Slow + * 3: Beta only + * */ + status = 1 // will be 3 if unspecified + tvTypes = listOf( + "AnimeMovie", + "Anime", + "OVA", + ) + + iconUrl = "https://www.google.com/s2/favicons?domain=nimegami.id&sz=%size%" +} \ No newline at end of file diff --git a/Nimegami/src/main/AndroidManifest.xml b/Nimegami/src/main/AndroidManifest.xml new file mode 100644 index 00000000..c98063f8 --- /dev/null +++ b/Nimegami/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Nimegami/src/main/kotlin/com/hexated/Extractors.kt b/Nimegami/src/main/kotlin/com/hexated/Extractors.kt new file mode 100644 index 00000000..aed3ac15 --- /dev/null +++ b/Nimegami/src/main/kotlin/com/hexated/Extractors.kt @@ -0,0 +1,60 @@ +package com.hexated + +import com.fasterxml.jackson.annotation.JsonProperty +import com.lagradost.cloudstream3.SubtitleFile +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.utils.ExtractorApi +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.Qualities + +open class Mitedrive : ExtractorApi() { + override val name = "Mitedrive" + override val mainUrl = "https://mitedrive.com" + override val requiresReferer = false + + override suspend fun getUrl( + url: String, + referer: String?, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit + ) { + val id = url.substringAfterLast("/") + val video = app.post( + "$mainUrl/api/generate", + referer = "$mainUrl/", + data = mapOf( + "short_url" to id + ) + ).parsedSafe()?.data?.url + + val headers = mapOf( + "Accept" to "*/*", + "Connection" to "keep-alive", + "Sec-Fetch-Dest" to "empty", + "Sec-Fetch-Mode" to "cors", + "Sec-Fetch-Site" to "cross-site", + "Origin" to mainUrl, + ) + + callback.invoke( + ExtractorLink( + this.name, + this.name, + video ?: return, + "$mainUrl/", + Qualities.Unknown.value, + headers = headers + ) + ) + + } + + data class Data( + @JsonProperty("url") val url: String? = null, + ) + + data class Responses( + @JsonProperty("data") val data: Data? = null, + ) + +} \ No newline at end of file diff --git a/Nimegami/src/main/kotlin/com/hexated/Nimegami.kt b/Nimegami/src/main/kotlin/com/hexated/Nimegami.kt new file mode 100644 index 00000000..69541e2e --- /dev/null +++ b/Nimegami/src/main/kotlin/com/hexated/Nimegami.kt @@ -0,0 +1,197 @@ +package com.hexated + +import com.fasterxml.jackson.annotation.JsonProperty +import com.lagradost.cloudstream3.* +import com.lagradost.cloudstream3.utils.* +import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson +import org.jsoup.nodes.Element +import org.jsoup.select.Elements +import java.net.URI + +class Nimegami : MainAPI() { + override var mainUrl = "https://nimegami.id" + override var name = "Nimegami" + override val hasMainPage = true + override var lang = "id" + override val supportedTypes = setOf( + TvType.Anime, + TvType.AnimeMovie, + TvType.OVA + ) + + companion object { + fun getType(t: String): TvType { + return if (t.contains("OVA", true) || t.contains("Special", true)) TvType.OVA + else if (t.contains("Movie", true)) TvType.AnimeMovie + else TvType.Anime + } + + fun getStatus(t: String?): ShowStatus { + return when { + t?.contains("On-Going", true) == true -> ShowStatus.Ongoing + else -> ShowStatus.Completed + } + } + } + + override val mainPage = mainPageOf( + "" to "Updated Anime", + "/type/tv" to "Anime", + "/type/movie" to "Movie", + "/type/ona" to "ONA", + "/type/live-action" to "Live Action", + ) + + override suspend fun getMainPage( + page: Int, + request: MainPageRequest + ): HomePageResponse { + val document = app.get("$mainUrl${request.data}/page/$page").document + val home = document.select("div.post-article article, div.archive article").mapNotNull { + it.toSearchResult() + } + return newHomePageResponse( + list = HomePageList( + name = request.name, + list = home, + isHorizontalImages = request.name != "Updated Anime" + ), + hasNext = true + ) + } + + private fun Element.toSearchResult(): AnimeSearchResponse? { + val href = fixUrl(this.selectFirst("a")!!.attr("href")) + val title = this.selectFirst("h2 a")?.text() ?: return null + val posterUrl = (this.selectFirst("noscript img") ?: this.selectFirst("img"))?.attr("src") + val episode = this.selectFirst("ul li:contains(Episode), div.eps-archive")?.ownText() + ?.filter { it.isDigit() }?.toIntOrNull() + + return newAnimeSearchResponse(title, href, TvType.Anime) { + this.posterUrl = posterUrl + addSub(episode) + } + + } + + override suspend fun search(query: String): List { + return app.get("$mainUrl/?s=$query&post_type=post").document.select("div.archive article") + .mapNotNull { + it.toSearchResult() + } + } + + override suspend fun load(url: String): LoadResponse { + val document = app.get(url).document + + val table = document.select("div#Info table tbody") + val title = table.getContent("Judul :").text() + val poster = document.selectFirst("div.coverthumbnail img")?.attr("src") + val bgPoster = document.selectFirst("div.thumbnail-a img")?.attr("src") + val tags = table.getContent("Kategori").select("a").map { it.text() } + + val year = table.getContent("Musim / Rilis").text().filter { it.isDigit() }.toIntOrNull() + val status = getStatus(document.selectFirst("h1[itemprop=headline]")?.text()) + val type = table.getContent("Type").text() + val description = document.select("div#Sinopsis p").text().trim() + + + val episodes = document.select("div.list_eps_stream li") + .mapNotNull { + val name = it.text() + val link = it.attr("data") + Episode(link, name) + } + + val recommendations = document.select("div#randomList > a").mapNotNull { + val epHref = it.attr("href") + val epTitle = it.select("h5.sidebar-title-h5.px-2.py-2").text() + val epPoster = it.select(".product__sidebar__view__item.set-bg").attr("data-setbg") + + newAnimeSearchResponse(epTitle, epHref, TvType.Anime) { + this.posterUrl = epPoster + addDubStatus(dubExist = false, subExist = true) + } + } + + return newAnimeLoadResponse(title, url, getType(type)) { + engName = title + posterUrl = poster + backgroundPosterUrl = bgPoster + this.year = year + addEpisodes(DubStatus.Subbed, episodes) + showStatus = status + plot = description + this.tags = tags + this.recommendations = recommendations + } + + } + + override suspend fun loadLinks( + data: String, + isCasting: Boolean, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit + ): Boolean { + + tryParseJson>(base64Decode(data))?.map { sources -> + sources.url?.apmap { url -> + loadFixedExtractor(url.fixIframe(), sources.format, "$mainUrl/", subtitleCallback, callback) + } + } + + return true + } + + private suspend fun loadFixedExtractor( + url: String, + quality: String?, + referer: String? = null, + subtitleCallback: (SubtitleFile) -> Unit, + callback: (ExtractorLink) -> Unit + ) { + loadExtractor(url, referer, subtitleCallback) { link -> + callback.invoke( + ExtractorLink( + link.name, + link.name, + link.url, + link.referer, + getQualityFromName(quality), + link.isM3u8, + link.headers, + link.extractorData + ) + ) + } + } + + private fun getBaseUrl(url: String): String { + return URI(url).let { + "${it.scheme}://${it.host}" + } + } + + private fun Elements.getContent(css: String) : Elements { + return this.select("tr:contains($css) td:last-child") + } + + private fun String.fixIframe() : String { + val url = base64Decode(this.substringAfter("url=").substringAfter("id=")) + val host = getBaseUrl(url) + return when { + url.contains("hxfile") -> { + val id = url.substringAfterLast("/") + "$host/embed-$id.html" + } + else -> fixUrl(url) + } + } + + data class Sources( + @JsonProperty("format") val format: String? = null, + @JsonProperty("url") val url: ArrayList? = arrayListOf(), + ) + +} diff --git a/Nimegami/src/main/kotlin/com/hexated/NimegamiPlugin.kt b/Nimegami/src/main/kotlin/com/hexated/NimegamiPlugin.kt new file mode 100644 index 00000000..8ab01378 --- /dev/null +++ b/Nimegami/src/main/kotlin/com/hexated/NimegamiPlugin.kt @@ -0,0 +1,15 @@ + +package com.hexated + +import com.lagradost.cloudstream3.plugins.CloudstreamPlugin +import com.lagradost.cloudstream3.plugins.Plugin +import android.content.Context + +@CloudstreamPlugin +class NimegamiPlugin: Plugin() { + override fun load(context: Context) { + // All providers should be added in this manner. Please don't edit the providers list directly. + registerMainAPI(Nimegami()) + registerExtractorAPI(Mitedrive()) + } +} \ No newline at end of file diff --git a/NontonAnimeIDProvider/build.gradle.kts b/NontonAnimeIDProvider/build.gradle.kts index 3da1506d..cff263d4 100644 --- a/NontonAnimeIDProvider/build.gradle.kts +++ b/NontonAnimeIDProvider/build.gradle.kts @@ -1,5 +1,5 @@ // use an integer for version numbers -version = 15 +version = 16 cloudstream { diff --git a/NontonAnimeIDProvider/src/main/kotlin/com/hexated/NontonAnimeIDProvider.kt b/NontonAnimeIDProvider/src/main/kotlin/com/hexated/NontonAnimeIDProvider.kt index aa54f212..2912e7a2 100644 --- a/NontonAnimeIDProvider/src/main/kotlin/com/hexated/NontonAnimeIDProvider.kt +++ b/NontonAnimeIDProvider/src/main/kotlin/com/hexated/NontonAnimeIDProvider.kt @@ -11,7 +11,7 @@ import org.jsoup.nodes.Element import java.net.URI class NontonAnimeIDProvider : MainAPI() { - override var mainUrl = "https://nontonanimeid.bio" + override var mainUrl = "https://nontonanimeid.lol" override var name = "NontonAnimeID" override val hasQuickSearch = false override val hasMainPage = true diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt b/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt index 6d75648a..8b3819d5 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt @@ -2695,7 +2695,15 @@ object SoraExtractor : SoraStream() { epsDoc.select("ul.group-links-list li:nth-child($episode) a").attr("data-embed-src") } - loadExtractor(iframe, ask4MoviesAPI, subtitleCallback, callback) + val iframeDoc = app.get(iframe, referer = "$ask4MoviesAPI/").text + val script = Regex("""eval\(function\(p,a,c,k,e,.*\)\)""").findAll(iframeDoc).lastOrNull()?.value + val unpacked = getAndUnpack(script ?: return) + val m3u8 = Regex("file:\\s*\"(.*?m3u8.*?)\"").find(unpacked)?.groupValues?.getOrNull(1) + M3u8Helper.generateM3u8( + "Ask4movie", + m3u8 ?: return, + mainUrl + ).forEach(callback) } diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraParser.kt b/SoraStream/src/main/kotlin/com/hexated/SoraParser.kt index ee85e838..a1e91094 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraParser.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraParser.kt @@ -336,16 +336,12 @@ data class VizcloudSources( @JsonProperty("file") val file: String? = null, ) -data class VizcloudMedia( +data class VizcloudResult( @JsonProperty("sources") val sources: ArrayList? = arrayListOf(), ) -data class VizcloudData( - @JsonProperty("media") val media: VizcloudMedia? = null, -) - data class VizcloudResponses( - @JsonProperty("data") val data: VizcloudData? = null, + @JsonProperty("result") val result: VizcloudResult? = null, ) data class AnilistExternalLinks( diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt b/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt index aab30a60..16d00b6b 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt @@ -119,7 +119,7 @@ open class SoraStream : TmdbProvider() { const val smashyStreamAPI = "https://embed.smashystream.com" const val watchSomuchAPI = "https://watchsomuch.tv" // sub only val gomoviesAPI = base64DecodeAPI("bQ==Y28=ZS4=aW4=bmw=LW8=ZXM=dmk=bW8=Z28=Ly8=czo=dHA=aHQ=") - const val ask4MoviesAPI = "https://ask4movie.net" + const val ask4MoviesAPI = "https://ask4movie.nl" const val biliBiliAPI = "https://api-vn.otakuz.live/server" const val watchOnlineAPI = "https://watchonline.ag" const val nineTvAPI = "https://api.9animetv.live" diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraUtils.kt b/SoraStream/src/main/kotlin/com/hexated/SoraUtils.kt index 8db8f4f4..5f2ae0fd 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraUtils.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraUtils.kt @@ -418,7 +418,7 @@ suspend fun invokeVizcloud( ) { val id = Regex("(?:/embed[-/]|/e/)([^?/]*)").find(url)?.groupValues?.getOrNull(1) app.get("$consumetHelper?query=${id ?: return}&action=vizcloud") - .parsedSafe()?.data?.media?.sources?.map { + .parsedSafe()?.result?.sources?.map { M3u8Helper.generateM3u8( "Vizcloud", it.file ?: return@map, diff --git a/YomoviesProvider/src/main/kotlin/com/hexated/Extractors.kt b/YomoviesProvider/src/main/kotlin/com/hexated/Extractors.kt deleted file mode 100644 index 08597bf1..00000000 --- a/YomoviesProvider/src/main/kotlin/com/hexated/Extractors.kt +++ /dev/null @@ -1,37 +0,0 @@ -package com.hexated - -import com.fasterxml.jackson.annotation.JsonProperty -import com.lagradost.cloudstream3.SubtitleFile -import com.lagradost.cloudstream3.app -import com.lagradost.cloudstream3.extractors.SpeedoStream -import com.lagradost.cloudstream3.utils.AppUtils -import com.lagradost.cloudstream3.utils.ExtractorLink -import com.lagradost.cloudstream3.utils.M3u8Helper -import com.lagradost.cloudstream3.utils.getAndUnpack - -class Streamoupload : SpeedoStream() { - override val mainUrl = "https://streamoupload.xyz" - override val name = "Streamoupload" - - override suspend fun getUrl( - url: String, - referer: String?, - subtitleCallback: (SubtitleFile) -> Unit, - callback: (ExtractorLink) -> Unit - ) { - val script = getAndUnpack(app.get(url, referer = referer).text) - val data = script.substringAfter("sources:[") - .substringBefore("],").replace("file", "\"file\"").trim() - AppUtils.tryParseJson(data)?.let { - M3u8Helper.generateM3u8( - name, - it.file, - "$mainUrl/", - ).forEach(callback) - } - } - - private data class File( - @JsonProperty("file") val file: String, - ) -} \ No newline at end of file diff --git a/YomoviesProvider/src/main/kotlin/com/hexated/YomoviesProviderPlugin.kt b/YomoviesProvider/src/main/kotlin/com/hexated/YomoviesProviderPlugin.kt index 60bb8004..45bf3e5a 100644 --- a/YomoviesProvider/src/main/kotlin/com/hexated/YomoviesProviderPlugin.kt +++ b/YomoviesProvider/src/main/kotlin/com/hexated/YomoviesProviderPlugin.kt @@ -11,6 +11,5 @@ class YomoviesProviderPlugin: Plugin() { // All providers should be added in this manner. Please don't edit the providers list directly. registerMainAPI(YomoviesProvider()) registerMainAPI(Watchomovies()) - registerExtractorAPI(Streamoupload()) } } \ No newline at end of file