diff --git a/src/es/animefenix/build.gradle b/src/es/animefenix/build.gradle
index e444d95c4d..4754a67097 100644
--- a/src/es/animefenix/build.gradle
+++ b/src/es/animefenix/build.gradle
@@ -21,4 +21,5 @@ dependencies {
     implementation(project(':lib:dood-extractor'))
     implementation(project(':lib:upstream-extractor'))
     implementation(project(':lib:streamhidevid-extractor'))
+    implementation(project(':lib:universal-extractor'))
 }
diff --git a/src/es/animefenix/src/eu/kanade/tachiyomi/animeextension/es/animefenix/Animefenix.kt b/src/es/animefenix/src/eu/kanade/tachiyomi/animeextension/es/animefenix/Animefenix.kt
index 981eecf749..8b8679ee3e 100644
--- a/src/es/animefenix/src/eu/kanade/tachiyomi/animeextension/es/animefenix/Animefenix.kt
+++ b/src/es/animefenix/src/eu/kanade/tachiyomi/animeextension/es/animefenix/Animefenix.kt
@@ -21,6 +21,7 @@ import eu.kanade.tachiyomi.lib.streamhidevidextractor.StreamHideVidExtractor
 import eu.kanade.tachiyomi.lib.streamlareextractor.StreamlareExtractor
 import eu.kanade.tachiyomi.lib.streamtapeextractor.StreamTapeExtractor
 import eu.kanade.tachiyomi.lib.streamwishextractor.StreamWishExtractor
+import eu.kanade.tachiyomi.lib.universalextractor.UniversalExtractor
 import eu.kanade.tachiyomi.lib.upstreamextractor.UpstreamExtractor
 import eu.kanade.tachiyomi.lib.uqloadextractor.UqloadExtractor
 import eu.kanade.tachiyomi.lib.voeextractor.VoeExtractor
@@ -205,6 +206,10 @@ class Animefenix : ConfigurableAnimeSource, AnimeHttpSource() {
                 StreamWishExtractor(client, headers).videosFromUrl(url, videoNameGen = { "FileLions:$it" }).also(videoList::addAll)
             }
         } catch (_: Exception) { }
+
+        if (videoList.isEmpty()) {
+            UniversalExtractor(client).videosFromUrl(url, headers).let { videoList.addAll(it) }
+        }
         return videoList
     }
 
diff --git a/src/es/animeid/build.gradle b/src/es/animeid/build.gradle
index 18ca138c58..a6f89e468c 100644
--- a/src/es/animeid/build.gradle
+++ b/src/es/animeid/build.gradle
@@ -1,7 +1,7 @@
 ext {
     extName = 'AnimeID'
     extClass = '.AnimeID'
-    extVersionCode = 11
+    extVersionCode = 12
 }
 
 apply from: "$rootDir/common.gradle"
@@ -9,4 +9,5 @@ apply from: "$rootDir/common.gradle"
 dependencies {
     implementation(project(':lib:streamtape-extractor'))
     implementation(project(':lib:streamwish-extractor'))
+    implementation(project(':lib:universal-extractor'))
 }
diff --git a/src/es/animeid/src/eu/kanade/tachiyomi/animeextension/es/animeid/AnimeID.kt b/src/es/animeid/src/eu/kanade/tachiyomi/animeextension/es/animeid/AnimeID.kt
index 13be7d7394..ea4a9080e0 100644
--- a/src/es/animeid/src/eu/kanade/tachiyomi/animeextension/es/animeid/AnimeID.kt
+++ b/src/es/animeid/src/eu/kanade/tachiyomi/animeextension/es/animeid/AnimeID.kt
@@ -13,6 +13,7 @@ import eu.kanade.tachiyomi.animesource.model.Video
 import eu.kanade.tachiyomi.animesource.online.ParsedAnimeHttpSource
 import eu.kanade.tachiyomi.lib.streamtapeextractor.StreamTapeExtractor
 import eu.kanade.tachiyomi.lib.streamwishextractor.StreamWishExtractor
+import eu.kanade.tachiyomi.lib.universalextractor.UniversalExtractor
 import eu.kanade.tachiyomi.network.GET
 import eu.kanade.tachiyomi.util.asJsoup
 import kotlinx.serialization.json.Json
@@ -120,6 +121,7 @@ class AnimeID : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
     // ============================ Video Links =============================
     private val streamwishExtractor by lazy { StreamWishExtractor(client, headers) }
     private val streamtapeExtractor by lazy { StreamTapeExtractor(client) }
