From f0eb4b8d1f085848722de1ba869fd47ce869aefa Mon Sep 17 00:00:00 2001 From: dgtlmoon Date: Mon, 24 Nov 2025 16:50:09 +0100 Subject: [PATCH] WIP --- .../blueprint/settings/__init__.py | 8 ++++ .../settings/templates/settings.html | 15 +++++++- .../conditions/plugins/levenshtein_plugin.py | 4 ++ .../conditions/plugins/wordcount_plugin.py | 4 ++ changedetectionio/pluggy_interface.py | 38 +++++++++++++++++++ 5 files changed, 68 insertions(+), 1 deletion(-) 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 %} + + {% 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.