diff --git a/changedetectionio/blueprint/settings/__init__.py b/changedetectionio/blueprint/settings/__init__.py
index 2396d566..3c90538e 100644
--- a/changedetectionio/blueprint/settings/__init__.py
+++ b/changedetectionio/blueprint/settings/__init__.py
@@ -110,8 +110,16 @@ def construct_blueprint(datastore: ChangeDetectionStore):
# Convert to ISO 8601 format, all date/time relative events stored as UTC time
utc_time = datetime.now(ZoneInfo("UTC")).isoformat()
+ # Get active plugins
+ from changedetectionio.pluggy_interface import get_active_plugins
+ import sys
+ active_plugins = get_active_plugins()
+ python_version = f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}"
+
output = render_template("settings.html",
+ active_plugins=active_plugins,
api_key=datastore.data['settings']['application'].get('api_access_token'),
+ python_version=python_version,
available_timezones=sorted(available_timezones()),
emailprefix=os.getenv('NOTIFICATION_MAIL_BUTTON_PREFIX', False),
extra_notification_token_placeholder_info=datastore.get_unique_notification_token_placeholders_available(),
diff --git a/changedetectionio/blueprint/settings/templates/settings.html b/changedetectionio/blueprint/settings/templates/settings.html
index ce13ef00..5fbbda4d 100644
--- a/changedetectionio/blueprint/settings/templates/settings.html
+++ b/changedetectionio/blueprint/settings/templates/settings.html
@@ -27,6 +27,7 @@
RSS
Time & Date
CAPTCHA & Proxies
+ Info
@@ -352,7 +353,19 @@ nav
{{ render_fieldlist_with_inline_errors(form.requests.form.extra_browsers) }}
-
+
+
+
Python version: {{ python_version }}
+
Plugins active:
+ {% if active_plugins %}
+
+ {% for plugin in active_plugins %}
+ - {{ plugin.name }} - {{ plugin.description }}
+ {% endfor %}
+
+ {% else %}
+
No plugins active
+ {% endif %}
diff --git a/changedetectionio/conditions/plugins/levenshtein_plugin.py b/changedetectionio/conditions/plugins/levenshtein_plugin.py
index c3e843ea..67dc256c 100644
--- a/changedetectionio/conditions/plugins/levenshtein_plugin.py
+++ b/changedetectionio/conditions/plugins/levenshtein_plugin.py
@@ -1,3 +1,7 @@
+"""
+Levenshtein distance and similarity plugin for text change detection.
+Provides metrics for measuring text similarity between snapshots.
+"""
import pluggy
from loguru import logger
diff --git a/changedetectionio/conditions/plugins/wordcount_plugin.py b/changedetectionio/conditions/plugins/wordcount_plugin.py
index 8b3e89fa..4db9cb9a 100644
--- a/changedetectionio/conditions/plugins/wordcount_plugin.py
+++ b/changedetectionio/conditions/plugins/wordcount_plugin.py
@@ -1,3 +1,7 @@
+"""
+Word count plugin for content analysis.
+Provides word count metrics for snapshot content.
+"""
import pluggy
from loguru import logger
diff --git a/changedetectionio/pluggy_interface.py b/changedetectionio/pluggy_interface.py
index 06a3c3a0..3cfc935c 100644
--- a/changedetectionio/pluggy_interface.py
+++ b/changedetectionio/pluggy_interface.py
@@ -232,6 +232,44 @@ def get_itemprop_availability_from_plugin(content, fetcher_name, fetcher_instanc
return None
+def get_active_plugins():
+ """Get a list of active plugins with their descriptions.
+
+ Returns:
+ list: List of dictionaries with plugin information:
+ [
+ {'name': 'plugin_name', 'description': 'Plugin description'},
+ ...
+ ]
+ """
+ active_plugins = []
+
+ # Get all registered plugins
+ for plugin_name, plugin_obj in plugin_manager.list_name_plugin():
+ # Skip built-in plugins (they start with 'builtin_')
+ if plugin_name.startswith('builtin_'):
+ continue
+
+ # Get plugin description if available
+ description = None
+ if hasattr(plugin_obj, '__doc__') and plugin_obj.__doc__:
+ description = plugin_obj.__doc__.strip().split('\n')[0] # First line only
+ elif hasattr(plugin_obj, 'description'):
+ description = plugin_obj.description
+
+ # Try to get a friendly name from the plugin
+ friendly_name = plugin_name
+ if hasattr(plugin_obj, 'name'):
+ friendly_name = plugin_obj.name
+
+ active_plugins.append({
+ 'name': friendly_name,
+ 'description': description or 'No description available'
+ })
+
+ return active_plugins
+
+
def get_fetcher_capabilities(watch, datastore):
"""Get capability flags for a watch's fetcher.