+    private val universalExtractor by lazy { UniversalExtractor(client) }
 
     override fun videoListParse(response: Response): List<Video> {
         val document = response.asJsoup()
@@ -128,11 +130,10 @@ class AnimeID : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
             val jsonString = script.attr("data")
             val jsonUnescape = unescapeJava(jsonString)!!.replace("\\", "")
             val url = fetchUrls(jsonUnescape).firstOrNull()?.replace("\\\\", "\\") ?: ""
-            if (url.contains("streamtape") || url.contains("tape") || url.contains("stp")) {
-                streamtapeExtractor.videosFromUrl(url).also(videoList::addAll)
-            }
-            if (url.contains("wish") || url.contains("fviplions") || url.contains("obeywish")) {
-                streamwishExtractor.videosFromUrl(url, videoNameGen = { "StreamWish:$it" }).also(videoList::addAll)
+            return when {
+                url.contains("streamtape") || url.contains("tape") || url.contains("stp") -> streamtapeExtractor.videosFromUrl(url)
+                url.contains("wish") || url.contains("fviplions") || url.contains("obeywish") -> streamwishExtractor.videosFromUrl(url, videoNameGen = { "StreamWish:$it" })
+                else -> universalExtractor.videosFromUrl(url, headers)
             }
         }
         return videoList
diff --git a/src/es/animemovil/build.gradle b/src/es/animemovil/build.gradle
index 4d13fcc8dd..ea7317f9af 100644
--- a/src/es/animemovil/build.gradle
+++ b/src/es/animemovil/build.gradle
@@ -1,7 +1,7 @@
 ext {
     extName = 'AnimeMovil'
     extClass = '.AnimeMovil'
-    extVersionCode = 23
+    extVersionCode = 24
 }
 
 apply from: "$rootDir/common.gradle"
@@ -20,4 +20,5 @@ dependencies {
     implementation(project(':lib:streamtape-extractor'))
     implementation(project(':lib:playlist-utils'))
     implementation(project(':lib:streamlare-extractor'))
+    implementation(project(':lib:universal-extractor'))
 }
\ No newline at end of file
diff --git a/src/es/animemovil/src/eu/kanade/tachiyomi/animeextension/es/animemovil/AnimeMovil.kt b/src/es/animemovil/src/eu/kanade/tachiyomi/animeextension/es/animemovil/AnimeMovil.kt
index f049fc5f68..daddba4bf9 100644
--- a/src/es/animemovil/src/eu/kanade/tachiyomi/animeextension/es/animemovil/AnimeMovil.kt
+++ b/src/es/animemovil/src/eu/kanade/tachiyomi/animeextension/es/animemovil/AnimeMovil.kt
@@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.animeextension.es.animemovil
 
 import android.app.Application
 import android.content.SharedPreferences
+import android.util.Log
 import androidx.preference.ListPreference
 import androidx.preference.PreferenceScreen
 import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
@@ -20,6 +21,7 @@ import eu.kanade.tachiyomi.lib.mp4uploadextractor.Mp4uploadExtractor
 import eu.kanade.tachiyomi.lib.streamlareextractor.StreamlareExtractor
 import eu.kanade.tachiyomi.lib.streamtapeextractor.StreamTapeExtractor
 import eu.kanade.tachiyomi.lib.streamwishextractor.StreamWishExtractor
+import eu.kanade.tachiyomi.lib.universalextractor.UniversalExtractor
 import eu.kanade.tachiyomi.lib.upstreamextractor.UpstreamExtractor
 import eu.kanade.tachiyomi.lib.uqloadextractor.UqloadExtractor
 import eu.kanade.tachiyomi.lib.voeextractor.VoeExtractor
@@ -233,50 +235,57 @@ class AnimeMovil : ConfigurableAnimeSource, AnimeHttpSource() {
         val videoList = mutableListOf<Video>()
         val embedUrl = url.lowercase()
         try {
-            if (embedUrl.contains("voe")) {
-                VoeExtractor(client).videosFromUrl(url).also(videoList::addAll)
-            }
-            if (embedUrl.contains("filemoon") || embedUrl.contains("moonplayer")) {
-                FilemoonExtractor(client).videosFromUrl(url, prefix = "Filemoon:").also(videoList::addAll)
-            }
-            if (embedUrl.contains("uqload")) {
-                UqloadExtractor(client).videosFromUrl(url).also(videoList::addAll)
-            }
-            if (embedUrl.contains("mp4upload")) {
-                val newHeaders = headers.newBuilder().add("referer", "https://re.animepelix.net/").build()
-                Mp4uploadExtractor(client).videosFromUrl(url, newHeaders).also(videoList::addAll)
-            }
-            if (embedUrl.contains("wishembed") || embedUrl.contains("streamwish") || embedUrl.contains("wish")) {
-                val docHeaders = headers.newBuilder()
-                    .add("Referer", "$baseUrl/")
-                    .build()
-                StreamWishExtractor(client, docHeaders).videosFromUrl(url, videoNameGen = { "StreamWish:$it" }).also(videoList::addAll)
-            }
-            if (embedUrl.contains("doodstream") || embedUrl.contains("dood.")) {
-                DoodExtractor(client).videoFromUrl(url, "DoodStream")?.let { videoList.add(it) }
-            }
-            if (embedUrl.contains("streamlare")) {
-                StreamlareExtractor(client).videosFromUrl(url).also(videoList::addAll)
-            }
-            if (embedUrl.contains("yourupload")) {
-                YourUploadExtractor(client).videoFromUrl(url, headers = headers).also(videoList::addAll)
-            }
-            if (embedUrl.contains("burstcloud") || embedUrl.contains("burst")) {
-                BurstCloudExtractor(client).videoFromUrl(url, headers = headers).also(videoList::addAll)
-            }
-            if (embedUrl.contains("fastream")) {
-                FastreamExtractor(client, headers).videosFromUrl(url).also(videoList::addAll)
-            }
-            if (embedUrl.contains("upstream")) {
-                UpstreamExtractor(client).videosFromUrl(url).also(videoList::addAll)
-            }
-            if (embedUrl.contains("streamtape")) {
-                StreamTapeExtractor(client).videoFromUrl(url)?.also(videoList::add)
-            }
-            if (embedUrl.contains("filelions") || embedUrl.contains("lion")) {
-                StreamWishExtractor(client, headers).videosFromUrl(url, videoNameGen = { "FileLions:$it" }).also(videoList::addAll)
+            return when {
+                embedUrl.contains("voe") -> {
+                    VoeExtractor(client).videosFromUrl(url).also(videoList::addAll)
+                }
+                embedUrl.contains("filemoon") || embedUrl.contains("moonplayer") -> {
+                    FilemoonExtractor(client).videosFromUrl(url, prefix = "Filemoon:").also(videoList::addAll)
+                }
+                embedUrl.contains("uqload") -> {
+                    UqloadExtractor(client).videosFromUrl(url).also(videoList::addAll)
+                }
+                embedUrl.contains("mp4upload") -> {
+                    val newHeaders = headers.newBuilder().add("referer", "https://re.animepelix.net/").build()
+                    Mp4uploadExtractor(client).videosFromUrl(url, newHeaders).also(videoList::addAll)
+                }
+                embedUrl.contains("wishembed") || embedUrl.contains("streamwish") || embedUrl.contains("wish") -> {
+                    val docHeaders = headers.newBuilder()
+                        .add("Referer", "$baseUrl/")
+                        .build()
+                    StreamWishExtractor(client, docHeaders).videosFromUrl(url, videoNameGen = { "StreamWish:$it" }).also(videoList::addAll)
+                }
+                embedUrl.contains("doodstream") || embedUrl.contains("dood.") -> {
+                    DoodExtractor(client).videosFromUrl(url, "DoodStream").also(videoList::addAll)
+                }
+                embedUrl.contains("streamlare") -> {
+                    StreamlareExtractor(client).videosFromUrl(url).also(videoList::addAll)
+                }
+                embedUrl.contains("yourupload") -> {
+                    YourUploadExtractor(client).videoFromUrl(url, headers = headers).also(videoList::addAll)
+                }
+                embedUrl.contains("burstcloud") || embedUrl.contains("burst") -> {
+                    BurstCloudExtractor(client).videoFromUrl(url, headers = headers).also(videoList::addAll)
+                }
+                embedUrl.contains("fastream") -> {
+                    FastreamExtractor(client, headers).videosFromUrl(url).also(videoList::addAll)
+                }
+                embedUrl.contains("upstream") -> {
+                    UpstreamExtractor(client).videosFromUrl(url).also(videoList::addAll)
+                }
+                embedUrl.contains("streamtape") -> {
+                    StreamTapeExtractor(client).videosFromUrl(url).also(videoList::addAll)
+                }
+                embedUrl.contains("filelions") || embedUrl.contains("lion") -> {
+                    StreamWishExtractor(client, headers).videosFromUrl(url, videoNameGen = { "FileLions:$it" }).also(videoList::addAll)
+                }
+                else -> {
+                    UniversalExtractor(client).videosFromUrl(url, headers).also(videoList::addAll)
+                }
             }
-        } catch (_: Exception) {}
+        } catch (_: Exception) {
+            Log.e("AnimeMovil", "Error: Server not supported")
+        }
         return videoList
     }
 
diff --git a/src/es/animenix/build.gradle b/src/es/animenix/build.gradle
index a2faacaae5..f4594e4112 100644
--- a/src/es/animenix/build.gradle
+++ b/src/es/animenix/build.gradle
@@ -3,7 +3,7 @@ ext {
     extClass = '.Animenix'
     themePkg = 'dooplay'
     baseUrl = 'https://animenix.com'
-    overrideVersionCode = 4
+    overrideVersionCode = 5
 }
 
 apply from: "$rootDir/common.gradle"
@@ -11,4 +11,5 @@ apply from: "$rootDir/common.gradle"
 dependencies {
     implementation(project(":lib:filemoon-extractor"))
     implementation(project(":lib:streamwish-extractor"))
+    implementation(project(":lib:universal-extractor"))
 }
\ No newline at end of file
diff --git a/src/es/animenix/src/eu/kanade/tachiyomi/animeextension/es/animenix/Animenix.kt b/src/es/animenix/src/eu/kanade/tachiyomi/animeextension/es/animenix/Animenix.kt
index 03ec305c4b..02f9bf3ddd 100644
--- a/src/es/animenix/src/eu/kanade/tachiyomi/animeextension/es/animenix/Animenix.kt
+++ b/src/es/animenix/src/eu/kanade/tachiyomi/animeextension/es/animenix/Animenix.kt
@@ -7,6 +7,7 @@ import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
 import eu.kanade.tachiyomi.animesource.model.Video
 import eu.kanade.tachiyomi.lib.filemoonextractor.FilemoonExtractor
 import eu.kanade.tachiyomi.lib.streamwishextractor.StreamWishExtractor
+import eu.kanade.tachiyomi.lib.universalextractor.UniversalExtractor
 import eu.kanade.tachiyomi.multisrc.dooplay.DooPlay
 import eu.kanade.tachiyomi.network.GET
 import eu.kanade.tachiyomi.network.POST
@@ -64,13 +65,14 @@ class Animenix : DooPlay(
 
     private val filemoonExtractor by lazy { FilemoonExtractor(client) }
     private val streamWishExtractor by lazy { StreamWishExtractor(headers = headers, client = client) }
+    private val universalExtractor by lazy { UniversalExtractor(client) }
 
     private fun getPlayerVideos(link: String): List<Video> {
         return when {
             link.contains("filemoon") -> filemoonExtractor.videosFromUrl(link)
             link.contains("swdyu") -> streamWishExtractor.videosFromUrl(link)
             link.contains("wishembed") || link.contains("cdnwish") || link.contains("flaswish") || link.contains("sfastwish") || link.contains("streamwish") || link.contains("asnwish") -> streamWishExtractor.videosFromUrl(link)
-            else -> emptyList()
+            else -> universalExtractor.videosFromUrl(link, headers)
         }
     }
 
diff --git a/src/es/animeonlineninja/build.gradle b/src/es/animeonlineninja/build.gradle
index e72ff77a5a..78e2e3bb97 100644
--- a/src/es/animeonlineninja/build.gradle
+++ b/src/es/animeonlineninja/build.gradle
@@ -3,7 +3,7 @@ ext {
     extClass = '.AnimeOnlineNinja'
     themePkg = 'dooplay'
     baseUrl = 'https://ww3.animeonline.ninja'
-    overrideVersionCode = 44
+    overrideVersionCode = 45
 }
 
 apply from: "$rootDir/common.gradle"
@@ -14,4 +14,5 @@ dependencies {
     implementation(project(':lib:filemoon-extractor'))
     implementation(project(':lib:mixdrop-extractor'))
     implementation(project(':lib:uqload-extractor'))
+    implementation(project(':lib:universal-extractor'))
 }
\ No newline at end of file
diff --git a/src/es/animeonlineninja/src/eu/kanade/tachiyomi/animeextension/es/animeonlineninja/AnimeOnlineNinja.kt b/src/es/animeonlineninja/src/eu/kanade/tachiyomi/animeextension/es/animeonlineninja/AnimeOnlineNinja.kt
index ad35b67e55..59148ff18c 100644
--- a/src/es/animeonlineninja/src/eu/kanade/tachiyomi/animeextension/es/animeonlineninja/AnimeOnlineNinja.kt
+++ b/src/es/animeonlineninja/src/eu/kanade/tachiyomi/animeextension/es/animeonlineninja/AnimeOnlineNinja.kt
@@ -9,6 +9,7 @@ import eu.kanade.tachiyomi.lib.doodextractor.DoodExtractor
 import eu.kanade.tachiyomi.lib.filemoonextractor.FilemoonExtractor
 import eu.kanade.tachiyomi.lib.mixdropextractor.MixDropExtractor
 import eu.kanade.tachiyomi.lib.streamtapeextractor.StreamTapeExtractor
+import eu.kanade.tachiyomi.lib.universalextractor.UniversalExtractor
 import eu.kanade.tachiyomi.lib.uqloadextractor.UqloadExtractor
 import eu.kanade.tachiyomi.multisrc.dooplay.DooPlay
 import eu.kanade.tachiyomi.network.GET
@@ -115,6 +116,7 @@ class AnimeOnlineNinja : DooPlay(
     private val streamTapeExtractor by lazy { StreamTapeExtractor(client) }
     private val mixDropExtractor by lazy { MixDropExtractor(client) }
     private val uqloadExtractor by lazy { UqloadExtractor(client) }
+    private val universalExtractor by lazy { UniversalExtractor(client) }
 
     private fun extractVideos(url: String, lang: String): List<Video> {
         return when {
@@ -142,8 +144,8 @@ class AnimeOnlineNinja : DooPlay(
                         listOf(Video(videoUrl, "$lang WolfStream", videoUrl, headers = headers))
                     }
             }
-            else -> null
-        } ?: emptyList<Video>()
+            else -> universalExtractor.videosFromUrl(url, headers, prefix = lang)
+        } ?: emptyList()
     }
 
     private fun extractFromMulti(url: String): List<Video> {
diff --git a/src/es/animeytes/build.gradle b/src/es/animeytes/build.gradle
index a5b2ddf827..e36ca85475 100644
--- a/src/es/animeytes/build.gradle
+++ b/src/es/animeytes/build.gradle
@@ -3,7 +3,7 @@ ext {
     extClass = '.AnimeYTES'
     themePkg = 'animestream'
     baseUrl = 'https://animeyt.pro'
-    overrideVersionCode = 5
+    overrideVersionCode = 6
 }
 
 apply from: "$rootDir/common.gradle"
@@ -15,4 +15,5 @@ dependencies {
     implementation(project(":lib:yourupload-extractor"))
     implementation(project(":lib:burstcloud-extractor"))
     implementation(project(":lib:filemoon-extractor"))
+    implementation(project(":lib:universal-extractor"))
 }
\ No newline at end of file
diff --git a/src/es/animeytes/src/eu/kanade/tachiyomi/animeextension/es/animeytes/AnimeYTES.kt b/src/es/animeytes/src/eu/kanade/tachiyomi/animeextension/es/animeytes/AnimeYTES.kt
index e364962695..ea5e8abbdf 100644
--- a/src/es/animeytes/src/eu/kanade/tachiyomi/animeextension/es/animeytes/AnimeYTES.kt
+++ b/src/es/animeytes/src/eu/kanade/tachiyomi/animeextension/es/animeytes/AnimeYTES.kt
@@ -10,6 +10,7 @@ import eu.kanade.tachiyomi.lib.filemoonextractor.FilemoonExtractor
 import eu.kanade.tachiyomi.lib.okruextractor.OkruExtractor
 import eu.kanade.tachiyomi.lib.sendvidextractor.SendvidExtractor
 import eu.kanade.tachiyomi.lib.streamtapeextractor.StreamTapeExtractor
+import eu.kanade.tachiyomi.lib.universalextractor.UniversalExtractor
 import eu.kanade.tachiyomi.lib.youruploadextractor.YourUploadExtractor
 import eu.kanade.tachiyomi.multisrc.animestream.AnimeStream
 import uy.kohesive.injekt.Injekt
@@ -48,6 +49,7 @@ class AnimeYTES : AnimeStream(
     private val youruploadExtractor by lazy { YourUploadExtractor(client) }
     private val burstcloudExtractor by lazy { BurstCloudExtractor(client) }
     private val filemoonExtractor by lazy { FilemoonExtractor(client) }
+    private val universalExtractor by lazy { UniversalExtractor(client) }
 
     override fun getVideoList(url: String, name: String): List<Video> {
         return when (name) {
@@ -57,7 +59,7 @@ class AnimeYTES : AnimeStream(
             "Your" -> youruploadExtractor.videoFromUrl(url, headers)
             "Alpha" -> burstcloudExtractor.videoFromUrl(url, headers)
             "Moon" -> filemoonExtractor.videosFromUrl(url)
-            else -> emptyList()
+            else -> universalExtractor.videosFromUrl(url, headers)
         }
     }
 
diff --git a/src/es/cinecalidad/build.gradle b/src/es/cinecalidad/build.gradle
index 6e30406d5e..237ce850c3 100644
--- a/src/es/cinecalidad/build.gradle
+++ b/src/es/cinecalidad/build.gradle
@@ -1,7 +1,7 @@
 ext {
     extName = 'CineCalidad'
     extClass = '.CineCalidad'
-    extVersionCode = 9
+    extVersionCode = 10
 }
 
 apply from: "$rootDir/common.gradle"
@@ -23,4 +23,6 @@ dependencies {
     implementation(project(':lib:fastream-extractor'))
     implementation(project(':lib:upstream-extractor'))
     implementation(project(':lib:streamhidevid-extractor'))
+    implementation(project(':lib:goodstream-extractor'))
+    implementation(project(':lib:universal-extractor'))
 }
\ No newline at end of file
diff --git a/src/es/cinecalidad/src/eu/kanade/tachiyomi/animeextension/es/cinecalidad/CineCalidad.kt b/src/es/cinecalidad/src/eu/kanade/tachiyomi/animeextension/es/cinecalidad/CineCalidad.kt
index 9ce7ceaca1..fc49e73257 100644
--- a/src/es/cinecalidad/src/eu/kanade/tachiyomi/animeextension/es/cinecalidad/CineCalidad.kt
+++ b/src/es/cinecalidad/src/eu/kanade/tachiyomi/animeextension/es/cinecalidad/CineCalidad.kt
@@ -15,12 +15,14 @@ import eu.kanade.tachiyomi.lib.burstcloudextractor.BurstCloudExtractor
 import eu.kanade.tachiyomi.lib.doodextractor.DoodExtractor
 import eu.kanade.tachiyomi.lib.fastreamextractor.FastreamExtractor
 import eu.kanade.tachiyomi.lib.filemoonextractor.FilemoonExtractor
+import eu.kanade.tachiyomi.lib.goodstramextractor.GoodStreamExtractor
 import eu.kanade.tachiyomi.lib.mp4uploadextractor.Mp4uploadExtractor
 import eu.kanade.tachiyomi.lib.okruextractor.OkruExtractor
 import eu.kanade.tachiyomi.lib.streamhidevidextractor.StreamHideVidExtractor
 import eu.kanade.tachiyomi.lib.streamlareextractor.StreamlareExtractor
 import eu.kanade.tachiyomi.lib.streamtapeextractor.StreamTapeExtractor
 import eu.kanade.tachiyomi.lib.streamwishextractor.StreamWishExtractor
+import eu.kanade.tachiyomi.lib.universalextractor.UniversalExtractor
 import eu.kanade.tachiyomi.lib.upstreamextractor.UpstreamExtractor
 import eu.kanade.tachiyomi.lib.uqloadextractor.UqloadExtractor
 import eu.kanade.tachiyomi.lib.voeextractor.VoeExtractor
@@ -176,7 +178,8 @@ class CineCalidad : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
                 embedUrl.contains("upstream") -> UpstreamExtractor(client).videosFromUrl(url)
                 embedUrl.contains("streamtape") || embedUrl.contains("stp") || embedUrl.contains("stape") -> listOf(StreamTapeExtractor(client).videoFromUrl(url, quality = "StreamTape")!!)
                 embedUrl.contains("ahvsh") || embedUrl.contains("streamhide") || embedUrl.contains("guccihide") || embedUrl.contains("streamvid") || embedUrl.contains("vidhide") -> StreamHideVidExtractor(client).videosFromUrl(url)
-                else -> emptyList()
+                embedUrl.contains("goodstream") -> GoodStreamExtractor(client, headers).videosFromUrl(url, name = "GoodStream: ")
+                else -> UniversalExtractor(client).videosFromUrl(url, headers)
             }
         }.getOrNull() ?: emptyList()
     }
diff --git a/src/es/cineplus123/build.gradle b/src/es/cineplus123/build.gradle
index 3e1ad7d852..72c8b5ed36 100644
--- a/src/es/cineplus123/build.gradle
+++ b/src/es/cineplus123/build.gradle
@@ -3,7 +3,7 @@ ext {
     extClass = '.Cineplus123'
     themePkg = 'dooplay'
     baseUrl = 'https://cineplus123.org'
-    overrideVersionCode = 1
+    overrideVersionCode = 2
 }
 
 apply from: "$rootDir/common.gradle"
@@ -11,4 +11,5 @@ apply from: "$rootDir/common.gradle"
 dependencies {
     implementation(project(":lib:streamwish-extractor"))
     implementation(project(":lib:uqload-extractor"))
+    implementation(project(":lib:universal-extractor"))
 }
\ No newline at end of file
diff --git a/src/es/cineplus123/src/eu/kanade/tachiyomi/animeextension/es/cineplus123/Cineplus123.kt b/src/es/cineplus123/src/eu/kanade/tachiyomi/animeextension/es/cineplus123/Cineplus123.kt
index eea7663731..4cf62d6f89 100644
--- a/src/es/cineplus123/src/eu/kanade/tachiyomi/animeextension/es/cineplus123/Cineplus123.kt
+++ b/src/es/cineplus123/src/eu/kanade/tachiyomi/animeextension/es/cineplus123/Cineplus123.kt
@@ -5,6 +5,7 @@ import androidx.preference.PreferenceScreen
 import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
 import eu.kanade.tachiyomi.animesource.model.Video
 import eu.kanade.tachiyomi.lib.streamwishextractor.StreamWishExtractor
+import eu.kanade.tachiyomi.lib.universalextractor.UniversalExtractor
 import eu.kanade.tachiyomi.lib.uqloadextractor.UqloadExtractor
 import eu.kanade.tachiyomi.multisrc.dooplay.DooPlay
 import eu.kanade.tachiyomi.network.GET
@@ -39,6 +40,7 @@ class Cineplus123 : DooPlay(
 
     private val uqloadExtractor by lazy { UqloadExtractor(client) }
     private val streamWishExtractor by lazy { StreamWishExtractor(client, headers) }
+    private val universalExtractor by lazy { UniversalExtractor(client) }
 
     // ============================ Video Links =============================
     override fun videoListParse(response: Response): List<Video> {
@@ -56,8 +58,8 @@ class Cineplus123 : DooPlay(
         return when {
             "uqload" in url -> uqloadExtractor.videosFromUrl(url, "$lang -")
             "strwish" in url -> streamWishExtractor.videosFromUrl(url, lang)
-            else -> null
-        } ?: emptyList()
+            else -> universalExtractor.videosFromUrl(url, headers, prefix = lang)
+        }
     }
 
     private fun getPlayerUrl(player: Element): String? {
diff --git a/src/es/cuevana/build.gradle b/src/es/cuevana/build.gradle
index 37c3ce3619..9b4f580db7 100644
--- a/src/es/cuevana/build.gradle
+++ b/src/es/cuevana/build.gradle
@@ -1,7 +1,7 @@
 ext {
     extName = 'Cuevana'
     extClass = '.CuevanaFactory'
-    extVersionCode = 40
+    extVersionCode = 41
 }
 
 apply from: "$rootDir/common.gradle"
@@ -22,5 +22,6 @@ dependencies {
     implementation(project(':lib:burstcloud-extractor'))
     implementation(project(':lib:fastream-extractor'))
     implementation(project(':lib:upstream-extractor'))
+    implementation(project(':lib:universal-extractor'))
     implementation libs.jsunpacker
 }
\ No newline at end of file
diff --git a/src/es/cuevana/src/eu/kanade/tachiyomi/animeextension/es/cuevana/CuevanaCh.kt b/src/es/cuevana/src/eu/kanade/tachiyomi/animeextension/es/cuevana/CuevanaCh.kt
index 5a3967ed24..aa36692e9a 100644
--- a/src/es/cuevana/src/eu/kanade/tachiyomi/animeextension/es/cuevana/CuevanaCh.kt
+++ b/src/es/cuevana/src/eu/kanade/tachiyomi/animeextension/es/cuevana/CuevanaCh.kt
@@ -20,6 +20,7 @@ import eu.kanade.tachiyomi.lib.okruextractor.OkruExtractor
 import eu.kanade.tachiyomi.lib.streamlareextractor.StreamlareExtractor
 import eu.kanade.tachiyomi.lib.streamtapeextractor.StreamTapeExtractor
 import eu.kanade.tachiyomi.lib.streamwishextractor.StreamWishExtractor
+import eu.kanade.tachiyomi.lib.universalextractor.UniversalExtractor
 import eu.kanade.tachiyomi.lib.upstreamextractor.UpstreamExtractor
 import eu.kanade.tachiyomi.lib.uqloadextractor.UqloadExtractor
 import eu.kanade.tachiyomi.lib.voeextractor.VoeExtractor
@@ -160,98 +161,121 @@ class CuevanaCh(override val name: String, override val baseUrl: String) : Confi
         val videoList = mutableListOf<Video>()
         val embedUrl = url.lowercase()
         try {
-            if (embedUrl.contains("voe")) {
-                VoeExtractor(client).videosFromUrl(url, prefix).also(videoList::addAll)
-            }
-            if ((embedUrl.contains("amazon") || embedUrl.contains("amz")) && !embedUrl.contains("disable")) {
-                val body = client.newCall(GET(url)).execute().asJsoup()
-                if (body.select("script:containsData(var shareId)").toString().isNotBlank()) {
-                    val shareId = body.selectFirst("script:containsData(var shareId)")!!.data()
-                        .substringAfter("shareId = \"").substringBefore("\"")
-                    val amazonApiJson = client.newCall(GET("https://www.amazon.com/drive/v1/shares/$shareId?resourceVersion=V2&ContentType=JSON&asset=ALL"))
-                        .execute().asJsoup()
-                    val epId = amazonApiJson.toString().substringAfter("\"id\":\"").substringBefore("\"")
-                    val amazonApi =
-                        client.newCall(GET("https://www.amazon.com/drive/v1/nodes/$epId/children?resourceVersion=V2&ContentType=JSON&limit=200&sort=%5B%22kind+DESC%22%2C+%22modifiedDate+DESC%22%5D&asset=ALL&tempLink=true&shareId=$shareId"))
+            return when {
+                embedUrl.contains("voe") -> {
+                    VoeExtractor(client).videosFromUrl(url, prefix).also(videoList::addAll)
+                    videoList
+                }
+                (embedUrl.contains("amazon") || embedUrl.contains("amz")) && !embedUrl.contains("disable") -> {
+                    val body = client.newCall(GET(url)).execute().asJsoup()
+                    if (body.select("script:containsData(var shareId)").toString().isNotBlank()) {
+                        val shareId = body.selectFirst("script:containsData(var shareId)")!!.data()
+                            .substringAfter("shareId = \"").substringBefore("\"")
+                        val amazonApiJson = client.newCall(GET("https://www.amazon.com/drive/v1/shares/$shareId?resourceVersion=V2&ContentType=JSON&asset=ALL"))
                             .execute().asJsoup()
-                    val videoUrl = amazonApi.toString().substringAfter("\"FOLDER\":").substringAfter("tempLink\":\"").substringBefore("\"")
-                    videoList.add(Video(videoUrl, "$prefix Amazon", videoUrl))
+                        val epId = amazonApiJson.toString().substringAfter("\"id\":\"").substringBefore("\"")
+                        val amazonApi =
+                            client.newCall(GET("https://www.amazon.com/drive/v1/nodes/$epId/children?resourceVersion=V2&ContentType=JSON&limit=200&sort=%5B%22kind+DESC%22%2C+%22modifiedDate+DESC%22%5D&asset=ALL&tempLink=true&shareId=$shareId"))
+                                .execute().asJsoup()
+                        val videoUrl = amazonApi.toString().substringAfter("\"FOLDER\":").substringAfter("tempLink\":\"").substringBefore("\"")
+                        videoList.add(Video(videoUrl, "$prefix Amazon", videoUrl))
+                    }
+                    videoList
                 }
-            }
-            if (embedUrl.contains("ok.ru") || embedUrl.contains("okru")) {
-                OkruExtractor(client).videosFromUrl(url, prefix).also(videoList::addAll)
-            }
-            if (embedUrl.contains("filemoon") || embedUrl.contains("moonplayer")) {
-                val vidHeaders = headers.newBuilder()
-                    .add("Origin", "https://${url.toHttpUrl().host}")
-                    .add("Referer", "https://${url.toHttpUrl().host}/")
-                    .build()
-                FilemoonExtractor(client).videosFromUrl(url, prefix = "$prefix Filemoon:", headers = vidHeaders).also(videoList::addAll)
-            }
-            if (embedUrl.contains("uqload")) {
-                UqloadExtractor(client).videosFromUrl(url, prefix = prefix).also(videoList::addAll)
-            }
-            if (embedUrl.contains("mp4upload")) {
-                Mp4uploadExtractor(client).videosFromUrl(url, headers, prefix = prefix).let { videoList.addAll(it) }
-            }
-            if (embedUrl.contains("wishembed") || embedUrl.contains("streamwish") || embedUrl.contains("strwish") || embedUrl.contains("wish")) {
-                val docHeaders = headers.newBuilder()
-                    .add("Origin", "https://streamwish.to")
-                    .add("Referer", "https://streamwish.to/")
-                    .build()
-                StreamWishExtractor(client, docHeaders).videosFromUrl(url, videoNameGen = { "$prefix StreamWish:$it" }).also(videoList::addAll)
-            }
-            if (embedUrl.contains("doodstream") || embedUrl.contains("dood.")) {
-                val url2 = url.replace("https://doodstream.com/e/", "https://dood.to/e/")
-                DoodExtractor(client).videoFromUrl(url2, "$prefix DoodStream")?.let { videoList.add(it) }
-            }
-            if (embedUrl.contains("streamlare")) {
-                StreamlareExtractor(client).videosFromUrl(url, prefix = prefix).let { videoList.addAll(it) }
-            }
-            if (embedUrl.contains("yourupload") || embedUrl.contains("upload")) {
-                YourUploadExtractor(client).videoFromUrl(url, headers = headers, prefix = prefix).let { videoList.addAll(it) }
-            }
-            if (embedUrl.contains("burstcloud") || embedUrl.contains("burst")) {
-                BurstCloudExtractor(client).videoFromUrl(url, headers = headers, prefix = prefix).let { videoList.addAll(it) }
-            }
-            if (embedUrl.contains("fastream")) {
-                FastreamExtractor(client, headers).videosFromUrl(url, prefix = "$prefix Fastream:").also(videoList::addAll)
-            }
-            if (embedUrl.contains("upstream")) {
-                UpstreamExtractor(client).videosFromUrl(url, prefix = prefix).let { videoList.addAll(it) }
-            }
-            if (embedUrl.contains("streamtape") || embedUrl.contains("stp") || embedUrl.contains("stape")) {
-                StreamTapeExtractor(client).videoFromUrl(url, quality = "$prefix StreamTape")?.let { videoList.add(it) }
-            }
-            if (embedUrl.contains("tomatomatela")) {
-                runCatching {
-                    val mainUrl = url.substringBefore("/embed.html#").substringAfter("https://")
-                    val headers = headers.newBuilder()
-                        .set("authority", mainUrl)
-                        .set("accept", "application/json, text/javascript, */*; q=0.01")
-                        .set("accept-language", "es-MX,es-419;q=0.9,es;q=0.8,en;q=0.7")
-                        .set("sec-ch-ua", "\"Chromium\";v=\"106\", \"Google Chrome\";v=\"106\", \"Not;A=Brand\";v=\"99\"")
-                        .set("sec-ch-ua-mobile", "?0")
-                        .set("sec-ch-ua-platform", "Windows")
-                        .set("sec-fetch-dest", "empty")
-                        .set("sec-fetch-mode", "cors")
-                        .set("sec-fetch-site", "same-origin")
-                        .set("x-requested-with", "XMLHttpRequest")
+                embedUrl.contains("ok.ru") || embedUrl.contains("okru") -> {
+                    OkruExtractor(client).videosFromUrl(url, prefix).also(videoList::addAll)
+                    videoList
+                }
+                embedUrl.contains("filemoon") || embedUrl.contains("moonplayer") -> {
+                    val vidHeaders = headers.newBuilder()
+                        .add("Origin", "https://${url.toHttpUrl().host}")
+                        .add("Referer", "https://${url.toHttpUrl().host}/")
                         .build()
-                    val token = url.substringAfter("/embed.html#")
-                    val urlRequest = "https://$mainUrl/details.php?v=$token"
-                    val response = client.newCall(GET(urlRequest, headers = headers)).execute().asJsoup()
-                    val bodyText = response.select("body").text()
-                    val json = json.decodeFromString<JsonObject>(bodyText)
-                    val status = json["status"]!!.jsonPrimitive.content
-                    val file = json["file"]!!.jsonPrimitive.content
-                    if (status == "200") { videoList.add(Video(file, "$prefix Tomatomatela", file, headers = null)) }
+                    FilemoonExtractor(client).videosFromUrl(url, prefix = "$prefix Filemoon:", headers = vidHeaders).also(videoList::addAll)
+                    videoList
+                }
+                embedUrl.contains("uqload") -> {
+                    UqloadExtractor(client).videosFromUrl(url, prefix = prefix).also(videoList::addAll)
+                    videoList
+                }
+                embedUrl.contains("mp4upload") -> {
+                    Mp4uploadExtractor(client).videosFromUrl(url, headers, prefix = prefix).let { videoList.addAll(it) }
+                    videoList
+                }
+                embedUrl.contains("wishembed") || embedUrl.contains("streamwish") || embedUrl.contains("strwish") || embedUrl.contains("wish") -> {
+                    val docHeaders = headers.newBuilder()
+                        .add("Origin", "https://streamwish.to")
+                        .add("Referer", "https://streamwish.to/")
+                        .build()
+                    StreamWishExtractor(client, docHeaders).videosFromUrl(url, videoNameGen = { "$prefix StreamWish:$it" }).also(videoList::addAll)
+                    videoList
+                }
+                embedUrl.contains("doodstream") || embedUrl.contains("dood.") -> {
+                    val url2 = url.replace("https://doodstream.com/e/", "https://dood.to/e/")
+                    DoodExtractor(client).videoFromUrl(url2, "$prefix DoodStream")?.let { videoList.add(it) }
+                    videoList
+                }
+                embedUrl.contains("streamlare") -> {
+                    StreamlareExtractor(client).videosFromUrl(url, prefix = prefix).let { videoList.addAll(it) }
+                    videoList
+                }
+                embedUrl.contains("yourupload") || embedUrl.contains("upload") -> {
+                    YourUploadExtractor(client).videoFromUrl(url, headers = headers, prefix = prefix).let { videoList.addAll(it) }
+                    videoList
+                }
+                embedUrl.contains("burstcloud") || embedUrl.contains("burst") -> {
+                    BurstCloudExtractor(client).videoFromUrl(url, headers = headers, prefix = prefix).let { videoList.addAll(it) }
+                    videoList
+                }
+                embedUrl.contains("fastream") -> {
+                    FastreamExtractor(client, headers).videosFromUrl(url, prefix = "$prefix Fastream:").also(videoList::addAll)
+                    videoList
+                }
+                embedUrl.contains("upstream") -> {
+                    UpstreamExtractor(client).videosFromUrl(url, prefix = prefix).let { videoList.addAll(it) }
+                    videoList
+                }
+                embedUrl.contains("streamtape") || embedUrl.contains("stp") || embedUrl.contains("stape") -> {
+                    StreamTapeExtractor(client).videoFromUrl(url, quality = "$prefix StreamTape")?.let { videoList.add(it) }
+                    videoList
+                }
+                embedUrl.contains("tomatomatela") -> {
+                    runCatching {
+                        val mainUrl = url.substringBefore("/embed.html#").substringAfter("https://")
+                        val headers = headers.newBuilder()
+                            .set("authority", mainUrl)
+                            .set("accept", "application/json, text/javascript, */*; q=0.01")
+                            .set("accept-language", "es-MX,es-419;q=0.9,es;q=0.8,en;q=0.7")
+                            .set("sec-ch-ua", "\"Chromium\";v=\"106\", \"Google Chrome\";v=\"106\", \"Not;A=Brand\";v=\"99\"")
+                            .set("sec-ch-ua-mobile", "?0")
+                            .set("sec-ch-ua-platform", "Windows")
+                            .set("sec-fetch-dest", "empty")
+                            .set("sec-fetch-mode", "cors")
+                            .set("sec-fetch-site", "same-origin")
+                            .set("x-requested-with", "XMLHttpRequest")
+                            .build()
+                        val token = url.substringAfter("/embed.html#")
+                        val urlRequest = "https://$mainUrl/details.php?v=$token"
+                        val response = client.newCall(GET(urlRequest, headers = headers)).execute().asJsoup()
+                        val bodyText = response.select("body").text()
+                        val json = json.decodeFromString<JsonObject>(bodyText)
+                        val status = json["status"]!!.jsonPrimitive.content
+                        val file = json["file"]!!.jsonPrimitive.content
+                        if (status == "200") { videoList.add(Video(file, "$prefix Tomatomatela", file, headers = null)) }
+                    }
+                    videoList
+                }
+                embedUrl.contains("filelions") || embedUrl.contains("lion") -> {
+                    StreamWishExtractor(client, headers).videosFromUrl(url, videoNameGen = { "$prefix FileLions:$it" }).also(videoList::addAll)
+                    videoList
+                }
+                else -> {
+                    UniversalExtractor(client).videosFromUrl(url, headers, prefix = prefix).also(videoList::addAll)
                 }
             }
-            if (embedUrl.contains("filelions") || embedUrl.contains("lion")) {
-                StreamWishExtractor(client, headers).videosFromUrl(url, videoNameGen = { "$prefix FileLions:$it" }).also(videoList::addAll)
-            }
-        } catch (_: Exception) { }
+        } catch (e: Exception) {
+            e.printStackTrace()
+        }
         return videoList
     }
 
diff --git a/src/es/cuevana/src/eu/kanade/tachiyomi/animeextension/es/cuevana/CuevanaEu.kt b/src/es/cuevana/src/eu/kanade/tachiyomi/animeextension/es/cuevana/CuevanaEu.kt
index ef8f477be9..e874916770 100644
--- a/src/es/cuevana/src/eu/kanade/tachiyomi/animeextension/es/cuevana/CuevanaEu.kt
+++ b/src/es/cuevana/src/eu/kanade/tachiyomi/animeextension/es/cuevana/CuevanaEu.kt
@@ -20,6 +20,7 @@ import eu.kanade.tachiyomi.lib.filemoonextractor.FilemoonExtractor
 import eu.kanade.tachiyomi.lib.okruextractor.OkruExtractor
 import eu.kanade.tachiyomi.lib.streamtapeextractor.StreamTapeExtractor
 import eu.kanade.tachiyomi.lib.streamwishextractor.StreamWishExtractor
+import eu.kanade.tachiyomi.lib.universalextractor.UniversalExtractor
 import eu.kanade.tachiyomi.lib.voeextractor.VoeExtractor
 import eu.kanade.tachiyomi.lib.youruploadextractor.YourUploadExtractor
 import eu.kanade.tachiyomi.network.GET
@@ -180,34 +181,47 @@ class CuevanaEu(override val name: String, override val baseUrl: String) : Confi
     private fun loadExtractor(url: String, prefix: String = ""): List<Video> {
         val videoList = mutableListOf<Video>()
         val embedUrl = url.lowercase()
-        if (embedUrl.contains("yourupload")) {
-            val videos = YourUploadExtractor(client).videoFromUrl(url, headers = headers)
-            videoList.addAll(videos)
-        }
-        if (embedUrl.contains("doodstream") || embedUrl.contains("dood.")) {
-            DoodExtractor(client).videoFromUrl(url, "$prefix DoodStream")
-                ?.let { videoList.add(it) }
-        }
-        if (embedUrl.contains("okru") || embedUrl.contains("ok.ru")) {
-            OkruExtractor(client).videosFromUrl(url, prefix, true).also(videoList::addAll)
-        }
-        if (embedUrl.contains("voe")) {
-            VoeExtractor(client).videosFromUrl(url, prefix).also(videoList::addAll)
-        }
-        if (embedUrl.contains("streamtape")) {
-            StreamTapeExtractor(client).videoFromUrl(url, "$prefix StreamTape")?.let { videoList.add(it) }
-        }
-        if (embedUrl.contains("wishembed") || embedUrl.contains("streamwish") || embedUrl.contains("wish")) {
-            StreamWishExtractor(client, headers).videosFromUrl(url) { "$prefix StreamWish:$it" }
-                .also(videoList::addAll)
-        }
-        if (embedUrl.contains("filemoon") || embedUrl.contains("moonplayer")) {
-            FilemoonExtractor(client).videosFromUrl(url, "$prefix Filemoon:").also(videoList::addAll)
-        }
-        if (embedUrl.contains("filelions") || embedUrl.contains("lion")) {
-            StreamWishExtractor(client, headers).videosFromUrl(url, videoNameGen = { "$prefix FileLions:$it" }).also(videoList::addAll)
+        return when {
+            embedUrl.contains("yourupload") -> {
+                val videos = YourUploadExtractor(client).videoFromUrl(url, headers = headers)
+                videoList.addAll(videos)
+                videoList
+            }
+            embedUrl.contains("doodstream") || embedUrl.contains("dood.") -> {
+                DoodExtractor(client).videoFromUrl(url, "$prefix DoodStream")
+                    ?.let { videoList.add(it) }
+                videoList
+            }
+            embedUrl.contains("okru") || embedUrl.contains("ok.ru") -> {
+                OkruExtractor(client).videosFromUrl(url, prefix, true).also(videoList::addAll)
+                videoList
+            }
+            embedUrl.contains("voe") -> {
+                VoeExtractor(client).videosFromUrl(url, prefix).also(videoList::addAll)
+                videoList
+            }
+            embedUrl.contains("streamtape") -> {
+                StreamTapeExtractor(client).videoFromUrl(url, "$prefix StreamTape")?.let { videoList.add(it) }
+                videoList
+            }
+            embedUrl.contains("wishembed") || embedUrl.contains("streamwish") || embedUrl.contains("wish") -> {
+                StreamWishExtractor(client, headers).videosFromUrl(url) { "$prefix StreamWish:$it" }
+                    .also(videoList::addAll)
+                videoList
+            }
+            embedUrl.contains("filemoon") || embedUrl.contains("moonplayer") -> {
+                FilemoonExtractor(client).videosFromUrl(url, "$prefix Filemoon:").also(videoList::addAll)
+                videoList
+            }
+            embedUrl.contains("filelions") || embedUrl.contains("lion") -> {
+                StreamWishExtractor(client, headers).videosFromUrl(url, videoNameGen = { "$prefix FileLions:$it" }).also(videoList::addAll)
+                videoList
+            }
+            else -> {
+                UniversalExtractor(client).videosFromUrl(url, headers, prefix = prefix).also(videoList::addAll)
+                videoList
+            }
         }
-        return videoList
     }
 
     override fun videoListSelector() = throw UnsupportedOperationException()
diff --git a/src/es/jkanime/build.gradle b/src/es/jkanime/build.gradle
index 7d53ff3ba8..d53e494f74 100644
--- a/src/es/jkanime/build.gradle
+++ b/src/es/jkanime/build.gradle
@@ -1,7 +1,7 @@
 ext {
     extName = 'Jkanime'
     extClass = '.Jkanime'
-    extVersionCode = 26
+    extVersionCode = 27
 }
 
 apply from: "$rootDir/common.gradle"
@@ -14,4 +14,5 @@ dependencies {
     implementation(project(':lib:filemoon-extractor'))
     implementation(project(':lib:streamtape-extractor'))
     implementation(project(':lib:voe-extractor'))
+    implementation(project(':lib:universal-extractor'))
 }
diff --git a/src/es/jkanime/src/eu/kanade/tachiyomi/animeextension/es/jkanime/Jkanime.kt b/src/es/jkanime/src/eu/kanade/tachiyomi/animeextension/es/jkanime/Jkanime.kt
index bf4fbb3db7..be01d0a1cc 100644
--- a/src/es/jkanime/src/eu/kanade/tachiyomi/animeextension/es/jkanime/Jkanime.kt
+++ b/src/es/jkanime/src/eu/kanade/tachiyomi/animeextension/es/jkanime/Jkanime.kt
@@ -20,6 +20,7 @@ import eu.kanade.tachiyomi.lib.mp4uploadextractor.Mp4uploadExtractor
 import eu.kanade.tachiyomi.lib.okruextractor.OkruExtractor
 import eu.kanade.tachiyomi.lib.streamtapeextractor.StreamTapeExtractor
 import eu.kanade.tachiyomi.lib.streamwishextractor.StreamWishExtractor
+import eu.kanade.tachiyomi.lib.universalextractor.UniversalExtractor
 import eu.kanade.tachiyomi.lib.voeextractor.VoeExtractor
 import eu.kanade.tachiyomi.network.GET
 import eu.kanade.tachiyomi.util.asJsoup
@@ -173,6 +174,7 @@ class Jkanime : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
     private val mixDropExtractor by lazy { MixDropExtractor(client) }
     private val streamWishExtractor by lazy { StreamWishExtractor(client, headers) }
     private val jkanimeExtractor by lazy { JkanimeExtractor(client) }
+    private val universalExtractor by lazy { UniversalExtractor(client) }
 
     override fun videoListParse(response: Response): List<Video> {
         val document = response.asJsoup()
@@ -189,7 +191,7 @@ class Jkanime : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
                 "stream/jkmedia" in url -> jkanimeExtractor.getDesukaFromUrl(url, "$lang ")
                 "um2.php" in url -> jkanimeExtractor.getNozomiFromUrl(url, "$lang ")
                 "um.php" in url -> jkanimeExtractor.getDesuFromUrl(url, "$lang ")
-                else -> emptyList()
+                else -> universalExtractor.videosFromUrl(url, headers, prefix = lang)
             }
         }
     }