mirror of
https://github.com/hexated/cloudstream-extensions-hexated.git
synced 2024-08-15 00:03:22 +00:00
added Anroll
This commit is contained in:
parent
b74f198e4d
commit
a46583ee2c
4 changed files with 283 additions and 0 deletions
26
Anroll/build.gradle.kts
Normal file
26
Anroll/build.gradle.kts
Normal file
|
@ -0,0 +1,26 @@
|
|||
// use an integer for version numbers
|
||||
version = 1
|
||||
|
||||
cloudstream {
|
||||
language = "pt"
|
||||
// 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(
|
||||
"Anime",
|
||||
"AnimeMovie",
|
||||
"OVA",
|
||||
)
|
||||
|
||||
iconUrl = "https://www.google.com/s2/favicons?domain=www.anroll.net&sz=%size%"
|
||||
}
|
2
Anroll/src/main/AndroidManifest.xml
Normal file
2
Anroll/src/main/AndroidManifest.xml
Normal file
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.hexated"/>
|
241
Anroll/src/main/kotlin/com/hexated/Anroll.kt
Normal file
241
Anroll/src/main/kotlin/com/hexated/Anroll.kt
Normal file
|
@ -0,0 +1,241 @@
|
|||
package com.hexated
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.lagradost.cloudstream3.*
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.toJson
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.Qualities
|
||||
import org.jsoup.nodes.Element
|
||||
|
||||
class Anroll : MainAPI() {
|
||||
override var mainUrl = "https://www.anroll.net"
|
||||
override var name = "Anroll"
|
||||
override val hasMainPage = true
|
||||
override var lang = "pt"
|
||||
override val hasDownloadSupport = true
|
||||
override val hasQuickSearch = true
|
||||
|
||||
override val supportedTypes = setOf(
|
||||
TvType.Anime,
|
||||
TvType.AnimeMovie,
|
||||
TvType.OVA
|
||||
)
|
||||
|
||||
companion object {
|
||||
private const val searchUrl = "https://apiv2-prd.anroll.net"
|
||||
private const val episodeUrl = "https://apiv3-prd.anroll.net"
|
||||
private const val posterUrl = "https://static.anroll.net"
|
||||
private const val videoUrl = "https://cdn-zenitsu.gamabunta.xyz"
|
||||
}
|
||||
|
||||
override suspend fun getMainPage(
|
||||
page: Int,
|
||||
request: MainPageRequest
|
||||
): HomePageResponse {
|
||||
val document = app.get("$mainUrl/home").document
|
||||
val home = mutableListOf<HomePageList>()
|
||||
document.select("div.sc-f5d5b250-1.iJHcsI").map { div ->
|
||||
val header = div.selectFirst("h2")?.text() ?: return@map
|
||||
val child = HomePageList(
|
||||
header,
|
||||
div.select("ul li").mapNotNull {
|
||||
it.toSearchResult()
|
||||
},
|
||||
header == "Últimos Laçamentos"
|
||||
)
|
||||
home.add(child)
|
||||
}
|
||||
return HomePageResponse(home)
|
||||
}
|
||||
|
||||
private fun Element.toSearchResult(): AnimeSearchResponse? {
|
||||
val title = this.selectFirst("h1")?.text()?.trim() ?: ""
|
||||
val href = fixUrl(this.selectFirst("a")?.attr("href") ?: return null)
|
||||
val posterUrl = fixUrlNull(this.select("img").attr("src"))
|
||||
val epNum = this.selectFirst("span.sc-f5d5b250-3.fsTgnD b")?.text()?.toIntOrNull()
|
||||
val isDub = this.selectFirst("div.sc-9dbd1f1d-5.efznig")?.text() == "DUB"
|
||||
return newAnimeSearchResponse(title, href, TvType.Anime) {
|
||||
this.posterUrl = posterUrl
|
||||
addDubStatus(isDub, epNum)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun quickSearch(query: String): List<SearchResponse> = search(query)
|
||||
|
||||
override suspend fun search(query: String): List<SearchResponse> {
|
||||
val res = app.get("$searchUrl/search?q=$query").parsedSafe<SearchAnime>()
|
||||
val collection = mutableListOf<SearchResponse>()
|
||||
val anime = res?.data_anime?.mapNotNull {
|
||||
addAnimeSearch(
|
||||
it.titulo ?: return@mapNotNull null,
|
||||
"a/${it.generate_id}",
|
||||
it.slug_serie ?: return@mapNotNull null,
|
||||
Image.Anime
|
||||
)
|
||||
}
|
||||
if (anime?.isNotEmpty() == true) collection.addAll(anime)
|
||||
val filme = res?.data_filme?.mapNotNull {
|
||||
addAnimeSearch(
|
||||
it.nome_filme ?: return@mapNotNull null,
|
||||
"f/${it.generate_id}",
|
||||
it.slug_filme ?: return@mapNotNull null,
|
||||
Image.Filme
|
||||
)
|
||||
}
|
||||
if (filme?.isNotEmpty() == true) collection.addAll(filme)
|
||||
return collection
|
||||
}
|
||||
|
||||
override suspend fun load(url: String): LoadResponse? {
|
||||
val fixUrl = getProperAnimeLink(url) ?: throw ErrorLoadingException()
|
||||
val document = app.get(fixUrl).document
|
||||
|
||||
val article = document.selectFirst("article.sc-f5d5b250-9") ?: return null
|
||||
val title = article.selectFirst("h2")?.text() ?: return null
|
||||
val poster = fixUrlNull(document.select("article.sc-f5d5b250-8 img").attr("src"))
|
||||
val tags = article.select("div#generos a").map { it.text() }
|
||||
val year = article.selectFirst("div.sc-f5d5b250-4")?.nextElementSibling()?.text()
|
||||
?.toIntOrNull()
|
||||
val description = document.select("div.sinopse").text().trim()
|
||||
val type = if (fixUrl.contains("/a/")) TvType.Anime else TvType.AnimeMovie
|
||||
|
||||
val episodes = mutableListOf<Episode>()
|
||||
|
||||
if (type == TvType.Anime) {
|
||||
for (i in 1..10) {
|
||||
val dataEpisode = app.get("$episodeUrl/animes/${fixUrl.substringAfterLast("/")}/episodes?page=$i&order=desc")
|
||||
.parsedSafe<LoadAnime>()?.data?.map {
|
||||
Episode(
|
||||
Load(it.anime?.get("slug_serie"), it.n_episodio, "animes").toJson(),
|
||||
it.titulo_episodio,
|
||||
episode = it.n_episodio?.toIntOrNull(),
|
||||
posterUrl = it.anime?.get("slug_serie")?.fixImageUrl(Image.Episode),
|
||||
description = it.sinopse_episodio
|
||||
)
|
||||
}?.reversed() ?: emptyList()
|
||||
if(dataEpisode.isEmpty()) break else episodes.addAll(dataEpisode)
|
||||
}
|
||||
} else {
|
||||
val dataEpisode = listOf(
|
||||
Episode(
|
||||
Load(
|
||||
document.selectFirst("script:containsData(slug_filme)")?.data()?.let {
|
||||
Regex("[\"']slug_filme[\"']:[\"'](\\S+?)[\"']").find(it)?.groupValues?.get(1)
|
||||
} ?: return null, "movie", "movies"
|
||||
).toJson()
|
||||
|
||||
)
|
||||
)
|
||||
episodes.addAll(dataEpisode)
|
||||
}
|
||||
|
||||
return newAnimeLoadResponse(title, url, type) {
|
||||
engName = title
|
||||
posterUrl = poster
|
||||
this.year = year
|
||||
addEpisodes(DubStatus.Subbed, episodes)
|
||||
plot = description
|
||||
this.tags = tags
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override suspend fun loadLinks(
|
||||
data: String,
|
||||
isCasting: Boolean,
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
): Boolean {
|
||||
val load = tryParseJson<Load>(data)
|
||||
callback.invoke(
|
||||
ExtractorLink(
|
||||
this.name,
|
||||
this.name,
|
||||
if(load?.type == "movies") {
|
||||
"$videoUrl/hls/${load.type}/${load.slug_serie}/${load.n_episodio}.mp4/media-1/stream.m3u8"
|
||||
} else {
|
||||
"$videoUrl/cf/hls/${load?.type}/${load?.slug_serie}/${load?.n_episodio}.mp4/media-1/stream.m3u8"
|
||||
},
|
||||
"$mainUrl/",
|
||||
Qualities.Unknown.value,
|
||||
true
|
||||
)
|
||||
)
|
||||
return true
|
||||
}
|
||||
|
||||
private suspend fun getProperAnimeLink(uri: String): String? {
|
||||
return if (uri.contains("/e/")) {
|
||||
app.get(uri).document.selectFirst("div.epcontrol2 a[href*=/a/]")?.attr("href")?.let {
|
||||
fixUrl(it)
|
||||
}
|
||||
} else {
|
||||
uri
|
||||
}
|
||||
}
|
||||
|
||||
private fun addAnimeSearch(titulo: String, id: String, slug: String, type: Image): AnimeSearchResponse {
|
||||
return newAnimeSearchResponse(titulo, "$mainUrl/$id", TvType.Anime) {
|
||||
this.posterUrl = slug.fixImageUrl(type)
|
||||
}
|
||||
}
|
||||
|
||||
private fun String.fixImageUrl(param: Image): String {
|
||||
return when (param) {
|
||||
Image.Episode -> {
|
||||
"$posterUrl/images/animes/screens/$this/130x74/007.jpg"
|
||||
}
|
||||
Image.Anime -> {
|
||||
"$mainUrl/_next/image?url=$posterUrl/images/animes/capas/130x209/$this.jpg&w=384&q=75"
|
||||
}
|
||||
Image.Filme -> {
|
||||
"$mainUrl/_next/image?url=$posterUrl/images/filmes/capas/130x209/$this.jpg&w=384&q=75"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum class Image {
|
||||
Episode,
|
||||
Anime,
|
||||
Filme,
|
||||
}
|
||||
|
||||
data class Load(
|
||||
val slug_serie: String? = null,
|
||||
val n_episodio: String? = null,
|
||||
val type: String? = null,
|
||||
)
|
||||
|
||||
data class DataEpisode(
|
||||
@JsonProperty("id_series_episodios") val id_series_episodios: Int? = null,
|
||||
@JsonProperty("n_episodio") val n_episodio: String? = null,
|
||||
@JsonProperty("titulo_episodio") val titulo_episodio: String? = null,
|
||||
@JsonProperty("sinopse_episodio") val sinopse_episodio: String? = null,
|
||||
@JsonProperty("generate_id") val generate_id: String? = null,
|
||||
@JsonProperty("anime") val anime: HashMap<String, String>? = null,
|
||||
)
|
||||
|
||||
data class LoadAnime(
|
||||
@JsonProperty("data") val data: ArrayList<DataEpisode>? = arrayListOf()
|
||||
)
|
||||
|
||||
data class DataAnime(
|
||||
@JsonProperty("titulo") val titulo: String? = null,
|
||||
@JsonProperty("generate_id") val generate_id: String? = null,
|
||||
@JsonProperty("slug_serie") val slug_serie: String? = null,
|
||||
@JsonProperty("total_eps_anime") val total_eps_anime: Int? = null,
|
||||
)
|
||||
|
||||
data class DataFilme(
|
||||
@JsonProperty("nome_filme") val nome_filme: String? = null,
|
||||
@JsonProperty("generate_id") val generate_id: String? = null,
|
||||
@JsonProperty("slug_filme") val slug_filme: String? = null,
|
||||
)
|
||||
|
||||
data class SearchAnime(
|
||||
@JsonProperty("data_anime") val data_anime: ArrayList<DataAnime>? = arrayListOf(),
|
||||
@JsonProperty("data_filme") val data_filme: ArrayList<DataFilme>? = arrayListOf(),
|
||||
)
|
||||
|
||||
}
|
14
Anroll/src/main/kotlin/com/hexated/AnrollPlugin.kt
Normal file
14
Anroll/src/main/kotlin/com/hexated/AnrollPlugin.kt
Normal file
|
@ -0,0 +1,14 @@
|
|||
|
||||
package com.hexated
|
||||
|
||||
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
|
||||
import com.lagradost.cloudstream3.plugins.Plugin
|
||||
import android.content.Context
|
||||
|
||||
@CloudstreamPlugin
|
||||
class AnrollPlugin: Plugin() {
|
||||
override fun load(context: Context) {
|
||||
// All providers should be added in this manner. Please don't edit the providers list directly.
|
||||
registerMainAPI(Anroll())
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue