AllAnime fix

This commit is contained in:
no-commit 2023-02-18 02:13:46 +01:00
parent d078283b01
commit da1dd7c2b8
3 changed files with 127 additions and 64 deletions

View File

@ -1,5 +1,5 @@
// use an integer for version numbers // use an integer for version numbers
version = 4 version = 5
cloudstream { cloudstream {
@ -22,5 +22,5 @@ cloudstream {
"Anime", "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%"
} }

View File

@ -5,20 +5,22 @@ import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.LoadResponse.Companion.addActors import com.lagradost.cloudstream3.LoadResponse.Companion.addActors
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
import com.lagradost.cloudstream3.mvvm.safeApiCall 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.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.ExtractorLink
import com.lagradost.cloudstream3.utils.M3u8Helper import com.lagradost.cloudstream3.utils.M3u8Helper
import com.lagradost.cloudstream3.utils.Qualities import com.lagradost.cloudstream3.utils.Qualities
import com.lagradost.cloudstream3.utils.loadExtractor
import org.jsoup.Jsoup import org.jsoup.Jsoup
import org.mozilla.javascript.Context import org.mozilla.javascript.Context
import org.mozilla.javascript.Scriptable import org.mozilla.javascript.Scriptable
import java.net.URI import java.net.URI
import java.net.URLDecoder
class AllAnimeProvider : MainAPI() { 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 var name = "AllAnime"
override val hasQuickSearch = false override val hasQuickSearch = false
override val hasMainPage = true override val hasMainPage = true
@ -60,10 +62,10 @@ class AllAnimeProvider : MainAPI() {
@JsonProperty("averageScore") val averageScore: Int?, @JsonProperty("averageScore") val averageScore: Int?,
@JsonProperty("description") val description: String?, @JsonProperty("description") val description: String?,
@JsonProperty("status") val status: String?, @JsonProperty("status") val status: String?,
@JsonProperty("banner") val banner : String?, @JsonProperty("banner") val banner: String?,
@JsonProperty("episodeDuration") val episodeDuration : Int?, @JsonProperty("episodeDuration") val episodeDuration: Int?,
@JsonProperty("prevideos") val prevideos : List<String> = emptyList(), @JsonProperty("prevideos") val prevideos: List<String> = emptyList(),
) )
private data class AvailableEpisodes( private data class AvailableEpisodes(
@JsonProperty("sub") val sub: Int, @JsonProperty("sub") val sub: Int,
@ -209,12 +211,13 @@ class AllAnimeProvider : MainAPI() {
@JsonProperty("raw") val raw: List<String> @JsonProperty("raw") val raw: List<String>
) )
override suspend fun load(url: String): LoadResponse? { override suspend fun load(url: String): LoadResponse? {
val rhino = Context.enter() val (rhino, scope) = mainWork {
rhino.initSafeStandardObjects() val rhino = Context.enter()
rhino.optimizationLevel = -1 rhino.optimizationLevel = -1
val scope: Scriptable = rhino.initSafeStandardObjects() val scope: Scriptable = rhino.initSafeStandardObjects()
rhino to scope
}
val html = app.get(url).text val html = app.get(url).text
val soup = Jsoup.parse(html) val soup = Jsoup.parse(html)
@ -229,8 +232,10 @@ class AllAnimeProvider : MainAPI() {
const returnValue = JSON.stringify(window.__NUXT__.fetch[0].show) const returnValue = JSON.stringify(window.__NUXT__.fetch[0].show)
""".trimIndent() """.trimIndent()
rhino.evaluateString(scope, js, "JavaScript", 1, null) val jsEval = mainWork {
val jsEval = scope.get("returnValue", scope) ?: return null rhino.evaluateString(scope, js, "JavaScript", 1, null)
scope.get("returnValue", scope) ?: return@mainWork null
} ?: return null
val showData = parseJson<Edges>(jsEval as String) val showData = parseJson<Edges>(jsEval as String)
@ -240,13 +245,15 @@ class AllAnimeProvider : MainAPI() {
val episodes = showData.availableEpisodes.let { val episodes = showData.availableEpisodes.let {
if (it == null) return@let Pair(null, null) 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 -> Pair(if (it.sub != 0) ((1..it.sub).map { epNum ->
Episode( 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 -> }) else null, if (it.dub != 0) ((1..it.dub).map { epNum ->
Episode( Episode(
"$mainUrl/anime/${showData.Id}/episodes/dub/$epNum", episode = epNum AllAnimeLoadData(showData.Id, "dub", epNum).toJson(), episode = epNum
) )
}) else null) }) else null)
} }
@ -279,7 +286,8 @@ class AllAnimeProvider : MainAPI() {
tags = showData.genres tags = showData.genres
year = showData.airedStart?.year year = showData.airedStart?.year
duration = showData.episodeDuration?.div(60_000) 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.Subbed, episodes.first)
addEpisodes(DubStatus.Dubbed, episodes.second) addEpisodes(DubStatus.Dubbed, episodes.second)
@ -299,6 +307,7 @@ class AllAnimeProvider : MainAPI() {
"https://videobin.co/", "https://videobin.co/",
"https://ok.ru", "https://ok.ru",
"https://streamlare.com", "https://streamlare.com",
"https://gembedhd.com",
) )
private fun embedIsBlacklisted(url: String): Boolean { 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( override suspend fun loadLinks(
data: String, data: String,
isCasting: Boolean, isCasting: Boolean,
subtitleCallback: (SubtitleFile) -> Unit, subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit callback: (ExtractorLink) -> Unit
): Boolean { ): Boolean {
val loadData = parseJson<AllAnimeLoadData>(data)
var apiEndPoint = var apiEndPoint =
parseJson<ApiEndPoint>(app.get("$mainUrl/getVersion").text).episodeIframeHead parseJson<ApiEndPoint>(app.get("$mainUrl/getVersion").text).episodeIframeHead
if (apiEndPoint.endsWith("/")) apiEndPoint = if (apiEndPoint.endsWith("/")) apiEndPoint =
apiEndPoint.slice(0 until apiEndPoint.length - 1) 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<LinksQuery>()
val sources = Regex("""sourceUrl[:=]"(.+?)"""").findAll(html).toList() apiResponse.data?.episode?.sourceUrls?.apmap { source ->
.map { URLDecoder.decode(it.destructured.component1().sanitize(), "UTF-8") }
sources.apmap {
safeApiCall { safeApiCall {
var link = it.replace(" ", "%20") val link = source.sourceUrl?.replace(" ", "%20") ?: return@safeApiCall
if (URI(link).isAbsolute || link.startsWith("//")) { 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)) { if (embedIsBlacklisted(fixedLink)) {
// for now ignore loadExtractor(fixedLink, subtitleCallback, callback)
} else if (!embedIsBlacklisted(link)) { } else if (URI(fixedLink).path.contains(".m3u")) {
if (URI(link).path.contains(".m3u")) { getM3u8Qualities(fixedLink, mainUrl, sourceName).forEach(callback)
getM3u8Qualities(link, data, URI(link).host).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<AllAnimeVideoApiResponse>()?.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 { } else {
callback( callback(
ExtractorLink( ExtractorLink(
"AllAnime - " + URI(link).host, "AllAnime - " + URI(server.link).host,
"", server.resolutionStr,
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<AllAnimeVideoApiResponse>(response.text).links
links.forEach { server ->
if (server.hls != null && server.hls) {
getM3u8Qualities(
server.link, server.link,
"$apiEndPoint/player?uri=" + (if (URI(server.link).host.isNotEmpty()) server.link else apiEndPoint + URI( "$apiEndPoint/player?uri=" + (if (URI(server.link).host.isNotEmpty()) server.link else apiEndPoint + URI(
server.link server.link
).path), ).path),
server.resolutionStr Qualities.P1080.value,
).forEach(callback) false
} 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
)
) )
} )
} }
} }
} }

View File

@ -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<SourceUrls> = 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<String> = 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
)