1
1
package com.hexated
2
2
3
- import com.lagradost.cloudstream3.*
4
- import com.lagradost.cloudstream3.extractors.Chillx
5
- import com.lagradost.cloudstream3.network.CloudflareKiller
6
- import com.lagradost.cloudstream3.utils.AppUtils
3
+ import com.google.gson.Gson
4
+ import com.lagradost.cloudstream3.Episode
5
+ import com.lagradost.cloudstream3.HomePageResponse
6
+ import com.lagradost.cloudstream3.LoadResponse
7
+ import com.lagradost.cloudstream3.MainAPI
8
+ import com.lagradost.cloudstream3.MainPageRequest
9
+ import com.lagradost.cloudstream3.SearchResponse
10
+ import com.lagradost.cloudstream3.SubtitleFile
11
+ import com.lagradost.cloudstream3.TvType
12
+ import com.lagradost.cloudstream3.app
13
+ import com.lagradost.cloudstream3.fixUrlNull
14
+ import com.lagradost.cloudstream3.mainPageOf
15
+ import com.lagradost.cloudstream3.newHomePageResponse
16
+ import com.lagradost.cloudstream3.newTvSeriesLoadResponse
17
+ import com.lagradost.cloudstream3.newTvSeriesSearchResponse
7
18
import com.lagradost.cloudstream3.utils.ExtractorLink
8
- import com.lagradost.cloudstream3.utils.ExtractorLinkType
9
- import com.lagradost.cloudstream3.utils.Qualities
19
+ import com.lagradost.cloudstream3.utils.getQualityFromName
10
20
import com.lagradost.cloudstream3.utils.loadExtractor
21
+ import com.lagradost.cloudstream3.utils.AppUtils
22
+ import java.util.Base64
11
23
import org.jsoup.nodes.Element
24
+ import java.security.MessageDigest
25
+ import javax.crypto.Cipher
26
+ import javax.crypto.spec.IvParameterSpec
27
+ import javax.crypto.spec.SecretKeySpec
28
+
29
+ class Kinogeru : Chillx () {
30
+ override val name = " Kinoger"
31
+ override val mainUrl = " https://kinoger.ru"
32
+ }
12
33
13
34
class Kinoger : MainAPI () {
14
- override var name = " Kinoger"
35
+ override var name = " Kinoger"
15
36
override var mainUrl = " https://kinoger.to"
16
37
override var lang = " de"
17
38
override val hasMainPage = true
18
39
override val supportedTypes = setOf (TvType .TvSeries , TvType .Movie )
19
40
20
41
override val mainPage = mainPageOf(
21
- " " to " Alle Filme" ,
22
- " stream/action" to " Action" ,
23
- " stream/fantasy" to " Fantasy" ,
24
- " stream/drama" to " Drama" ,
25
- " stream/mystery" to " Mystery" ,
26
- " stream/romance" to " Romance" ,
27
- " stream/animation" to " Animation" ,
28
- " stream/horror" to " Horror" ,
29
- " stream/familie" to " Familie" ,
30
- " stream/komdie" to " Komdie" ,
42
+ " " to " Alle Filme" ,
43
+ " stream/action" to " Action" ,
44
+ " stream/fantasy" to " Fantasy" ,
45
+ " stream/drama" to " Drama" ,
46
+ " stream/mystery" to " Mystery" ,
47
+ " stream/romance" to " Romance" ,
48
+ " stream/animation" to " Animation" ,
49
+ " stream/horror" to " Horror" ,
50
+ " stream/familie" to " Familie" ,
51
+ " stream/komdie" to " Komdie" ,
31
52
)
32
53
33
54
override suspend fun getMainPage (page : Int , request : MainPageRequest ): HomePageResponse {
@@ -46,6 +67,60 @@ class Kinoger : MainAPI() {
46
67
}
47
68
}
48
69
70
+ private fun Element.getImageAttr (): String? {
71
+ return when {
72
+ this .hasAttr(" data-src" ) -> this .attr(" data-src" )
73
+ this .hasAttr(" data-lazy-src" ) -> this .attr(" data-lazy-src" )
74
+ this .hasAttr(" srcset" ) -> this .attr(" srcset" ).substringBefore(" " )
75
+ else -> this .attr(" src" )
76
+ }
77
+ }
78
+
79
+ data class EncryptedData (
80
+ val s : String ,
81
+ val iv : String ,
82
+ val ct : String
83
+ )
84
+
85
+ fun contentDecryptor (htmlContent : String , passphrase : String ): String {
86
+ val encryptedData = Gson ().fromJson(htmlContent, EncryptedData ::class .java)
87
+ val salt = hexStringToByteArray(encryptedData.s)
88
+ val iv = hexStringToByteArray(encryptedData.iv)
89
+ val ct = Base64 .getDecoder().decode(encryptedData.ct)
90
+ val concatedPassphrase = passphrase.toByteArray(Charsets .UTF_8 ) + salt
91
+ val md5List = mutableListOf<ByteArray >()
92
+ md5List.add(md5(concatedPassphrase))
93
+ var result = md5List[0 ]
94
+ var i = 1
95
+ while (result.size < 32 ) {
96
+ md5List.add(md5(md5List[i - 1 ] + concatedPassphrase))
97
+ result + = md5List[i]
98
+ i++
99
+ }
100
+
101
+ val key = result.sliceArray(0 until 32 )
102
+ val cipher = Cipher .getInstance(" AES/CBC/PKCS5Padding" )
103
+ val secretKey = SecretKeySpec (key, " AES" )
104
+ cipher.init (Cipher .DECRYPT_MODE , secretKey, IvParameterSpec (iv))
105
+ val decrypted = cipher.doFinal(ct)
106
+
107
+ return String (decrypted, Charsets .UTF_8 )
108
+ }
109
+
110
+ private fun md5 (input : ByteArray ): ByteArray {
111
+ val md = MessageDigest .getInstance(" MD5" )
112
+ return md.digest(input)
113
+ }
114
+
115
+ private fun hexStringToByteArray (hexString : String ): ByteArray {
116
+ val len = hexString.length
117
+ val data = ByteArray (len / 2 )
118
+ for (i in 0 until len step 2 ) {
119
+ data[i / 2 ] = ((hexString[i].toString().toInt(16 ) shl 4 ) + hexString[i + 1 ].toString().toInt(16 )).toByte()
120
+ }
121
+ return data
122
+ }
123
+
49
124
private fun Element.toSearchResult (): SearchResponse ? {
50
125
val href = getProperLink(this .selectFirst(" a" )?.attr(" href" ) ? : return null )
51
126
val title = this .selectFirst(" a" )?.text() ? : this .selectFirst(" img" )?.attr(" alt" )
@@ -61,7 +136,7 @@ class Kinoger : MainAPI() {
61
136
62
137
override suspend fun search (query : String ): List <SearchResponse > {
63
138
return app.get(" $mainUrl /?do=search&subaction=search&titleonly=3&story=$query &x=0&y=0&submit=submit" ).document.select(
64
- " div#dle-content div.titlecontrol"
139
+ " div#dle-content div.titlecontrol"
65
140
).mapNotNull { it.toSearchResult() }
66
141
}
67
142
@@ -79,21 +154,25 @@ class Kinoger : MainAPI() {
79
154
val scripts = document.select(" script" ).mapNotNull { script ->
80
155
val scriptContent = script.data()
81
156
val showPattern = Regex (""" show\s*\(\s*\d+\s*,\s*\[\[(.*?)\]\],\s*0\.2""" )
82
- val match = showPattern.find(scriptContent)
83
- match?.groupValues?.get(1 )?.replace(" '" , " \" " )
157
+ val extractedData = showPattern.findAll(scriptContent)
158
+ .map { it.groupValues[1 ].replace(" '" , " \" " ) }
159
+ .joinToString(" ," )
160
+ println (" Extracted Data: $extractedData " ) // Print extracted data
161
+ extractedData
84
162
}
85
163
86
164
val jsonData = scripts.flatMap { data ->
87
165
val parsedData = AppUtils .tryParseJson<List <List <String >>>(" [[$data ]]" )
88
166
parsedData ? : emptyList()
89
- }
167
+ }.filter { it.isNotEmpty() }
168
+ println (" Jsondata " + jsonData)
90
169
91
170
val type = if (document.select(" script" ).any { it.data().contains(" 0.2" ) }) TvType .Movie else TvType .TvSeries
92
171
93
172
val episodes = jsonData.flatMapIndexed { season: Int , iframes: List <String > ->
94
173
iframes.mapIndexed { episode, iframe ->
95
174
Episode (
96
- iframe.trim( ),
175
+ jsonData.joinToString( " , " ),
97
176
season = season + 1 ,
98
177
episode = episode + 1
99
178
)
@@ -109,57 +188,60 @@ class Kinoger : MainAPI() {
109
188
}
110
189
}
111
190
112
-
113
191
override suspend fun loadLinks (
114
- data : String ,
115
- isCasting : Boolean ,
116
- subtitleCallback : (SubtitleFile ) -> Unit ,
117
- callback : (ExtractorLink ) -> Unit
192
+ data : String ,
193
+ isCasting : Boolean ,
194
+ subtitleCallback : (SubtitleFile ) -> Unit ,
195
+ callback : (ExtractorLink ) -> Unit
118
196
): Boolean {
119
- loadCustomExtractor(data, " $mainUrl /" , subtitleCallback, callback)
120
- return true
121
- }
122
-
123
- private suspend fun loadCustomExtractor (
124
- url : String ,
125
- referer : String? = null,
126
- subtitleCallback : (SubtitleFile ) -> Unit ,
127
- callback : (ExtractorLink ) -> Unit ,
128
- quality : Int? = null,
129
- ) {
130
- loadExtractor(url, referer, subtitleCallback) { link ->
131
- if (link.quality == Qualities .Unknown .value) {
132
- callback.invoke(
133
- ExtractorLink (
134
- link.source,
135
- link.name,
136
- link.url,
137
- link.referer,
138
- when (link.type) {
139
- ExtractorLinkType .M3U8 -> link.quality
140
- else -> quality ? : link.quality
141
- },
142
- link.type,
143
- link.headers,
144
- link.extractorData
197
+ val regexContent = Regex (" const Contents = '(.*)';" )
198
+ val regexFileLink = Regex (" sources:\\ s*\\ [\\ s*\\ {[^}]*\" file\"\\ s*:\\ s*\" ([^\" ]+)\" " )
199
+ val regexSubtitles = Regex (" tracks:\\ s*\\ [\\ s*\\ {(?:[^}]*\" file\"\\ s*:\\ s*\" ([^\" ]+)\" (?:[^}]*\" label\"\\ s*:\\ s*\" ([^\" ]*)\" )?)?[^}]*\\ }" )
200
+ val links = data.replace(" [" , " " ).replace(" ]" , " " )
201
+ .split(" ," )
202
+ .map { it.trim() }
203
+ links.forEach { link ->
204
+ if (link.contains(" kinoger" )) {
205
+ val doc = app.get(link, referer = mainUrl).text
206
+ val matchContent = regexContent.find(doc)
207
+ if (matchContent != null ) {
208
+ val content = matchContent.groupValues[1 ]
209
+ val decryptedContent = contentDecryptor(content, " 1FHuaQhhcsKgpTRB" ).replace(" \\ " , " " )
210
+
211
+
212
+ val matchFileLink = regexFileLink.findAll(decryptedContent)
213
+ matchFileLink.forEach { matchResult ->
214
+ val fileLink = matchResult.groupValues[1 ]
215
+ callback.invoke(
216
+ ExtractorLink (
217
+ " kinoger" ,
218
+ " kinoger" ,
219
+ fileLink,
220
+ link,
221
+ quality = getQualityFromName(name),
222
+ isM3u8 = fileLink.contains(" .m3u8" )
223
+ )
145
224
)
146
- )
225
+ }
226
+
227
+ val matchSubtitles = regexSubtitles.findAll(decryptedContent)
228
+ matchSubtitles.forEach { matchResult ->
229
+ val subtitleUrl = matchResult.groupValues[1 ]
230
+ val subtitleLabel = matchResult.groupValues[2 ]
231
+ subtitleCallback.invoke(
232
+ SubtitleFile (
233
+ subtitleLabel ? : " Unknown" ,
234
+ url = subtitleUrl
235
+ )
236
+ )
237
+ }
238
+ }
239
+ } else {
240
+ loadExtractor(link, mainUrl, subtitleCallback, callback)
147
241
}
148
- }
149
- }
150
242
151
- private fun Element.getImageAttr (): String? {
152
- return when {
153
- this .hasAttr(" data-src" ) -> this .attr(" data-src" )
154
- this .hasAttr(" data-lazy-src" ) -> this .attr(" data-lazy-src" )
155
- this .hasAttr(" srcset" ) -> this .attr(" srcset" ).substringBefore(" " )
156
- else -> this .attr(" src" )
157
243
}
244
+ return true
158
245
}
159
246
160
247
}
161
-
162
- class Kinogeru : Chillx () {
163
- override val name = " Kinoger"
164
- override val mainUrl = " https://kinoger.ru"
165
- }
0 commit comments