Skip to content

Commit 1864200

Browse files
Last Sync: 2026-02-24 02:48 (Mobile)
1 parent 8ef7d09 commit 1864200

2 files changed

Lines changed: 167 additions & 147 deletions

File tree

AnimasuProvider/src/main/kotlin/com/animasu/AnimasuProvider.kt

Lines changed: 58 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ import com.lagradost.cloudstream3.*
44
import com.lagradost.cloudstream3.LoadResponse.Companion.addAniListId
55
import com.lagradost.cloudstream3.LoadResponse.Companion.addMalId
66
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
7+
import com.lagradost.cloudstream3.amap
78
import com.lagradost.cloudstream3.utils.*
9+
import kotlinx.coroutines.runBlocking
810
import org.jsoup.Jsoup
911
import org.jsoup.nodes.Element
1012

@@ -35,7 +37,7 @@ class AnimasuProvider : MainAPI() {
3537
fun getStatus(t: String?): ShowStatus {
3638
if (t == null) return ShowStatus.Completed
3739
return when {
38-
t.contains("Sedang Tayang", true) -> ShowStatus.Ongoing
40+
t.contains("Ongoing", true) -> ShowStatus.Ongoing
3941
else -> ShowStatus.Completed
4042
}
4143
}
@@ -52,12 +54,10 @@ class AnimasuProvider : MainAPI() {
5254

5355
override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse {
5456
val document = app.get("$mainUrl/pencarian/?${request.data}&halaman=$page").document
55-
56-
val homeList = document.select("div.listupd div.bs").mapNotNull {
57+
val home = document.select("div.listupd div.bs").map {
5758
it.toSearchResult()
5859
}
59-
60-
return newHomePageResponse(request.name, homeList, hasNext = homeList.isNotEmpty())
60+
return newHomePageResponse(request.name, home)
6161
}
6262

6363
private fun getProperAnimeLink(uri: String): String {
@@ -66,70 +66,68 @@ class AnimasuProvider : MainAPI() {
6666
} else {
6767
var title = uri.substringAfter("$mainUrl/")
6868
title = when {
69-
(title.contains("-episode")) && !(title.contains("-movie")) -> title.substringBefore("-episode")
69+
(title.contains("-episode")) && !(title.contains("-movie")) -> title.substringBefore(
70+
"-episode"
71+
)
72+
7073
(title.contains("-movie")) -> title.substringBefore("-movie")
7174
else -> title
7275
}
76+
7377
"$mainUrl/anime/$title"
7478
}
7579
}
7680

77-
private fun Element.toSearchResult(): AnimeSearchResponse? {
78-
val a = this.selectFirst("a") ?: return null
79-
val href = getProperAnimeLink(fixUrlNull(a.attr("href")).toString())
81+
private fun Element.toSearchResult(): AnimeSearchResponse {
82+
val href = getProperAnimeLink(fixUrlNull(this.selectFirst("a")?.attr("href")).toString())
8083
val title = this.select("div.tt").text().trim()
8184
val posterUrl = fixUrlNull(this.selectFirst("img")?.getImageAttr())
8285
val epNum = this.selectFirst("span.epx")?.text()?.filter { it.isDigit() }?.toIntOrNull()
83-
8486
return newAnimeSearchResponse(title, href, TvType.Anime) {
8587
this.posterUrl = posterUrl
8688
addSub(epNum)
8789
}
90+
8891
}
8992

9093
override suspend fun search(query: String): List<SearchResponse> {
91-
val document = app.get("$mainUrl/?s=$query").document
92-
return document.select("div.listupd div.bs").mapNotNull {
93-
it.toSearchResult()
94+
return app.get("$mainUrl/?s=$query").document.select("div.listupd div.bs").map {
95+
it.toSearchResult()
9496
}
9597
}
9698

97-
override suspend fun load(url: String): LoadResponse? {
99+
override suspend fun load(url: String): LoadResponse {
98100
val document = app.get(url).document
99101

100-
val rawTitle = document.selectFirst("div.infox h1")?.text() ?: return null
101-
val title = rawTitle.replace("Sub Indo", "").trim()
102+
val title =
103+
document.selectFirst("div.infox h1")?.text().toString().replace("Sub Indo", "").trim()
102104
val poster = document.selectFirst("div.bigcontent img")?.getImageAttr()
103105

104106
val table = document.selectFirst("div.infox div.spe")
105-
val typeStr = table?.selectFirst("span:contains(Jenis:)")?.ownText()
106-
val type = getType(typeStr)
107-
val year = table?.selectFirst("span:contains(Rilis:)")?.ownText()?.substringAfterLast(",")?.trim()?.toIntOrNull()
108-
val statusStr = table?.selectFirst("span:contains(Status:) font")?.text()
109-
val status = getStatus(statusStr)
110-
107+
val type = getType(table?.selectFirst("span:contains(Jenis:)")?.ownText())
108+
val year =
109+
table?.selectFirst("span:contains(Rilis:)")?.ownText()?.substringAfterLast(",")?.trim()
110+
?.toIntOrNull()
111+
val status = table?.selectFirst("span:contains(Status:) font")?.text()
111112
val trailer = document.selectFirst("div.trailer iframe")?.attr("src")
112-
val tags = table?.select("span:contains(Genre:) a")?.map { it.text() }
113-
val plotDesc = document.select("div.sinopsis p").text()
114-
115-
val episodes = document.select("ul#daftarepisode > li").mapNotNull {
116-
val link = fixUrlNull(it.selectFirst("a")?.attr("href")) ?: return@mapNotNull null
113+
val episodes = document.select("ul#daftarepisode > li").map {
114+
val link = fixUrl(it.selectFirst("a")!!.attr("href"))
117115
val name = it.selectFirst("a")?.text() ?: ""
118-
val episode = Regex("Episode\\s?(\\d+)").find(name)?.groupValues?.getOrNull(1)?.toIntOrNull()
116+
val episode =
117+
Regex("Episode\\s?(\\d+)").find(name)?.groupValues?.getOrNull(0)?.toIntOrNull()
119118
newEpisode(link) { this.episode = episode }
120119
}.reversed()
121120

122121
val tracker = APIHolder.getTracker(listOf(title), TrackerType.getTypes(type), year, true)
123122

124123
return newAnimeLoadResponse(title, url, type) {
125-
engName = title
126124
posterUrl = tracker?.image ?: poster
127125
backgroundPosterUrl = tracker?.cover
128126
this.year = year
129127
addEpisodes(DubStatus.Subbed, episodes)
130-
showStatus = status
131-
plot = plotDesc
132-
this.tags = tags
128+
showStatus = getStatus(status)
129+
plot = document.select("div.sinopsis p").text()
130+
this.tags = table?.select("span:contains(Genre:) a")?.map { it.text() }
133131
addTrailer(trailer)
134132
addMalId(tracker?.malId)
135133
addAniListId(tracker?.aniId?.toIntOrNull())
@@ -143,62 +141,47 @@ class AnimasuProvider : MainAPI() {
143141
callback: (ExtractorLink) -> Unit
144142
): Boolean {
145143
val document = app.get(data).document
146-
147-
document.select(".mobius select.mirror option").toList().amap { option ->
148-
val rawValue = option.attr("value")
149-
if (rawValue.isNotEmpty()) {
150-
val decodedHtml = base64Decode(rawValue)
151-
val iframeUrl = Jsoup.parse(decodedHtml).select("iframe").attr("src")
152-
val qualityText = option.text()
153-
154-
if (iframeUrl.isNotEmpty()) {
155-
loadFixedExtractor(
156-
fixUrl(iframeUrl),
157-
qualityText,
158-
data,
159-
subtitleCallback,
160-
callback
161-
)
162-
}
163-
}
144+
document.select(".mobius > .mirror > option").mapNotNull {
145+
fixUrl(
146+
Jsoup.parse(base64Decode(it.attr("value"))).select("iframe").attr("src")
147+
) to it.text()
148+
}.amap { (iframe, quality) ->
149+
loadFixedExtractor(iframe, quality, "$mainUrl/", subtitleCallback, callback)
164150
}
165151
return true
166152
}
167153

168154
private suspend fun loadFixedExtractor(
169155
url: String,
170-
qualityName: String,
156+
quality: String?,
171157
referer: String? = null,
172158
subtitleCallback: (SubtitleFile) -> Unit,
173159
callback: (ExtractorLink) -> Unit
174160
) {
175-
val extractedQuality = qualityName.fixQuality()
176-
177161
loadExtractor(url, referer, subtitleCallback) { link ->
178-
val newLink = newExtractorLink(
179-
source = link.source,
180-
name = "$qualityName - ${link.name}",
181-
url = link.url,
182-
type = link.type
183-
) {
184-
this.referer = link.referer
185-
this.quality = if (link.quality == Qualities.Unknown.value) extractedQuality else link.quality
186-
this.headers = link.headers
162+
runBlocking {
163+
callback.invoke(
164+
newExtractorLink(
165+
link.name,
166+
link.name,
167+
link.url,
168+
link.type
169+
) {
170+
this.referer = link.referer
171+
this.quality = if (link.type == ExtractorLinkType.M3U8 || link.name == "Uservideo") link.quality else getIndexQuality(
172+
quality
173+
)
174+
this.headers = link.headers
175+
this.extractorData = link.extractorData
176+
}
177+
)
187178
}
188-
callback.invoke(newLink)
189179
}
190180
}
191181

192-
private fun String.fixQuality(): Int {
193-
val lower = this.lowercase()
194-
return when {
195-
lower.contains("1080") || lower.contains("fhd") -> Qualities.P1080.value
196-
lower.contains("720") || lower.contains("hd") -> Qualities.P720.value
197-
lower.contains("480") || lower.contains("sd") -> Qualities.P480.value
198-
lower.contains("360") -> Qualities.P360.value
199-
else -> Regex("(\\d{3,4})").find(this)?.groupValues?.getOrNull(1)?.toIntOrNull()
200-
?: Qualities.Unknown.value
201-
}
182+
private fun getIndexQuality(str: String?): Int {
183+
return Regex("(\\d{3,4})[pP]").find(str ?: "")?.groupValues?.getOrNull(1)?.toIntOrNull()
184+
?: Qualities.Unknown.value
202185
}
203186

204187
private fun Element.getImageAttr(): String? {
@@ -209,4 +192,5 @@ class AnimasuProvider : MainAPI() {
209192
else -> this.attr("abs:src")
210193
}
211194
}
212-
}
195+
196+
}

0 commit comments

Comments
 (0)