diff --git a/app/src/main/java/com/futo/platformplayer/Settings.kt b/app/src/main/java/com/futo/platformplayer/Settings.kt
index f2d689ed9c4d21bff14938303381d5b86676e82f..168cddfb674863820dd1085bb77b499fd5d9ccd7 100644
--- a/app/src/main/java/com/futo/platformplayer/Settings.kt
+++ b/app/src/main/java/com/futo/platformplayer/Settings.kt
@@ -685,7 +685,9 @@ class Settings : FragmentedStorageFileJson() {
         fun manualCheck() {
             if (!BuildConfig.IS_PLAYSTORE_BUILD) {
                 SettingsActivity.getActivity()?.let {
-                    StateUpdate.instance.checkForUpdates(it, true);
+                    StateApp.instance.scopeOrNull?.launch(Dispatchers.IO) {
+                        StateUpdate.instance.checkForUpdates(it, true)
+                    }
                 }
             } else {
                 SettingsActivity.getActivity()?.let {
diff --git a/app/src/main/java/com/futo/platformplayer/activities/AddSourceActivity.kt b/app/src/main/java/com/futo/platformplayer/activities/AddSourceActivity.kt
index bc22d3dc4326a47ab8f1a0608eb3ce6b235c7f8b..067205743d0dcfc0d10c2fe278df6fb0a08babad 100644
--- a/app/src/main/java/com/futo/platformplayer/activities/AddSourceActivity.kt
+++ b/app/src/main/java/com/futo/platformplayer/activities/AddSourceActivity.kt
@@ -216,8 +216,10 @@ class AddSourceActivity : AppCompatActivity() {
 
     fun install(config: SourcePluginConfig, script: String) {
         StatePlugins.instance.installPlugin(this, lifecycleScope, config, script) {
-            if(it)
+            if(it) {
+                StatePlatform.instance.clearUpdateAvailable(config)
                 backToSources();
+            }
         }
     }
 
diff --git a/app/src/main/java/com/futo/platformplayer/activities/ExceptionActivity.kt b/app/src/main/java/com/futo/platformplayer/activities/ExceptionActivity.kt
index a51c0f4abcfb1902a8e9cd86519460a4ecf26a30..99a6e1b0b9835647db1b1e1beb7734c92b438c21 100644
--- a/app/src/main/java/com/futo/platformplayer/activities/ExceptionActivity.kt
+++ b/app/src/main/java/com/futo/platformplayer/activities/ExceptionActivity.kt
@@ -9,9 +9,11 @@ import android.widget.TextView
 import android.widget.Toast
 import androidx.appcompat.app.AppCompatActivity
 import androidx.lifecycle.lifecycleScope
-import com.futo.platformplayer.*
+import com.futo.platformplayer.BuildConfig
+import com.futo.platformplayer.R
 import com.futo.platformplayer.logging.LogLevel
 import com.futo.platformplayer.logging.Logging
+import com.futo.platformplayer.setNavigationBarColorAndIcons
 import com.futo.platformplayer.states.StateApp
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.launch
diff --git a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/SourceDetailFragment.kt b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/SourceDetailFragment.kt
index 3af3f01d8241678a7466ded0850616df48602b86..6a743d4e59b82e6a598e78ffdbe56829e8f0b02b 100644
--- a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/SourceDetailFragment.kt
+++ b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/SourceDetailFragment.kt
@@ -454,6 +454,7 @@ class SourceDetailFragment : MainFragment() {
                 }
             });
         }
+
         private fun checkForUpdatesSource() {
             val c = _config ?: return;
             val sourceUrl = c.sourceUrl ?: return;
diff --git a/app/src/main/java/com/futo/platformplayer/states/StateApp.kt b/app/src/main/java/com/futo/platformplayer/states/StateApp.kt
index bcf685928e1ffd9f911558fbdfe7e84aa33f8f25..412abd555b1ffa5e90ddd35577f8f65f49e3cc03 100644
--- a/app/src/main/java/com/futo/platformplayer/states/StateApp.kt
+++ b/app/src/main/java/com/futo/platformplayer/states/StateApp.kt
@@ -460,7 +460,9 @@ class StateApp {
 
             //Foreground download
             autoUpdateEnabled -> {
-                StateUpdate.instance.checkForUpdates(context, false);
+                scopeOrNull?.launch(Dispatchers.IO) {
+                    StateUpdate.instance.checkForUpdates(context, false)
+                }
             }
 
             else -> {
@@ -558,6 +560,23 @@ class StateApp {
 
         if(StateHistory.instance.shouldMigrateLegacyHistory())
             StateHistory.instance.migrateLegacyHistory();
+
+        StateAnnouncement.instance.deleteAnnouncement("plugin-update")
+
+        scopeOrNull?.launch(Dispatchers.IO) {
+            val updateAvailableCount = StatePlatform.instance.checkForUpdates()
+
+            withContext(Dispatchers.Main) {
+                if (updateAvailableCount > 0) {
+                    StateAnnouncement.instance.registerAnnouncement(
+                        "plugin-update",
+                        "Plugin updates available",
+                        "There are $updateAvailableCount plugin updates available.",
+                        AnnouncementType.SESSION_RECURRING
+                    )
+                }
+            }
+        }
     }
 
     fun mainAppStartedWithExternalFiles(context: Context) {
diff --git a/app/src/main/java/com/futo/platformplayer/states/StatePlatform.kt b/app/src/main/java/com/futo/platformplayer/states/StatePlatform.kt
index a9aae85d362404bbc0b6d057e8077d78cce51359..fe06e78d6c41d79c53f03eb8dbdfbf1386d2e4fb 100644
--- a/app/src/main/java/com/futo/platformplayer/states/StatePlatform.kt
+++ b/app/src/main/java/com/futo/platformplayer/states/StatePlatform.kt
@@ -5,6 +5,7 @@ import androidx.collection.LruCache
 import com.futo.platformplayer.R
 import com.futo.platformplayer.Settings
 import com.futo.platformplayer.UIDialogs
+import com.futo.platformplayer.api.http.ManagedHttpClient
 import com.futo.platformplayer.api.media.IPlatformClient
 import com.futo.platformplayer.api.media.IPluginSourced
 import com.futo.platformplayer.api.media.PlatformMultiClientPool
@@ -78,6 +79,7 @@ class StatePlatform {
     private val _clientsLock = Object();
     private val _availableClients : ArrayList<IPlatformClient> = ArrayList();
     private val _enabledClients : ArrayList<IPlatformClient> = ArrayList();
+    private var _updatesAvailableMap: HashSet<String> = hashSetOf();
 
     //ClientPools are used to isolate plugin usage of certain components from others
     //This prevents for example a background task like subscriptions from blocking a user from opening a video
@@ -932,6 +934,67 @@ class StatePlatform {
         }
     }
 
+    fun hasUpdateAvailable(c: SourcePluginConfig): Boolean {
+        val updatesAvailableMap = _updatesAvailableMap
+        synchronized(updatesAvailableMap) {
+            return updatesAvailableMap.contains(c.id)
+        }
+    }
+
+    suspend fun checkForUpdates(): Int = withContext(Dispatchers.IO) {
+        var updateAvailableCount = 0
+        val updatesAvailableFor = hashSetOf<String>()
+        for (availableClient in getAvailableClients()) {
+            if (availableClient !is JSClient) {
+                continue
+            }
+
+            if (checkForUpdates(availableClient.config)) {
+                updateAvailableCount++
+                updatesAvailableFor.add(availableClient.config.id)
+            }
+        }
+
+        _updatesAvailableMap = updatesAvailableFor
+        return@withContext updateAvailableCount
+    }
+
+    fun clearUpdateAvailable(c: SourcePluginConfig) {
+        val updatesAvailableMap = _updatesAvailableMap
+        synchronized(updatesAvailableMap) {
+            updatesAvailableMap.remove(c.id)
+        }
+    }
+
+    private suspend fun checkForUpdates(c: SourcePluginConfig): Boolean = withContext(Dispatchers.IO) {
+        val sourceUrl = c.sourceUrl ?: return@withContext false;
+
+        Logger.i(TAG, "Check for source updates '${c.name}'.");
+        try {
+            val client = ManagedHttpClient();
+            val response = client.get(sourceUrl);
+            Logger.i(TAG, "Downloading source config '$sourceUrl'.");
+
+            if (!response.isOk || response.body == null) {
+                return@withContext false;
+            }
+
+            val configJson = response.body.string();
+            Logger.i(TAG, "Downloaded source config ($sourceUrl):\n${configJson}");
+
+            val config = SourcePluginConfig.fromJson(configJson);
+            if (config.version <= c.version) {
+                return@withContext false;
+            }
+
+            Logger.i(TAG, "Update is available (config.version=${config.version}, source.config.version=${c.version}).");
+            return@withContext true;
+        } catch (e: Throwable) {
+            Logger.e(TAG, "Failed to check for updates.", e);
+            return@withContext false;
+        }
+    }
+
     companion object {
         private var _instance : StatePlatform? = null;
         val instance : StatePlatform
diff --git a/app/src/main/java/com/futo/platformplayer/states/StatePlugins.kt b/app/src/main/java/com/futo/platformplayer/states/StatePlugins.kt
index 2f08937d975ffca42c78a5ab7d4a064bc0b46102..34848c1d23b65807eb09942ff29cd88e0dc6f9d6 100644
--- a/app/src/main/java/com/futo/platformplayer/states/StatePlugins.kt
+++ b/app/src/main/java/com/futo/platformplayer/states/StatePlugins.kt
@@ -10,7 +10,6 @@ import com.futo.platformplayer.api.media.platforms.js.SourceAuth
 import com.futo.platformplayer.api.media.platforms.js.SourceCaptchaData
 import com.futo.platformplayer.api.media.platforms.js.SourcePluginConfig
 import com.futo.platformplayer.api.media.platforms.js.SourcePluginDescriptor
-import com.futo.platformplayer.developer.DeveloperEndpoints
 import com.futo.platformplayer.logging.Logger
 import com.futo.platformplayer.models.ImageVariable
 import com.futo.platformplayer.stores.FragmentedStorage
@@ -467,7 +466,6 @@ class StatePlugins {
         _plugins.save(descriptor);
     }
 
-
     @Serializable
     private data class PluginConfig(
         val SOURCES_EMBEDDED: Map<String, String>,
diff --git a/app/src/main/java/com/futo/platformplayer/states/StateUpdate.kt b/app/src/main/java/com/futo/platformplayer/states/StateUpdate.kt
index 1a5e4c808aa6881992a1288cac5837adfc75f78f..7a625a1532b67ea92f6df2fb34bd97197d8968b1 100644
--- a/app/src/main/java/com/futo/platformplayer/states/StateUpdate.kt
+++ b/app/src/main/java/com/futo/platformplayer/states/StateUpdate.kt
@@ -2,15 +2,15 @@ package com.futo.platformplayer.states
 
 import android.content.Context
 import android.os.Build
-import android.os.Environment
-import com.futo.platformplayer.*
+import com.futo.platformplayer.BuildConfig
+import com.futo.platformplayer.UIDialogs
 import com.futo.platformplayer.api.http.ManagedHttpClient
+import com.futo.platformplayer.copyToOutputStream
 import com.futo.platformplayer.logging.Logger
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.withContext
 import java.io.File
-import java.io.FileNotFoundException
 import java.io.InputStream
 import java.io.OutputStream
 
@@ -155,47 +155,45 @@ class StateUpdate {
         }
     }
 
-    fun checkForUpdates(context: Context, showUpToDateToast: Boolean) {
-        StateApp.instance.scopeOrNull?.launch(Dispatchers.IO) {
-            try {
-                val client = ManagedHttpClient();
-                val latestVersion = downloadVersionCode(client);
+    suspend fun checkForUpdates(context: Context, showUpToDateToast: Boolean) = withContext(Dispatchers.IO) {
+        try {
+            val client = ManagedHttpClient();
+            val latestVersion = downloadVersionCode(client);
 
-                if (latestVersion != null) {
-                    val currentVersion = BuildConfig.VERSION_CODE;
-                    Logger.i(TAG, "Current version ${currentVersion} latest version ${latestVersion}.");
+            if (latestVersion != null) {
+                val currentVersion = BuildConfig.VERSION_CODE;
+                Logger.i(TAG, "Current version ${currentVersion} latest version ${latestVersion}.");
 
-                    if (latestVersion > currentVersion) {
-                        withContext(Dispatchers.Main) {
-                            try {
-                                UIDialogs.showUpdateAvailableDialog(context, latestVersion);
-                            } catch (e: Throwable) {
-                                UIDialogs.toast(context, "Failed to show update dialog");
-                                Logger.w(TAG, "Error occurred in update dialog.");
-                            }
-                        }
-                    } else {
-                        if (showUpToDateToast) {
-                            withContext(Dispatchers.Main) {
-                                UIDialogs.toast(context, "Already on latest version");
-                            }
+                if (latestVersion > currentVersion) {
+                    withContext(Dispatchers.Main) {
+                        try {
+                            UIDialogs.showUpdateAvailableDialog(context, latestVersion);
+                        } catch (e: Throwable) {
+                            UIDialogs.toast(context, "Failed to show update dialog");
+                            Logger.w(TAG, "Error occurred in update dialog.");
                         }
                     }
                 } else {
-                    Logger.w(TAG, "Failed to retrieve version from version URL.");
-
-                    withContext(Dispatchers.Main) {
-                        UIDialogs.toast(context, "Failed to retrieve version");
+                    if (showUpToDateToast) {
+                        withContext(Dispatchers.Main) {
+                            UIDialogs.toast(context, "Already on latest version");
+                        }
                     }
                 }
-            } catch (e: Throwable) {
-                Logger.w(TAG, "Failed to check for updates.", e);
+            } else {
+                Logger.w(TAG, "Failed to retrieve version from version URL.");
 
                 withContext(Dispatchers.Main) {
-                    UIDialogs.toast(context, "Failed to check for updates");
+                    UIDialogs.toast(context, "Failed to retrieve version");
                 }
             }
-        };
+        } catch (e: Throwable) {
+            Logger.w(TAG, "Failed to check for updates.", e);
+
+            withContext(Dispatchers.Main) {
+                UIDialogs.toast(context, "Failed to check for updates");
+            }
+        }
     }
 
     private fun downloadApkToFile(client: ManagedHttpClient, destinationFile: File, isCancelled: (() -> Boolean)? = null) {
diff --git a/app/src/main/java/com/futo/platformplayer/views/adapters/DisabledSourceAdapter.kt b/app/src/main/java/com/futo/platformplayer/views/adapters/DisabledSourceAdapter.kt
deleted file mode 100644
index 4ce526461ee94efc87aec76ce41a689a25ba9811..0000000000000000000000000000000000000000
--- a/app/src/main/java/com/futo/platformplayer/views/adapters/DisabledSourceAdapter.kt
+++ /dev/null
@@ -1,42 +0,0 @@
-package com.futo.platformplayer.views.adapters
-
-import android.view.LayoutInflater
-import android.view.ViewGroup
-import androidx.recyclerview.widget.RecyclerView
-import com.futo.platformplayer.R
-import com.futo.platformplayer.api.media.IPlatformClient
-import com.futo.platformplayer.constructs.Event1
-
-class DisabledSourceAdapter : RecyclerView.Adapter<DisabledSourceViewHolder> {
-    private val _sources: MutableList<IPlatformClient>;
-
-    var onClick = Event1<IPlatformClient>();
-    var onAdd = Event1<IPlatformClient>();
-
-    constructor(sources: MutableList<IPlatformClient>) : super() {
-        _sources = sources;
-    }
-
-    override fun getItemCount() = _sources.size
-
-    override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): DisabledSourceViewHolder {
-        val holder = DisabledSourceViewHolder(viewGroup);
-        holder.onAdd.subscribe {
-            val source = holder.source;
-            if (source != null) {
-                onAdd.emit(source);
-            }
-        }
-        holder.onClick.subscribe {
-            val source = holder.source;
-            if (source != null) {
-                onClick.emit(source);
-            }
-        };
-        return holder;
-    }
-
-    override fun onBindViewHolder(viewHolder: DisabledSourceViewHolder, position: Int) {
-        viewHolder.bind(_sources[position])
-    }
-}
diff --git a/app/src/main/java/com/futo/platformplayer/views/adapters/DisabledSourceView.kt b/app/src/main/java/com/futo/platformplayer/views/adapters/DisabledSourceView.kt
index 83cc2d951342f3e3db4c9fb3d37050e17f8122f3..a7194ae73eacfbbc5bdb7aeb20ea21811645d502 100644
--- a/app/src/main/java/com/futo/platformplayer/views/adapters/DisabledSourceView.kt
+++ b/app/src/main/java/com/futo/platformplayer/views/adapters/DisabledSourceView.kt
@@ -1,17 +1,15 @@
 package com.futo.platformplayer.views.adapters
 
 import android.content.Context
-import android.view.LayoutInflater
-import android.view.ViewGroup
 import android.widget.ImageView
 import android.widget.LinearLayout
 import android.widget.TextView
-import androidx.recyclerview.widget.RecyclerView.ViewHolder
 import com.futo.platformplayer.R
 import com.futo.platformplayer.api.media.IPlatformClient
 import com.futo.platformplayer.api.media.platforms.js.JSClient
 import com.futo.platformplayer.constructs.Event0
 import com.futo.platformplayer.constructs.Event1
+import com.futo.platformplayer.states.StatePlatform
 
 class DisabledSourceView : LinearLayout {
     private val _root: LinearLayout;
@@ -38,7 +36,16 @@ class DisabledSourceView : LinearLayout {
         client.icon?.setImageView(_imageSource);
 
         _textSource.text = client.name;
-        _textSourceSubtitle.text = context.getString(R.string.tap_to_open);
+
+        if (client is JSClient && StatePlatform.instance.hasUpdateAvailable(client.config)) {
+            _textSourceSubtitle.text = context.getString(R.string.update_available_exclamation)
+            _textSourceSubtitle.setTextColor(context.getColor(R.color.light_blue_400))
+            _textSourceSubtitle.typeface = resources.getFont(R.font.inter_regular)
+        } else {
+            _textSourceSubtitle.text = context.getString(R.string.tap_to_open)
+            _textSourceSubtitle.setTextColor(context.getColor(R.color.gray_ac))
+            _textSourceSubtitle.typeface = resources.getFont(R.font.inter_extra_light)
+        }
 
         _buttonAdd.setOnClickListener { onAdd.emit(source) }
         _root.setOnClickListener { onClick.emit(); };
diff --git a/app/src/main/java/com/futo/platformplayer/views/adapters/DisabledSourceViewHolder.kt b/app/src/main/java/com/futo/platformplayer/views/adapters/DisabledSourceViewHolder.kt
deleted file mode 100644
index ed55fe62f91d977597331408586f8d2415723452..0000000000000000000000000000000000000000
--- a/app/src/main/java/com/futo/platformplayer/views/adapters/DisabledSourceViewHolder.kt
+++ /dev/null
@@ -1,44 +0,0 @@
-package com.futo.platformplayer.views.adapters
-
-import android.view.LayoutInflater
-import android.view.ViewGroup
-import android.widget.ImageView
-import android.widget.LinearLayout
-import android.widget.TextView
-import androidx.recyclerview.widget.RecyclerView.ViewHolder
-import com.futo.platformplayer.R
-import com.futo.platformplayer.api.media.IPlatformClient
-import com.futo.platformplayer.api.media.platforms.js.JSClient
-import com.futo.platformplayer.constructs.Event0
-
-class DisabledSourceViewHolder : ViewHolder {
-    private val _imageSource: ImageView;
-    private val _textSource: TextView;
-    private val _textSourceSubtitle: TextView;
-
-    private val _buttonAdd: LinearLayout;
-
-    var onClick = Event0();
-    var onAdd = Event0();
-    var source: IPlatformClient? = null
-        private set
-
-    constructor(viewGroup: ViewGroup) : super(LayoutInflater.from(viewGroup.context).inflate(R.layout.list_source_disabled, viewGroup, false)) {
-        _imageSource = itemView.findViewById(R.id.image_source);
-        _textSource = itemView.findViewById(R.id.text_source);
-        _textSourceSubtitle = itemView.findViewById(R.id.text_source_subtitle);
-        _buttonAdd = itemView.findViewById(R.id.button_add);
-
-        val root = itemView.findViewById<LinearLayout>(R.id.root);
-        _buttonAdd.setOnClickListener { onAdd.emit() }
-        root.setOnClickListener { onClick.emit(); };
-    }
-
-    fun bind(client: IPlatformClient) {
-        client.icon?.setImageView(_imageSource);
-
-        _textSource.text = client.name;
-        _textSourceSubtitle.text = itemView.context.getString(R.string.tap_to_open);
-        source = client;
-    }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/futo/platformplayer/views/adapters/EnabledSourceViewHolder.kt b/app/src/main/java/com/futo/platformplayer/views/adapters/EnabledSourceViewHolder.kt
index 78cb55c439a437ca13a50ff06a22a3be06bbfeda..9eed743bde8ff14cb4c566b821cabce4d2e322c6 100644
--- a/app/src/main/java/com/futo/platformplayer/views/adapters/EnabledSourceViewHolder.kt
+++ b/app/src/main/java/com/futo/platformplayer/views/adapters/EnabledSourceViewHolder.kt
@@ -10,7 +10,9 @@ import androidx.recyclerview.widget.ItemTouchHelper
 import androidx.recyclerview.widget.RecyclerView.ViewHolder
 import com.futo.platformplayer.R
 import com.futo.platformplayer.api.media.IPlatformClient
+import com.futo.platformplayer.api.media.platforms.js.JSClient
 import com.futo.platformplayer.constructs.Event1
+import com.futo.platformplayer.states.StatePlatform
 
 class EnabledSourceViewHolder : ViewHolder {
     private val _imageSource: ImageView;
@@ -57,8 +59,18 @@ class EnabledSourceViewHolder : ViewHolder {
     fun bind(client: IPlatformClient) {
         client.icon?.setImageView(_imageSource);
 
-        _textSource.text = client.name;
-        _textSourceSubtitle.text = itemView.context.getString(R.string.tap_to_open);
+        _textSource.text = client.name
+
+        if (client is JSClient && StatePlatform.instance.hasUpdateAvailable(client.config)) {
+            _textSourceSubtitle.text = itemView.context.getString(R.string.update_available_exclamation)
+            _textSourceSubtitle.setTextColor(itemView.context.getColor(R.color.light_blue_400))
+            _textSourceSubtitle.typeface = itemView.resources.getFont(R.font.inter_regular)
+        } else {
+            _textSourceSubtitle.text = itemView.context.getString(R.string.tap_to_open)
+            _textSourceSubtitle.setTextColor(itemView.context.getColor(R.color.gray_ac))
+            _textSourceSubtitle.typeface = itemView.resources.getFont(R.font.inter_extra_light)
+        }
+
         source = client
     }
 }
\ No newline at end of file
diff --git a/app/src/main/java/com/futo/platformplayer/views/sources/SourceHeaderView.kt b/app/src/main/java/com/futo/platformplayer/views/sources/SourceHeaderView.kt
index 2b0c4e10d9ba8d060be5ac3d02049225777859e3..614f7d069b20b904d73f19cbb79d051ef77fc514 100644
--- a/app/src/main/java/com/futo/platformplayer/views/sources/SourceHeaderView.kt
+++ b/app/src/main/java/com/futo/platformplayer/views/sources/SourceHeaderView.kt
@@ -25,6 +25,7 @@ class SourceHeaderView : LinearLayout {
     private val _sourcePlatformUrl: TextView;
     private val _sourceRepositoryUrl: TextView;
     private val _sourceScriptUrl: TextView;
+    private val _sourceScriptConfig: TextView;
     private val _sourceSignature: TextView;
 
     private val _sourcePlatformUrlContainer: LinearLayout;
@@ -45,6 +46,7 @@ class SourceHeaderView : LinearLayout {
         _sourcePlatformUrl = findViewById(R.id.source_platform);
         _sourcePlatformUrlContainer = findViewById(R.id.source_platform_container);
         _sourceScriptUrl = findViewById(R.id.source_script);
+        _sourceScriptConfig = findViewById(R.id.source_config);
         _sourceSignature = findViewById(R.id.source_signature);
 
         _sourceBy.setOnClickListener {
@@ -59,6 +61,10 @@ class SourceHeaderView : LinearLayout {
             if(!_config?.absoluteScriptUrl.isNullOrEmpty())
                 context.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(_config?.absoluteScriptUrl)));
         };
+        _sourceScriptConfig.setOnClickListener {
+            if(!_config?.sourceUrl.isNullOrEmpty())
+                context.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(_config?.sourceUrl)));
+        }
         _sourcePlatformUrl.setOnClickListener {
             if(!_config?.platformUrl.isNullOrEmpty())
                 context.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(_config?.platformUrl)));
@@ -82,6 +88,7 @@ class SourceHeaderView : LinearLayout {
         _sourceVersion.text = config.version.toString();
         _sourceScriptUrl.text = config.absoluteScriptUrl;
         _sourceRepositoryUrl.text = config.repositoryUrl;
+        _sourceScriptConfig.text = config.sourceUrl
         _sourceAuthorID.text = "";
 
         _sourcePlatformUrl.text = config.platformUrl ?: "";
diff --git a/app/src/main/res/layout/view_source_header.xml b/app/src/main/res/layout/view_source_header.xml
index 2042fa4836be758883e5a88a18efd47689422561..6a62c45b25926657f1b0ffb1d116ee852ef68cc7 100644
--- a/app/src/main/res/layout/view_source_header.xml
+++ b/app/src/main/res/layout/view_source_header.xml
@@ -170,6 +170,28 @@
             tools:text="https://some.repository.url/whatever/someScript.js" />
     </LinearLayout>
 
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical">
+        <TextView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:textSize="14dp"
+            android:textColor="@color/white"
+            android:layout_marginTop="10dp"
+            android:fontFamily="@font/inter_light"
+            android:text="@string/config_url" />
+        <TextView
+            android:id="@+id/source_config"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:textSize="14dp"
+            android:textColor="@color/colorPrimary"
+            android:fontFamily="@font/inter_extra_light"
+            tools:text="https://some.repository.url/whatever/someScript.js" />
+    </LinearLayout>
+
     <!--Script Url-->
     <LinearLayout
         android:layout_width="match_parent"
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 6ae83fe2210b4d717178b0c6f5befcd28e291d02..d4f1b6d18317a8c439090e1263d11fb79a579e03 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -113,6 +113,7 @@
     <string name="platform_url">Platform URL</string>
     <string name="repository_url">Repository URL</string>
     <string name="script_url">Script URL</string>
+    <string name="config_url">Config URL</string>
     <string name="source_permissions_explanation">These are the permissions the plugin requires to function</string>
     <string name="source_explain_eval_access">The plugin will have access to eval capacity</string>
     <string name="source_explain_script_url">The plugin will have access to the following domains</string>
@@ -651,6 +652,7 @@
     <string name="please_use_at_least_3_characters">Please use at least 3 characters</string>
     <string name="are_you_sure_you_want_to_delete_this_video">Are you sure you want to delete this video?</string>
     <string name="tap_to_open">Tap to open</string>
+    <string name="update_available_exclamation">Update available!</string>
     <string name="watching">watching</string>
     <string name="available_in">available in</string>
     <string name="seconds">seconds</string>
diff --git a/app/src/stable/assets/sources/odysee b/app/src/stable/assets/sources/odysee
index a21ad56829b0f0b45bbd677979f3d260e13abb34..206d996801b9734cae13093859375c70be980a8d 160000
--- a/app/src/stable/assets/sources/odysee
+++ b/app/src/stable/assets/sources/odysee
@@ -1 +1 @@
-Subproject commit a21ad56829b0f0b45bbd677979f3d260e13abb34
+Subproject commit 206d996801b9734cae13093859375c70be980a8d
diff --git a/app/src/unstable/assets/sources/odysee b/app/src/unstable/assets/sources/odysee
index a21ad56829b0f0b45bbd677979f3d260e13abb34..206d996801b9734cae13093859375c70be980a8d 160000
--- a/app/src/unstable/assets/sources/odysee
+++ b/app/src/unstable/assets/sources/odysee
@@ -1 +1 @@
-Subproject commit a21ad56829b0f0b45bbd677979f3d260e13abb34
+Subproject commit 206d996801b9734cae13093859375c70be980a8d