diff --git a/lib/vidsrc-extractor/src/main/java/eu/kanade/tachiyomi/lib/vidsrcextractor/VidSrcExtractor.kt b/lib/vidsrc-extractor/src/main/java/eu/kanade/tachiyomi/lib/vidsrcextractor/VidSrcExtractor.kt
index aecda1f6..c6cf9db4 100644
--- a/lib/vidsrc-extractor/src/main/java/eu/kanade/tachiyomi/lib/vidsrcextractor/VidSrcExtractor.kt
+++ b/lib/vidsrc-extractor/src/main/java/eu/kanade/tachiyomi/lib/vidsrcextractor/VidSrcExtractor.kt
@@ -1,18 +1,19 @@
 package eu.kanade.tachiyomi.lib.vidsrcextractor
 
 import android.util.Base64
-import app.cash.quickjs.QuickJs
 import eu.kanade.tachiyomi.animesource.model.Track
 import eu.kanade.tachiyomi.animesource.model.Video
 import eu.kanade.tachiyomi.lib.playlistutils.PlaylistUtils
+import eu.kanade.tachiyomi.lib.vidsrcextractor.MediaResponseBody.Result
 import eu.kanade.tachiyomi.network.GET
 import eu.kanade.tachiyomi.util.parseAs
 import kotlinx.serialization.ExperimentalSerializationApi
 import kotlinx.serialization.Serializable
-import okhttp3.CacheControl
+import kotlinx.serialization.json.Json
 import okhttp3.Headers
 import okhttp3.HttpUrl.Companion.toHttpUrl
 import okhttp3.OkHttpClient
+import uy.kohesive.injekt.injectLazy
 import java.net.URLDecoder
 import javax.crypto.Cipher
 import javax.crypto.spec.SecretKeySpec
