Skip to content

Commit 6a5bb97

Browse files
test
1 parent d0cf5bd commit 6a5bb97

5 files changed

Lines changed: 315 additions & 0 deletions

File tree

NimegamiProvider/build.gradle.kts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// use an integer for version numbers
2+
version = 1
3+
4+
5+
cloudstream {
6+
language = "id"
7+
// All of these properties are optional, you can safely remove them
8+
9+
// description = "Lorem Ipsum"
10+
authors = listOf("Hexated")
11+
12+
/**
13+
* Status int as the following:
14+
* 0: Down
15+
* 1: Ok
16+
* 2: Slow
17+
* 3: Beta only
18+
* */
19+
status = 1 // will be 3 if unspecified
20+
tvTypes = listOf(
21+
"AnimeMovie",
22+
"Anime",
23+
"OVA",
24+
)
25+
26+
iconUrl = "https://www.google.com/s2/favicons?domain=nimegami.id&sz=%size%"
27+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<manifest package="com.hexated"/>
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
package com.hexated
2+
3+
import com.lagradost.cloudstream3.*
4+
import com.lagradost.cloudstream3.SubtitleFile
5+
import com.lagradost.cloudstream3.utils.*
6+
import okhttp3.MediaType.Companion.toMediaTypeOrNull
7+
import okhttp3.RequestBody
8+
import org.json.JSONObject
9+
10+
class DlganExtractor : ExtractorApi() {
11+
override val name = "Dlgan"
12+
override val mainUrl = "https://dlgan.space/"
13+
override val requiresReferer = false
14+
15+
override suspend fun getUrl(
16+
url: String,
17+
referer: String?,
18+
subtitleCallback: (SubtitleFile) -> Unit,
19+
callback: (ExtractorLink) -> Unit
20+
) {
21+
val html = app.get(url, headers = mapOf("Referer" to (referer ?: mainUrl))).text
22+
23+
Regex("""stream_url":"(https:[^"]+)""").findAll(html).forEach { match ->
24+
val stream = match.groupValues[1]
25+
.replace("\\/", "/")
26+
.replace("\\u0026", "&")
27+
28+
val quality = Regex("""(\d{3,4}p)""").find(stream)?.value
29+
30+
callback(
31+
newExtractorLink(name, "$name ${quality ?: ""}", stream, ExtractorLinkType.VIDEO) {
32+
this.referer = referer ?: mainUrl
33+
this.quality = getQualityFromName(quality)
34+
this.headers = mapOf("Referer" to (referer ?: mainUrl))
35+
}
36+
)
37+
}
38+
}
39+
}
40+
41+
class BerkasDriveExtractor : ExtractorApi() {
42+
override val name = "BerkasDrive"
43+
override val mainUrl = "https://dl.berkasdrive.com"
44+
override val requiresReferer = false
45+
46+
override suspend fun getUrl(
47+
url: String,
48+
referer: String?,
49+
subtitleCallback: (SubtitleFile) -> Unit,
50+
callback: (ExtractorLink) -> Unit
51+
) {
52+
53+
val id = Regex("id=([a-zA-Z0-9+/=]+)").find(url)?.groupValues?.getOrNull(1)
54+
55+
if (id != null) {
56+
try {
57+
val api = "$mainUrl/new/streaming.php?action=stream-worker&id=$id"
58+
59+
val response = app.get(
60+
api,
61+
headers = mapOf(
62+
"User-Agent" to "Mozilla/5.0",
63+
"Referer" to "$mainUrl/"
64+
)
65+
).text
66+
67+
val json = JSONObject(response)
68+
69+
if (json.getBoolean("ok")) {
70+
val videoUrl = json.getString("url").replace("\\/", "/")
71+
val quality = Regex("""(\d{3,4}p)""").find(videoUrl)?.value
72+
73+
callback(
74+
newExtractorLink(
75+
name,
76+
"$name ${quality ?: ""}",
77+
videoUrl,
78+
ExtractorLinkType.VIDEO
79+
) {
80+
this.referer = "$mainUrl/"
81+
this.quality = getQualityFromName(quality)
82+
this.headers = mapOf(
83+
"Referer" to "$mainUrl/",
84+
"User-Agent" to "Mozilla/5.0"
85+
)
86+
}
87+
)
88+
89+
return
90+
}
91+
} catch (_: Exception) {
92+
}
93+
}
94+
95+
val res = app.get(url, referer = referer).document
96+
val video = res.selectFirst("video source")?.attr("src") ?: return
97+
98+
callback(
99+
newExtractorLink(
100+
name,
101+
name,
102+
video,
103+
INFER_TYPE
104+
) {
105+
this.referer = "$mainUrl/"
106+
}
107+
)
108+
}
109+
}
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
package com.hexated
2+
3+
import com.fasterxml.jackson.annotation.JsonProperty
4+
import com.lagradost.cloudstream3.*
5+
import com.lagradost.cloudstream3.LoadResponse.Companion.addAniListId
6+
import com.lagradost.cloudstream3.LoadResponse.Companion.addMalId
7+
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
8+
import com.lagradost.cloudstream3.utils.*
9+
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
10+
import kotlinx.coroutines.runBlocking
11+
import org.jsoup.nodes.Element
12+
import org.jsoup.select.Elements
13+
14+
class Nimegami : MainAPI() {
15+
override var mainUrl = "https://nimegami.id"
16+
override var name = "Nimegami"
17+
override val hasMainPage = true
18+
override var lang = "id"
19+
override val supportedTypes = setOf(TvType.Anime, TvType.AnimeMovie, TvType.OVA)
20+
21+
companion object {
22+
fun getType(t: String): TvType {
23+
return when {
24+
t.contains("Tv", true) -> TvType.Anime
25+
t.contains("Movie", true) -> TvType.AnimeMovie
26+
t.contains("OVA", true) || t.contains("Special", true) -> TvType.OVA
27+
else -> TvType.Anime
28+
}
29+
}
30+
31+
fun getStatus(t: String?): ShowStatus {
32+
return if (t?.contains("On-Going", true) == true) ShowStatus.Ongoing
33+
else ShowStatus.Completed
34+
}
35+
}
36+
37+
override val mainPage = mainPageOf(
38+
"" to "Updated Anime",
39+
"/type/tv" to "Anime",
40+
"/type/movie" to "Movie",
41+
"/type/ona" to "ONA",
42+
"/type/ova" to "OVA",
43+
"/type/special" to "Special"
44+
)
45+
46+
override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse {
47+
val document = app.get("$mainUrl${request.data}/page/$page").document
48+
val home = document.select("div.post-article article, div.archive article").mapNotNull { it.toSearchResult() }
49+
return newHomePageResponse(
50+
list = HomePageList(
51+
name = request.name,
52+
list = home,
53+
isHorizontalImages = request.name != "Updated Anime"
54+
),
55+
hasNext = true
56+
)
57+
}
58+
59+
private fun Element.toSearchResult(): AnimeSearchResponse? {
60+
val href = fixUrl(this.selectFirst("a")!!.attr("href"))
61+
val title = this.selectFirst("h2 a")?.text() ?: return null
62+
val posterUrl = (this.selectFirst("noscript img") ?: this.selectFirst("img"))?.attr("src")
63+
val episode = this.selectFirst("ul li:contains(Episode), div.eps-archive")?.ownText()?.filter { it.isDigit() }?.toIntOrNull()
64+
65+
return newAnimeSearchResponse(title, href, TvType.Anime) {
66+
this.posterUrl = posterUrl
67+
addSub(episode)
68+
}
69+
}
70+
71+
override suspend fun search(query: String): List<SearchResponse> {
72+
val searchResponse = mutableListOf<SearchResponse>()
73+
for (i in 1..2) {
74+
val res = app.get("$mainUrl/page/$i/?s=$query&post_type=post").document.select("div.archive article").mapNotNull { it.toSearchResult() }
75+
searchResponse.addAll(res)
76+
}
77+
return searchResponse
78+
}
79+
80+
override suspend fun load(url: String): LoadResponse {
81+
val document = app.get(url).document
82+
val table = document.select("div#Info table tbody")
83+
val title = table.getContent("Judul :").text()
84+
val poster = document.selectFirst("div.coverthumbnail img")?.attr("src")
85+
val bgPoster = document.selectFirst("div.thumbnail-a img")?.attr("src")
86+
val tags = table.getContent("Kategori").select("a").map { it.text() }
87+
val year = table.getContent("Musim / Rilis").text().filter { it.isDigit() }.toIntOrNull()
88+
val status = getStatus(document.selectFirst("h1[itemprop=headline]")?.text())
89+
val type = getType(table.getContent("Type").text())
90+
val description = document.select("div#Sinopsis p").text().trim()
91+
val trailer = document.selectFirst("div#Trailer iframe")?.attr("src")
92+
93+
val episodes = document.select("div.list_eps_stream li").mapNotNull {
94+
val episode = Regex("Episode\\s?(\\d+)").find(it.text())?.groupValues?.getOrNull(1)?.toIntOrNull()
95+
val link = it.attr("data")
96+
newEpisode(url = link, initializer = { this.episode = episode }, fix = false)
97+
}
98+
99+
val recommendations = document.select("div#randomList > a").mapNotNull {
100+
val epHref = it.attr("href")
101+
val epTitle = it.select("h5.sidebar-title-h5.px-2.py-2").text()
102+
val epPoster = it.select(".product__sidebar__view__item.set-bg").attr("data-setbg")
103+
newAnimeSearchResponse(epTitle, epHref, TvType.Anime) {
104+
this.posterUrl = epPoster
105+
addDubStatus(dubExist = false, subExist = true)
106+
}
107+
}
108+
109+
val tracker = APIHolder.getTracker(listOf(title), TrackerType.getTypes(type), year, true)
110+
111+
return newAnimeLoadResponse(title, url, type) {
112+
engName = title
113+
posterUrl = tracker?.image ?: poster
114+
backgroundPosterUrl = tracker?.cover ?: bgPoster
115+
this.year = year
116+
addEpisodes(DubStatus.Subbed, episodes)
117+
showStatus = status
118+
plot = description
119+
this.tags = tags
120+
this.recommendations = recommendations
121+
addTrailer(trailer)
122+
addMalId(tracker?.malId)
123+
addAniListId(tracker?.aniId?.toIntOrNull())
124+
}
125+
}
126+
127+
override suspend fun loadLinks(data: String, isCasting: Boolean, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit): Boolean {
128+
tryParseJson<ArrayList<Sources>>(base64Decode(data))?.map { sources ->
129+
sources.url?.amap { url ->
130+
loadFixedExtractor(url, sources.format, "$mainUrl/", subtitleCallback, callback)
131+
}
132+
}
133+
return true
134+
}
135+
136+
private suspend fun loadFixedExtractor(
137+
url: String,
138+
quality: String?,
139+
referer: String? = null,
140+
subtitleCallback: (SubtitleFile) -> Unit,
141+
callback: (ExtractorLink) -> Unit
142+
) {
143+
loadExtractor(url, referer, subtitleCallback) { link ->
144+
runBlocking {
145+
callback.invoke(
146+
newExtractorLink(link.name, link.name, link.url, link.type) {
147+
this.referer = link.referer
148+
this.quality = getQualityFromName(quality)
149+
this.headers = link.headers
150+
this.extractorData = link.extractorData
151+
}
152+
)
153+
}
154+
}
155+
}
156+
157+
private fun Elements.getContent(css: String): Elements = this.select("tr:contains($css) td:last-child")
158+
159+
data class Sources(@JsonProperty("format") val format: String? = null, @JsonProperty("url") val url: ArrayList<String>? = arrayListOf())
160+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
2+
3+
package com.hexated
4+
5+
import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
6+
import com.lagradost.cloudstream3.plugins.Plugin
7+
import android.content.Context
8+
9+
@CloudstreamPlugin
10+
class NimegamiPlugin : Plugin() {
11+
override fun load(context: Context) {
12+
13+
registerMainAPI(Nimegami())
14+
registerExtractorAPI(DlganExtractor())
15+
registerExtractorAPI(BerkasDriveExtractor())
16+
}
17+
}

0 commit comments

Comments
 (0)