fix some providers: Anichi, Layarkaca, Anroll, Movierulzhd

This commit is contained in:
ghost 2023-07-13 13:27:01 +07:00
parent 20dbd2a774
commit 1e272a0893
9 changed files with 143 additions and 50 deletions

View file

@ -1,7 +1,7 @@
import org.jetbrains.kotlin.konan.properties.Properties import org.jetbrains.kotlin.konan.properties.Properties
// use an integer for version numbers // use an integer for version numbers
version = 4 version = 5
android { android {
defaultConfig { defaultConfig {

View file

@ -2,12 +2,12 @@ package com.hexated
import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.APIHolder.getTracker
import com.lagradost.cloudstream3.LoadResponse.Companion.addActors import com.lagradost.cloudstream3.LoadResponse.Companion.addActors
import com.lagradost.cloudstream3.LoadResponse.Companion.addAniListId import com.lagradost.cloudstream3.LoadResponse.Companion.addAniListId
import com.lagradost.cloudstream3.LoadResponse.Companion.addMalId import com.lagradost.cloudstream3.LoadResponse.Companion.addMalId
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
import com.lagradost.cloudstream3.extractors.helper.GogoHelper import com.lagradost.cloudstream3.extractors.helper.GogoHelper
import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.mvvm.safeApiCall import com.lagradost.cloudstream3.mvvm.safeApiCall
import com.lagradost.cloudstream3.utils.* import com.lagradost.cloudstream3.utils.*
import com.lagradost.cloudstream3.utils.AppUtils.parseJson 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) override val supportedTypes = setOf(TvType.Anime, TvType.AnimeMovie)
private val popularTitle = "Popular" private val popularTitle = "Popular"
@ -141,7 +133,6 @@ class Anichi : MainAPI() {
val title = showData.name val title = showData.name
val description = showData.description val description = showData.description
val poster = showData.thumbnail val poster = showData.thumbnail
val type = getType(showData.type ?: "")
val episodes = showData.availableEpisodesDetail.let { val episodes = showData.availableEpisodesDetail.let {
if (it == null) return@let Pair(null, null) if (it == null) return@let Pair(null, null)
@ -164,13 +155,12 @@ class Anichi : MainAPI() {
Pair(Actor(name, image), role) Pair(Actor(name, image), role)
} }
val names = showData.altNames?.plus(title)?.filterNotNull() ?: emptyList() val trackers = getTracker(title, showData.altNames?.firstOrNull(), showData.airedStart?.year, showData.season?.quarter, showData.type)
val trackers = getTracker(names, TrackerType.getTypes(type), showData.airedStart?.year)
return newAnimeLoadResponse(title ?: "", url, TvType.Anime) { return newAnimeLoadResponse(title ?: "", url, TvType.Anime) {
engName = showData.altNames?.firstOrNull() engName = showData.altNames?.firstOrNull()
posterUrl = trackers?.image ?: poster posterUrl = trackers?.coverImage?.extraLarge ?: trackers?.coverImage?.large ?: poster
backgroundPosterUrl = trackers?.cover ?: showData.banner backgroundPosterUrl = trackers?.bannerImage ?: showData.banner
rating = showData.averageScore?.times(100) rating = showData.averageScore?.times(100)
tags = showData.genres tags = showData.genres
year = showData.airedStart?.year year = showData.airedStart?.year
@ -184,8 +174,8 @@ class Anichi : MainAPI() {
//this.recommendations = recommendations //this.recommendations = recommendations
showStatus = getStatus(showData.status.toString()) showStatus = getStatus(showData.status.toString())
addMalId(trackers?.malId) addMalId(trackers?.idMal)
addAniListId(trackers?.aniId?.toIntOrNull()) addAniListId(trackers?.id)
plot = description?.replace(Regex("""<(.*?)>"""), "") plot = description?.replace(Regex("""<(.*?)>"""), "")
} }
} }
@ -273,6 +263,14 @@ class Anichi : MainAPI() {
isDash = server.resolutionStr == "Dash 1" 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 -> return meta.map { eps ->
Episode( Episode(
AnichiLoadData(id, lang, eps).toJson(), AnichiLoadData(id, lang, eps).toJson(),
"Ep $eps" "Ep $eps",
episode = eps.toIntOrNull()
) )
}.reversed() }.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<AniSearch>()?.data?.Page?.media?.firstOrNull()
} catch (t: Throwable) {
logError(t)
null
}
}
companion object { companion object {
private const val apiUrl = BuildConfig.ANICHI_API private const val apiUrl = BuildConfig.ANICHI_API
private const val serverUrl = BuildConfig.ANICHI_SERVER private const val serverUrl = BuildConfig.ANICHI_SERVER
@ -406,6 +468,30 @@ class Anichi : MainAPI() {
val episode: String 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<AniMedia> = arrayListOf()
)
data class AniData(
@JsonProperty("Page") var Page: AniPage? = AniPage()
)
data class AniSearch(
@JsonProperty("data") var data: AniData? = AniData()
)
data class AkIframe( data class AkIframe(
@JsonProperty("idUrl") val idUrl: String? = null, @JsonProperty("idUrl") val idUrl: String? = null,
) )

View file

@ -1,5 +1,5 @@
// use an integer for version numbers // use an integer for version numbers
version = 1 version = 2
cloudstream { cloudstream {
language = "pt-pt" language = "pt-pt"

View file

@ -35,7 +35,7 @@ class Anroll : MainAPI() {
): HomePageResponse { ): HomePageResponse {
val document = app.get("$mainUrl/home").document val document = app.get("$mainUrl/home").document
val home = mutableListOf<HomePageList>() val home = mutableListOf<HomePageList>()
document.select("div.sc-f5d5b250-1.iJHcsI").map { div -> document.select("div.hAbQAe").map { div ->
val header = div.selectFirst("h2")?.text() ?: return@map val header = div.selectFirst("h2")?.text() ?: return@map
val child = HomePageList( val child = HomePageList(
header, header,
@ -91,11 +91,11 @@ class Anroll : MainAPI() {
val fixUrl = getProperAnimeLink(url) ?: throw ErrorLoadingException() val fixUrl = getProperAnimeLink(url) ?: throw ErrorLoadingException()
val document = app.get(fixUrl).document 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 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 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() ?.toIntOrNull()
val description = document.select("div.sinopse").text().trim() val description = document.select("div.sinopse").text().trim()
val type = if (fixUrl.contains("/a/")) TvType.Anime else TvType.AnimeMovie val type = if (fixUrl.contains("/a/")) TvType.Anime else TvType.AnimeMovie

View file

@ -1,5 +1,5 @@
// use an integer for version numbers // use an integer for version numbers
version = 13 version = 14
cloudstream { cloudstream {

View file

@ -6,11 +6,10 @@ import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
import com.lagradost.cloudstream3.utils.* import com.lagradost.cloudstream3.utils.*
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import java.net.URLDecoder import java.net.URLDecoder
import java.net.URI
class LayarKacaProvider : MainAPI() { class LayarKacaProvider : MainAPI() {
override var mainUrl = "https://d21.fun" override var mainUrl = "https://tv.lk21official.pro"
private var seriesUrl = "https://tv.nontondrama.click" private var seriesUrl = "https://tv1.nontondrama.click"
override var name = "LayarKaca" override var name = "LayarKaca"
override val hasMainPage = true override val hasMainPage = true
override var lang = "id" override var lang = "id"
@ -57,7 +56,7 @@ class LayarKacaProvider : MainAPI() {
private fun Element.toSearchResult(): SearchResponse? { private fun Element.toSearchResult(): SearchResponse? {
val title = this.selectFirst("h1.grid-title > a")?.ownText()?.trim() ?: return null val title = this.selectFirst("h1.grid-title > a")?.ownText()?.trim() ?: return null
val href = fixUrl(this.selectFirst("a")!!.attr("href")) 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 = val type =
if (this.selectFirst("div.last-episode") == null) TvType.Movie else TvType.TvSeries if (this.selectFirst("div.last-episode") == null) TvType.Movie else TvType.TvSeries
return if (type == TvType.TvSeries) { return if (type == TvType.TvSeries) {
@ -176,33 +175,34 @@ class LayarKacaProvider : MainAPI() {
it it
} }
} }
invokeCast(link, callback) loadExtractor(link, bananalicious, subtitleCallback, callback)
} }
return true 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") 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)
}
}

View file

@ -10,5 +10,6 @@ class LayarKacaProviderPlugin: Plugin() {
override fun load(context: Context) { override fun load(context: Context) {
// All providers should be added in this manner. Please don't edit the providers list directly. // All providers should be added in this manner. Please don't edit the providers list directly.
registerMainAPI(LayarKacaProvider()) registerMainAPI(LayarKacaProvider())
registerExtractorAPI(Emturbovid())
} }
} }

View file

@ -11,6 +11,11 @@ import kotlin.random.Random
const val twoEmbedAPI = "https://www.2embed.to" const val twoEmbedAPI = "https://www.2embed.to"
class Sbnmp : Sbflix() {
override val name = "Sbnmp"
override var mainUrl = "https://sbnmp.bar"
}
class Sbrulz : Sbflix() { class Sbrulz : Sbflix() {
override val name = "Sbrulz" override val name = "Sbrulz"
override var mainUrl = "https://sbrulz.xyz" override var mainUrl = "https://sbrulz.xyz"

View file

@ -13,5 +13,6 @@ class MovierulzhdPlugin: Plugin() {
registerExtractorAPI(Sbflix()) registerExtractorAPI(Sbflix())
registerExtractorAPI(Sbrulz()) registerExtractorAPI(Sbrulz())
registerExtractorAPI(Sbmiz()) registerExtractorAPI(Sbmiz())
registerExtractorAPI(Sbnmp())
} }
} }