Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(en/fmovies): update vrf & vidsrc extractor #2789

Merged
merged 1 commit into from
Jan 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/en/fmovies/build.gradle
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
ext {
extName = 'FMovies'
extClass = '.FMovies'
extVersionCode = 15
extVersionCode = 16
}

apply from: "$rootDir/common.gradle"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ class FMovies : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
}

private val vrfHelper by lazy { FMoviesHelper(client, headers) }
private val utils by lazy { FmoviesUtils() }

// ============================== Popular ===============================

Expand Down Expand Up @@ -126,8 +126,7 @@ class FMovies : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
val id = client.newCall(GET(baseUrl + anime.url)).execute().asJsoup()
.selectFirst("div[data-id]")!!.attr("data-id")

val vrf = vrfHelper.getVrf(id)

val vrf = utils.vrfEncrypt(id)
val vrfHeaders = headers.newBuilder().apply {
add("Accept", "application/json, text/javascript, */*; q=0.01")
add("Host", baseUrl.toHttpUrl().host)
Expand Down Expand Up @@ -189,7 +188,7 @@ class FMovies : ConfigurableAnimeSource, ParsedAnimeHttpSource() {

override fun videoListRequest(episode: SEpisode): Request {
val data = json.decodeFromString<EpisodeInfo>(episode.url)
val vrf = vrfHelper.getVrf(data.id)
val vrf = utils.vrfEncrypt(data.id)

val vrfHeaders = headers.newBuilder()
.add("Accept", "application/json, text/javascript, */*; q=0.01")
Expand Down Expand Up @@ -217,7 +216,7 @@ class FMovies : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
if (!hosterSelection.contains(name)) return@parallelCatchingFlatMap emptyList()

// Get decrypted url
val vrf = vrfHelper.getVrf(server.attr("data-link-id"))
val vrf = utils.vrfEncrypt(server.attr("data-link-id"))

val vrfHeaders = headers.newBuilder()
.add("Accept", "application/json, text/javascript, */*; q=0.01")
Expand All @@ -229,8 +228,7 @@ class FMovies : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
GET("$baseUrl/ajax/server/${server.attr("data-link-id")}?vrf=$vrf", headers = vrfHeaders),
).await().parseAs<AjaxServerResponse>().result.url

val decrypted = vrfHelper.decrypt(encrypted)

val decrypted = utils.vrfDecrypt(encrypted)
when (name) {
"Vidplay", "MyCloud" -> vidsrcExtractor.videosFromUrl(decrypted, name)
"Filemoon" -> filemoonExtractor.videosFromUrl(decrypted, headers = headers)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,6 @@ package eu.kanade.tachiyomi.animeextension.en.fmovies

import kotlinx.serialization.Serializable

@Serializable
data class VrfResponse(
val url: String,
val vrfQuery: String? = null,
)

@Serializable
data class AjaxResponse(
val result: String,
Expand Down Expand Up @@ -36,21 +30,25 @@ data class FMoviesSubs(
)

@Serializable
data class RawResponse(
val rawURL: String,
)

@Serializable
data class VidsrcResponse(
val result: ResultObject,
data class MediaResponseBody(
val status: Int,
val result: Result,
) {
@Serializable
data class ResultObject(
val sources: List<SourceObject>,
data class Result(
val sources: ArrayList<Source>,
val tracks: ArrayList<SubTrack> = ArrayList(),
) {
@Serializable
data class SourceObject(
data class Source(
val file: String,
)

@Serializable
data class SubTrack(
val file: String,
val label: String = "",
val kind: String,
)
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package eu.kanade.tachiyomi.animeextension.en.fmovies

import android.util.Base64
import java.net.URLDecoder
import javax.crypto.Cipher
import javax.crypto.spec.SecretKeySpec

class FmoviesUtils {

fun vrfEncrypt(input: String): String {
val rc4Key = SecretKeySpec("FWsfu0KQd9vxYGNB".toByteArray(), "RC4")
val cipher = Cipher.getInstance("RC4")
cipher.init(Cipher.DECRYPT_MODE, rc4Key, cipher.parameters)

var vrf = cipher.doFinal(input.toByteArray())
vrf = Base64.encode(vrf, Base64.URL_SAFE or Base64.NO_WRAP)
vrf = rot13(vrf)
vrf = Base64.encode(vrf, Base64.URL_SAFE or Base64.NO_WRAP)
vrf = vrfShift(vrf)
val stringVrf = vrf.toString(Charsets.UTF_8)
return java.net.URLEncoder.encode(stringVrf, "utf-8")
}

fun vrfDecrypt(input: String): String {
var vrf = input.toByteArray()
vrf = Base64.decode(vrf, Base64.URL_SAFE)

val rc4Key = SecretKeySpec("8z5Ag5wgagfsOuhz".toByteArray(), "RC4")
val cipher = Cipher.getInstance("RC4")
cipher.init(Cipher.DECRYPT_MODE, rc4Key, cipher.parameters)
vrf = cipher.doFinal(vrf)

return URLDecoder.decode(vrf.toString(Charsets.UTF_8), "utf-8")
}

private fun rot13(vrf: ByteArray): ByteArray {
for (i in vrf.indices) {
val byte = vrf[i]
if (byte in 'A'.code..'Z'.code) {
vrf[i] = ((byte - 'A'.code + 13) % 26 + 'A'.code).toByte()
} else if (byte in 'a'.code..'z'.code) {
vrf[i] = ((byte - 'a'.code + 13) % 26 + 'a'.code).toByte()
}
}
return vrf
}

private fun vrfShift(vrf: ByteArray): ByteArray {
for (i in vrf.indices) {
val shift = arrayOf(-4, -2, -6, 5, -2)[i % 5]
vrf[i] = vrf[i].plus(shift).toByte()
}
return vrf
}
}
Loading