@@ -14,7 +14,8 @@ import org.jsoup.nodes.Element
1414import java.net.URI
1515
1616class KuramanimeProvider : MainAPI () {
17- override var mainUrl = " https://v8.kuramanime.tel"
17+ // Pastikan domain ini masih aktif, jika redirect, ganti ke domain baru
18+ override var mainUrl = " https://v8.kuramanime.tel"
1819 override var name = " Kuramanime"
1920 override val hasQuickSearch = false
2021 override val hasMainPage = true
@@ -174,29 +175,34 @@ class KuramanimeProvider : MainAPI() {
174175 headers = headers,
175176 cookies = cookies
176177 ).document
177- document.select(" video#player > source" ).map {
178- val link = fixUrl(it.attr(" src" ))
179- val quality = it.attr(" size" ).toIntOrNull()
180- callback.invoke(
181- newExtractorLink(
182- fixTitle(server),
183- fixTitle(server),
184- link,
185- INFER_TYPE
186- ) {
187- this .headers = mapOf (
188- " Accept" to " video/webm,video/ogg,video/*;q=0.9,application/ogg;q=0.7,audio/*;q=0.6,*/*;q=0.5" ,
189- " Range" to " bytes=0-" ,
190- " Sec-Fetch-Dest" to " video" ,
191- " Sec-Fetch-Mode" to " no-cors" ,
192- )
193- this .quality = quality ? : Qualities .Unknown .value
194- }
195- )
196- }
197- if (server == " kuramadrive" ) {
178+
179+ // Memperbaiki selector video agar lebih general
180+ val sources = document.select(" video source" )
181+ if (sources.isNotEmpty()) {
182+ sources.map {
183+ val link = fixUrl(it.attr(" src" ))
184+ val quality = it.attr(" size" ).toIntOrNull()
185+ callback.invoke(
186+ newExtractorLink(
187+ fixTitle(server),
188+ fixTitle(server),
189+ link,
190+ INFER_TYPE
191+ ) {
192+ this .headers = mapOf (
193+ " Accept" to " video/webm,video/ogg,video/*;q=0.9,application/ogg;q=0.7,audio/*;q=0.6,*/*;q=0.5" ,
194+ " Range" to " bytes=0-" ,
195+ " Sec-Fetch-Dest" to " video" ,
196+ " Sec-Fetch-Mode" to " no-cors" ,
197+ )
198+ this .quality = quality ? : Qualities .Unknown .value
199+ }
200+ )
201+ }
202+ } else {
203+ // Fallback jika video tag tidak langsung ditemukan (mungkin didalam script)
198204 document.select(" div#animeDownloadLink a" ).amap {
199- loadExtractor(it.attr(" href" ), " $mainUrl /" , subtitleCallback, callback)
205+ loadExtractor(it.attr(" href" ), " $mainUrl /" , subtitleCallback, callback)
200206 }
201207 }
202208 }
@@ -213,9 +219,14 @@ class KuramanimeProvider : MainAPI() {
213219 cookies = req.cookies
214220
215221 val token = res.selectFirst(" meta[name=csrf-token]" )?.attr(" content" ) ? : return false
216- val dataKps = res.selectFirst(" div.col-lg-12.mt-3 " )?.attr(" data-kk" ) ? : return false
222+ val dataKps = res.selectFirst(" div[data-kk] " )?.attr(" data-kk" ) ? : return false
217223
218- val assets = getAssets(dataKps)
224+ // Menggunakan try-catch saat mengambil assets agar tidak crash jika pattern berubah
225+ val assets = try {
226+ getAssets(dataKps)
227+ } catch (e: Exception ) {
228+ return false
229+ }
219230
220231 var headers = mapOf (
221232 " X-CSRF-TOKEN" to token,
@@ -225,11 +236,13 @@ class KuramanimeProvider : MainAPI() {
225236 " X-Requested-With" to " XMLHttpRequest" ,
226237 )
227238
228- val tokenKey = app.get(
239+ val tokenKeyResponse = app.get(
229240 " $mainUrl /${assets.MIX_PREFIX_AUTH_ROUTE_PARAM }${assets.MIX_AUTH_ROUTE_PARAM } " ,
230241 headers = headers,
231242 cookies = cookies
232- ).text
243+ )
244+
245+ val tokenKey = tokenKeyResponse.text
233246
234247 headers = mapOf (
235248 " Alt-Used" to URI (mainUrl).host,
@@ -239,38 +252,51 @@ class KuramanimeProvider : MainAPI() {
239252 )
240253
241254 res.select(" select#changeServer option" ).amap { source ->
242- val server = source.attr(" value" )
243- val link =
244- " $data ?${assets.MIX_PAGE_TOKEN_KEY } =$tokenKey &${assets.MIX_STREAM_SERVER_KEY } =$server "
245- if (server.contains(Regex (" (?i)kuramadrive|archive" ))) {
246- invokeLocalSource(link, server, headers, subtitleCallback, callback)
247- } else {
248- app.get(
249- link,
250- referer = data,
251- headers = headers,
252- cookies = cookies
253- ).document.select(" div.iframe-container iframe" ).attr(" src" ).let { videoUrl ->
254- loadExtractor(fixUrl(videoUrl), " $mainUrl /" , subtitleCallback, callback)
255+ try {
256+ val server = source.attr(" value" )
257+ val link = " $data ?${assets.MIX_PAGE_TOKEN_KEY } =$tokenKey &${assets.MIX_STREAM_SERVER_KEY } =$server "
258+
259+ if (server.contains(Regex (" (?i)kuramadrive|archive" ))) {
260+ invokeLocalSource(link, server, headers, subtitleCallback, callback)
261+ } else {
262+ val iframeDoc = app.get(
263+ link,
264+ referer = data,
265+ headers = headers,
266+ cookies = cookies
267+ ).document
268+
269+ // Selector iframe yang lebih kuat
270+ val videoUrl = iframeDoc.select(" iframe" ).attr(" src" )
271+
272+ if (videoUrl.isNotBlank()) {
273+ loadExtractor(fixUrl(videoUrl), " $mainUrl /" , subtitleCallback, callback)
274+ }
255275 }
276+ } catch (e: Exception ) {
277+ // Ignore error pada satu server, lanjut ke server lain
256278 }
257279 }
258280
259-
260281 return true
261282 }
262283
284+ // Fungsi getAssets yang diperbarui menggunakan Regex
285+ // Ini menangani kutip satu ('), kutip dua ("), dan variasi spasi
263286 private suspend fun getAssets (bpjs : String? ): Assets {
264287 val env = app.get(" $mainUrl /assets/js/$bpjs .js" ).text
265- val MIX_PREFIX_AUTH_ROUTE_PARAM =
266- env.substringAfter(" MIX_PREFIX_AUTH_ROUTE_PARAM: '" ).substringBefore(" '," )
267- val MIX_AUTH_ROUTE_PARAM =
268- env.substringAfter(" MIX_AUTH_ROUTE_PARAM: '" ).substringBefore(" '," )
269- val MIX_AUTH_KEY = env.substringAfter(" MIX_AUTH_KEY: '" ).substringBefore(" '," )
270- val MIX_AUTH_TOKEN = env.substringAfter(" MIX_AUTH_TOKEN: '" ).substringBefore(" '," )
271- val MIX_PAGE_TOKEN_KEY = env.substringAfter(" MIX_PAGE_TOKEN_KEY: '" ).substringBefore(" '," )
272- val MIX_STREAM_SERVER_KEY =
273- env.substringAfter(" MIX_STREAM_SERVER_KEY: '" ).substringBefore(" '," )
288+
289+ fun extractVar (name : String ): String {
290+ return Regex (""" $name \s*:\s*['"](.*?)['"]""" ).find(env)?.groupValues?.get(1 ) ? : " "
291+ }
292+
293+ val MIX_PREFIX_AUTH_ROUTE_PARAM = extractVar(" MIX_PREFIX_AUTH_ROUTE_PARAM" )
294+ val MIX_AUTH_ROUTE_PARAM = extractVar(" MIX_AUTH_ROUTE_PARAM" )
295+ val MIX_AUTH_KEY = extractVar(" MIX_AUTH_KEY" )
296+ val MIX_AUTH_TOKEN = extractVar(" MIX_AUTH_TOKEN" )
297+ val MIX_PAGE_TOKEN_KEY = extractVar(" MIX_PAGE_TOKEN_KEY" )
298+ val MIX_STREAM_SERVER_KEY = extractVar(" MIX_STREAM_SERVER_KEY" )
299+
274300 return Assets (
275301 MIX_PREFIX_AUTH_ROUTE_PARAM ,
276302 MIX_AUTH_ROUTE_PARAM ,
@@ -296,5 +322,4 @@ class KuramanimeProvider : MainAPI() {
296322 val MIX_PAGE_TOKEN_KEY : String? ,
297323 val MIX_STREAM_SERVER_KEY : String? ,
298324 )
299-
300- }
325+ }
0 commit comments