@@ -21,54 +22,32 @@ import javax.crypto.spec.SecretKeySpec
 class VidsrcExtractor(private val client: OkHttpClient, private val headers: Headers) {
 
     private val playlistUtils by lazy { PlaylistUtils(client, headers) }
+    private val json: Json by injectLazy()
 
-    private val cacheControl = CacheControl.Builder().noStore().build()
-    private val noCacheClient = client.newBuilder()
-        .cache(null)
-        .build()
-
-    private val keys by lazy {
-        noCacheClient.newCall(
-            GET("https://raw.githubusercontent.com/KillerDogeEmpire/vidplay-keys/keys/keys.json", cache = cacheControl),
-        ).execute().parseAs<List<String>>()
-    }
-
-    fun videosFromUrl(embedLink: String, hosterName: String, type: String = "", subtitleList: List<Track> = emptyList()): List<Video> {
+    fun videosFromUrl(
+        embedLink: String,
+        hosterName: String,
+        type: String = "",
+        subtitleList: List<Track> = emptyList(),
+    ): List<Video> {
         val host = embedLink.toHttpUrl().host
-        val apiUrl = getApiUrl(embedLink, keys)
+        val apiUrl = getApiUrl(embedLink)
 
-        val apiHeaders = headers.newBuilder().apply {
-            add("Accept", "application/json, text/javascript, */*; q=0.01")
-            add("Host", host)
-            add("Referer", URLDecoder.decode(embedLink, "UTF-8"))
-            add("X-Requested-With", "XMLHttpRequest")
-        }.build()
+        val response = client.newCall(GET(apiUrl)).execute()
+        val data = response.parseAs<MediaResponseBody>()
 
-        val response = client.newCall(
-            GET(apiUrl, apiHeaders),
-        ).execute()
-
-        val data = runCatching {
-            response.parseAs<MediaResponseBody>()
-        }.getOrElse { // Keys are out of date
-            val newKeys = noCacheClient.newCall(
-                GET("https://raw.githubusercontent.com/KillerDogeEmpire/vidplay-keys/keys/keys.json", cache = cacheControl),
-            ).execute().parseAs<List<String>>()
-            val newApiUrL = getApiUrl(embedLink, newKeys)
-            client.newCall(
-                GET(newApiUrL, apiHeaders),
-            ).execute().parseAs()
-        }
+        val decrypted = vrfDecrypt(data.result)
+        val result = json.decodeFromString<Result>(decrypted)
 
         return playlistUtils.extractFromHls(
-            data.result.sources.first().file,
+            playlistUrl = result.sources.first().file,
             referer = "https://$host/",
             videoNameGen = { q -> hosterName + (if (type.isBlank()) "" else " - $type") + " - $q" },
-            subtitleList = subtitleList + data.result.tracks.toTracks(),
+            subtitleList = subtitleList + result.tracks.toTracks(),
         )
     }
 
-    private fun getApiUrl(embedLink: String, keyList: List<String>): String {
+    private fun getApiUrl(embedLink: String): String {
         val host = embedLink.toHttpUrl().host
         val params = embedLink.toHttpUrl().let { url ->
             url.queryParameterNames.map {
@@ -76,13 +55,13 @@ class VidsrcExtractor(private val client: OkHttpClient, private val headers: Hea
             }
         }
         val vidId = embedLink.substringAfterLast("/").substringBefore("?")
-        val encodedID = encodeID(vidId, keyList)
-        val apiSlug = callFromFuToken(host, encodedID, embedLink)
+        val apiSlug = encodeID(vidId, ENCRYPTION_KEY1)
+        val h = encodeID(vidId, ENCRYPTION_KEY2)
 
         return buildString {
             append("https://")
             append(host)
-            append("/")
+            append("/mediainfo/")
             append(apiSlug)
             if (params.isNotEmpty()) {
                 append("?")
@@ -91,51 +70,23 @@ class VidsrcExtractor(private val client: OkHttpClient, private val headers: Hea
                         "${it.first}=${it.second}"
                     },
                 )
+                append("&h=$h")
             }
         }
     }
 
-    private fun encodeID(videoID: String, keyList: List<String>): String {
-        val rc4Key1 = SecretKeySpec(keyList[0].toByteArray(), "RC4")
-        val rc4Key2 = SecretKeySpec(keyList[1].toByteArray(), "RC4")
-        val cipher1 = Cipher.getInstance("RC4")
-        val cipher2 = Cipher.getInstance("RC4")
-        cipher1.init(Cipher.DECRYPT_MODE, rc4Key1, cipher1.parameters)
-        cipher2.init(Cipher.DECRYPT_MODE, rc4Key2, cipher2.parameters)
-        var encoded = videoID.toByteArray()
-
-        encoded = cipher1.doFinal(encoded)
-        encoded = cipher2.doFinal(encoded)
-        encoded = Base64.encode(encoded, Base64.DEFAULT)
-        return encoded.toString(Charsets.UTF_8).replace("/", "_").trim()
+    private fun encodeID(videoID: String, key: String): String {
+        val rc4Key = SecretKeySpec(key.toByteArray(), "RC4")
+        val cipher = Cipher.getInstance("RC4")
+        cipher.init(Cipher.DECRYPT_MODE, rc4Key, cipher.parameters)
+        return Base64.encode(cipher.doFinal(videoID.toByteArray()), Base64.DEFAULT)
+            .toString(Charsets.UTF_8)
+            .replace("+", "-")
+            .replace("/", "_")
+            .trim()
     }
 
-    private fun callFromFuToken(host: String, data: String, embedLink: String): String {
-        val refererHeaders = headers.newBuilder().apply {
-            add("Referer", embedLink)
-        }.build()
-
-        val fuTokenScript = client.newCall(
-            GET("https://$host/futoken", headers = refererHeaders),
-        ).execute().body.string()
-
-        val js = buildString {
-            append("(function")
-            append(
-                fuTokenScript.substringAfter("window")
-                    .substringAfter("function")
-                    .replace("jQuery.ajax(", "")
-                    .substringBefore("+location.search"),
-            )
-            append("}(\"$data\"))")
-        }
-
-        return QuickJs.create().use {
-            it.evaluate(js)?.toString()!!
-        }
-    }
-
-    private fun List<MediaResponseBody.Result.SubTrack>.toTracks(): List<Track> {
+    private fun List<Result.SubTrack>.toTracks(): List<Track> {
         return filter {
             it.kind == "captions"
         }.mapNotNull {
@@ -147,17 +98,32 @@ class VidsrcExtractor(private val client: OkHttpClient, private val headers: Hea
             }.getOrNull()
         }
     }
+
+    private fun vrfDecrypt(input: String): String {
+        var vrf = Base64.decode(input.toByteArray(), Base64.URL_SAFE)
+        val rc4Key = SecretKeySpec(DECRYPTION_KEY.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")
+    }
+
+    companion object {
+        private const val ENCRYPTION_KEY1 = "8Qy3mlM2kod80XIK"
+        private const val ENCRYPTION_KEY2 = "BgKVSrzpH2Enosgm"
+        private const val DECRYPTION_KEY = "9jXDYBZUcTcTZveM"
+    }
 }
 
 @Serializable
 data class MediaResponseBody(
     val status: Int,
-    val result: Result,
+    val result: String,
 ) {
     @Serializable
     data class Result(
-        val sources: ArrayList<Source>,
-        val tracks: ArrayList<SubTrack> = ArrayList(),
+        val sources: List<Source>,
+        val tracks: List<SubTrack> = emptyList(),
     ) {
         @Serializable
         data class Source(