diff --git a/AllAnimeProvider/build.gradle.kts b/AllAnimeProvider/build.gradle.kts index 0963531..cdecd02 100644 --- a/AllAnimeProvider/build.gradle.kts +++ b/AllAnimeProvider/build.gradle.kts @@ -1,5 +1,5 @@ // use an integer for version numbers -version = 4 +version = 5 cloudstream { @@ -22,5 +22,5 @@ cloudstream { "Anime", ) - iconUrl = "https://www.google.com/s2/favicons?domain=allanime.site&sz=%size%" + iconUrl = "https://www.google.com/s2/favicons?domain=allanime.to&sz=%size%" } \ No newline at end of file diff --git a/AllAnimeProvider/src/main/kotlin/com/lagradost/AllAnimeProvider.kt b/AllAnimeProvider/src/main/kotlin/com/lagradost/AllAnimeProvider.kt index cf23e73..c8f5473 100644 --- a/AllAnimeProvider/src/main/kotlin/com/lagradost/AllAnimeProvider.kt +++ b/AllAnimeProvider/src/main/kotlin/com/lagradost/AllAnimeProvider.kt @@ -5,20 +5,22 @@ import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.LoadResponse.Companion.addActors import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer import com.lagradost.cloudstream3.mvvm.safeApiCall -import com.lagradost.cloudstream3.ui.settings.SettingsProviders import com.lagradost.cloudstream3.utils.AppUtils.parseJson +import com.lagradost.cloudstream3.utils.AppUtils.toJson +import com.lagradost.cloudstream3.utils.Coroutines.mainWork 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 import org.mozilla.javascript.Context import org.mozilla.javascript.Scriptable import java.net.URI -import java.net.URLDecoder class AllAnimeProvider : MainAPI() { - override var mainUrl = "https://allanime.site" + override var mainUrl = "https://allanime.to" + private val apiUrl = "https://api.allanime.co" override var name = "AllAnime" override val hasQuickSearch = false override val hasMainPage = true @@ -60,10 +62,10 @@ class AllAnimeProvider : MainAPI() { @JsonProperty("averageScore") val averageScore: Int?, @JsonProperty("description") val description: String?, @JsonProperty("status") val status: String?, - @JsonProperty("banner") val banner : String?, - @JsonProperty("episodeDuration") val episodeDuration : Int?, - @JsonProperty("prevideos") val prevideos : List = emptyList(), - ) + @JsonProperty("banner") val banner: String?, + @JsonProperty("episodeDuration") val episodeDuration: Int?, + @JsonProperty("prevideos") val prevideos: List = emptyList(), + ) private data class AvailableEpisodes( @JsonProperty("sub") val sub: Int, @@ -209,12 +211,13 @@ class AllAnimeProvider : MainAPI() { @JsonProperty("raw") val raw: List ) - override suspend fun load(url: String): LoadResponse? { - val rhino = Context.enter() - rhino.initSafeStandardObjects() - rhino.optimizationLevel = -1 - val scope: Scriptable = rhino.initSafeStandardObjects() + val (rhino, scope) = mainWork { + val rhino = Context.enter() + rhino.optimizationLevel = -1 + val scope: Scriptable = rhino.initSafeStandardObjects() + rhino to scope + } val html = app.get(url).text val soup = Jsoup.parse(html) @@ -229,8 +232,10 @@ class AllAnimeProvider : MainAPI() { const returnValue = JSON.stringify(window.__NUXT__.fetch[0].show) """.trimIndent() - rhino.evaluateString(scope, js, "JavaScript", 1, null) - val jsEval = scope.get("returnValue", scope) ?: return null + val jsEval = mainWork { + rhino.evaluateString(scope, js, "JavaScript", 1, null) + scope.get("returnValue", scope) ?: return@mainWork null + } ?: return null val showData = parseJson(jsEval as String) @@ -240,13 +245,15 @@ class AllAnimeProvider : MainAPI() { val episodes = showData.availableEpisodes.let { if (it == null) return@let Pair(null, null) + if (showData.Id == null) return@let Pair(null, null) + Pair(if (it.sub != 0) ((1..it.sub).map { epNum -> Episode( - "$mainUrl/anime/${showData.Id}/episodes/sub/$epNum", episode = epNum + AllAnimeLoadData(showData.Id, "sub", epNum).toJson(), episode = epNum ) }) else null, if (it.dub != 0) ((1..it.dub).map { epNum -> Episode( - "$mainUrl/anime/${showData.Id}/episodes/dub/$epNum", episode = epNum + AllAnimeLoadData(showData.Id, "dub", epNum).toJson(), episode = epNum ) }) else null) } @@ -279,7 +286,8 @@ class AllAnimeProvider : MainAPI() { tags = showData.genres year = showData.airedStart?.year duration = showData.episodeDuration?.div(60_000) - addTrailer(showData.prevideos.filter { it.isNotBlank() }.map { "https://www.youtube.com/watch?v=$it" }) + addTrailer(showData.prevideos.filter { it.isNotBlank() } + .map { "https://www.youtube.com/watch?v=$it" }) addEpisodes(DubStatus.Subbed, episodes.first) addEpisodes(DubStatus.Dubbed, episodes.second) @@ -299,6 +307,7 @@ class AllAnimeProvider : MainAPI() { "https://videobin.co/", "https://ok.ru", "https://streamlare.com", + "https://gembedhd.com", ) private fun embedIsBlacklisted(url: String): Boolean { @@ -352,74 +361,77 @@ class AllAnimeProvider : MainAPI() { ) } + data class AllAnimeLoadData( + val hash: String, + val dubStatus: String, + val episode: Int + ) + override suspend fun loadLinks( data: String, isCasting: Boolean, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit ): Boolean { + val loadData = parseJson(data) var apiEndPoint = parseJson(app.get("$mainUrl/getVersion").text).episodeIframeHead if (apiEndPoint.endsWith("/")) apiEndPoint = apiEndPoint.slice(0 until apiEndPoint.length - 1) - val html = app.get(data).text + val apiUrl = + """$apiUrl/allanimeapi?variables={"showId":"${loadData.hash}","translationType":"${loadData.dubStatus}","episodeString":"${loadData.episode}"}&extensions={"persistedQuery":{"version":1,"sha256Hash":"1f0a5d6c9ce6cd3127ee4efd304349345b0737fbf5ec33a60bbc3d18e3bb7c61"}}""" + val apiResponse = app.get(apiUrl).parsed() - val sources = Regex("""sourceUrl[:=]"(.+?)"""").findAll(html).toList() - .map { URLDecoder.decode(it.destructured.component1().sanitize(), "UTF-8") } - sources.apmap { + apiResponse.data?.episode?.sourceUrls?.apmap { source -> safeApiCall { - var link = it.replace(" ", "%20") + val link = source.sourceUrl?.replace(" ", "%20") ?: return@safeApiCall if (URI(link).isAbsolute || link.startsWith("//")) { - if (link.startsWith("//")) link = "https:$it" + val fixedLink = if (link.startsWith("//")) "https:$link" else link + val sourceName = source.sourceName ?: URI(link).host - if (Regex("""streaming\.php\?""").matches(link)) { - // for now ignore - } else if (!embedIsBlacklisted(link)) { - if (URI(link).path.contains(".m3u")) { - getM3u8Qualities(link, data, URI(link).host).forEach(callback) + if (embedIsBlacklisted(fixedLink)) { + loadExtractor(fixedLink, subtitleCallback, callback) + } else if (URI(fixedLink).path.contains(".m3u")) { + getM3u8Qualities(fixedLink, mainUrl, sourceName).forEach(callback) + } else { + callback( + ExtractorLink( + name, + sourceName, + fixedLink, + mainUrl, + Qualities.P1080.value, + false + ) + ) + } + } else { + val fixedLink = apiEndPoint + URI(link).path + ".json?" + URI(link).query + val links = app.get(fixedLink).parsedSafe()?.links + ?: emptyList() + links.forEach { server -> + if (server.hls != null && server.hls) { + getM3u8Qualities( + server.link, + "$apiEndPoint/player?uri=" + (if (URI(server.link).host.isNotEmpty()) server.link else apiEndPoint + URI( + server.link + ).path), + server.resolutionStr + ).forEach(callback) } else { callback( ExtractorLink( - "AllAnime - " + URI(link).host, - "", - link, - data, - Qualities.P1080.value, - false - ) - ) - } - } - } else { - link = apiEndPoint + URI(link).path + ".json?" + URI(link).query - val response = app.get(link) - - if (response.code < 400) { - val links = parseJson(response.text).links - links.forEach { server -> - if (server.hls != null && server.hls) { - getM3u8Qualities( + "AllAnime - " + URI(server.link).host, + server.resolutionStr, server.link, "$apiEndPoint/player?uri=" + (if (URI(server.link).host.isNotEmpty()) server.link else apiEndPoint + URI( server.link ).path), - server.resolutionStr - ).forEach(callback) - } else { - callback( - ExtractorLink( - "AllAnime - " + URI(server.link).host, - server.resolutionStr, - server.link, - "$apiEndPoint/player?uri=" + (if (URI(server.link).host.isNotEmpty()) server.link else apiEndPoint + URI( - server.link - ).path), - Qualities.P1080.value, - false - ) + Qualities.P1080.value, + false ) - } + ) } } } diff --git a/AllAnimeProvider/src/main/kotlin/com/lagradost/LinksQuery.kt b/AllAnimeProvider/src/main/kotlin/com/lagradost/LinksQuery.kt new file mode 100644 index 0000000..eef5c05 --- /dev/null +++ b/AllAnimeProvider/src/main/kotlin/com/lagradost/LinksQuery.kt @@ -0,0 +1,51 @@ +package com.lagradost + +import com.fasterxml.jackson.annotation.JsonProperty + +data class LinksQuery( + @JsonProperty("data") val data: LinkData? = LinkData() +) + +data class LinkData( + @JsonProperty("episode") val episode: Episode? = Episode() +) + +data class SourceUrls( + @JsonProperty("sourceUrl") val sourceUrl: String? = null, + @JsonProperty("priority") val priority: Int? = null, + @JsonProperty("sourceName") val sourceName: String? = null, + @JsonProperty("type") val type: String? = null, + @JsonProperty("className") val className: String? = null, + @JsonProperty("streamerId") val streamerId: String? = null +) + +data class Episode( + @JsonProperty("episodeString") val episodeString: String? = null, +// @JsonProperty("uploadDate" ) val uploadDate : UploadDate? = UploadDate(), + @JsonProperty("sourceUrls") val sourceUrls: ArrayList = arrayListOf(), + @JsonProperty("thumbnail") val thumbnail: String? = null, + @JsonProperty("notes") val notes: String? = null, +// @JsonProperty("show" ) val show : Show? = Show(), + @JsonProperty("pageStatus") val pageStatus: PageStatus? = PageStatus(), + @JsonProperty("episodeInfo") val episodeInfo: EpisodeInfo? = EpisodeInfo(), + @JsonProperty("versionFix") val versionFix: String? = null, + @JsonProperty("__typename") val _typename: String? = null +) + +data class EpisodeInfo( + @JsonProperty("notes") val notes: String? = null, + @JsonProperty("thumbnails") val thumbnails: ArrayList = arrayListOf(), + @JsonProperty("vidInforssub") val vidInforssub: VidInforssub? = VidInforssub(), +// @JsonProperty("uploadDates" ) val uploadDates : UploadDates? = UploadDates(), + @JsonProperty("vidInforsdub") val vidInforsdub: String? = null, + @JsonProperty("vidInforsraw") val vidInforsraw: String? = null, + @JsonProperty("description") val description: String? = null, + @JsonProperty("__typename") val _typename: String? = null +) + +data class VidInforssub( + @JsonProperty("vidResolution") val vidResolution: Int? = null, + @JsonProperty("vidPath") val vidPath: String? = null, + @JsonProperty("vidSize") val vidSize: Int? = null, + @JsonProperty("vidDuration") val vidDuration: Double? = null +) \ No newline at end of file