Skip to content

Commit b851709

Browse files
authored
Merge pull request #5 from aymanbest/master
Kinoger Fix by a legend
2 parents 8ac1cf4 + af2e114 commit b851709

File tree

2 files changed

+150
-67
lines changed

2 files changed

+150
-67
lines changed

Kinoger/src/main/kotlin/com/ne1work/Kinoger.kt

+149-67
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,54 @@
11
package com.hexated
22

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
718
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
1020
import com.lagradost.cloudstream3.utils.loadExtractor
21+
import com.lagradost.cloudstream3.utils.AppUtils
22+
import java.util.Base64
1123
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+
}
1233

1334
class Kinoger : MainAPI() {
14-
override var name = "Kinoger"
35+
override var name = "Kinoger"
1536
override var mainUrl = "https://kinoger.to"
1637
override var lang = "de"
1738
override val hasMainPage = true
1839
override val supportedTypes = setOf(TvType.TvSeries, TvType.Movie)
1940

2041
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",
3152
)
3253

3354
override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse {
@@ -46,6 +67,60 @@ class Kinoger : MainAPI() {
4667
}
4768
}
4869

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+
49124
private fun Element.toSearchResult(): SearchResponse? {
50125
val href = getProperLink(this.selectFirst("a")?.attr("href") ?: return null)
51126
val title = this.selectFirst("a")?.text() ?: this.selectFirst("img")?.attr("alt")
@@ -61,7 +136,7 @@ class Kinoger : MainAPI() {
61136

62137
override suspend fun search(query: String): List<SearchResponse> {
63138
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"
65140
).mapNotNull { it.toSearchResult() }
66141
}
67142

@@ -79,21 +154,25 @@ class Kinoger : MainAPI() {
79154
val scripts = document.select("script").mapNotNull { script ->
80155
val scriptContent = script.data()
81156
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
84162
}
85163

86164
val jsonData = scripts.flatMap { data ->
87165
val parsedData = AppUtils.tryParseJson<List<List<String>>>("[[$data]]")
88166
parsedData ?: emptyList()
89-
}
167+
}.filter { it.isNotEmpty() }
168+
println("Jsondata "+jsonData)
90169

91170
val type = if (document.select("script").any { it.data().contains("0.2") }) TvType.Movie else TvType.TvSeries
92171

93172
val episodes = jsonData.flatMapIndexed { season: Int, iframes: List<String> ->
94173
iframes.mapIndexed { episode, iframe ->
95174
Episode(
96-
iframe.trim(),
175+
jsonData.joinToString(","),
97176
season = season + 1,
98177
episode = episode + 1
99178
)
@@ -109,57 +188,60 @@ class Kinoger : MainAPI() {
109188
}
110189
}
111190

112-
113191
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
118196
): 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+
)
145224
)
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)
147241
}
148-
}
149-
}
150242

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")
157243
}
244+
return true
158245
}
159246

160247
}
161-
162-
class Kinogeru : Chillx() {
163-
override val name = "Kinoger"
164-
override val mainUrl = "https://kinoger.ru"
165-
}

build.gradle.kts

+1
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ subprojects {
7878
implementation("org.jsoup:jsoup:1.16.2") // html parser
7979
implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.16.0")
8080
implementation("com.fasterxml.jackson.core:jackson-databind:2.16.0")
81+
implementation("com.google.code.gson:gson:2.11.0") //Gsoon
8182
}
8283
}
8384

0 commit comments

Comments
 (0)