From 10181669ba80ee2f629935d09909ad7cf757a989 Mon Sep 17 00:00:00 2001 From: dgtlmoon Date: Tue, 12 Sep 2023 15:39:10 +0200 Subject: [PATCH] WIP - Plugin architecture --- changedetectionio/processors/__init__.py | 25 +++++++++++++++++++++--- changedetectionio/store.py | 14 +++++++++++++ changedetectionio/update_worker.py | 21 ++++++++++++++++++-- 3 files changed, 55 insertions(+), 5 deletions(-) diff --git a/changedetectionio/processors/__init__.py b/changedetectionio/processors/__init__.py index 225e9c8a..d872607b 100644 --- a/changedetectionio/processors/__init__.py +++ b/changedetectionio/processors/__init__.py @@ -18,7 +18,26 @@ class difference_detection_processor(): def available_processors(): + import importlib + import pkgutil + from . import restock_diff, text_json_diff - x=[('text_json_diff', text_json_diff.name), ('restock_diff', restock_diff.name)] - # @todo Make this smarter with introspection of sorts. - return x + + processors = [('text_json_diff', text_json_diff.name), ('restock_diff', restock_diff.name)] + + discovered_plugins = { + name: importlib.import_module(name) + for finder, name, ispkg + in pkgutil.iter_modules() + if name.startswith('changedetectionio-plugin-') + } + + try: + for name, plugin in discovered_plugins.items(): + if hasattr(plugin, 'processors'): + for machine_name, desc in plugin.processors.items(): + processors.append((machine_name, desc)) + except Exception as e: + print (f"Problem fetching one or more plugins") + + return processors diff --git a/changedetectionio/store.py b/changedetectionio/store.py index a8082cd5..52032d09 100644 --- a/changedetectionio/store.py +++ b/changedetectionio/store.py @@ -126,6 +126,7 @@ class ChangeDetectionStore: self.needs_write = True + self.scan_plugins() # Finally start the thread that will manage periodic data saves to JSON save_data_thread = threading.Thread(target=self.save_datastore).start() @@ -612,6 +613,19 @@ class ChangeDetectionStore: def tag_exists_by_name(self, tag_name): return any(v.get('title', '').lower() == tag_name.lower() for k, v in self.__data['settings']['application']['tags'].items()) + def scan_plugins(self): + import importlib + import pkgutil + + discovered_plugins = { + name: importlib.import_module(name) + for finder, name, ispkg + in pkgutil.iter_modules() + if name.startswith('changedetectionio-plugin-') + } + + return discovered_plugins + # Run all updates # IMPORTANT - Each update could be run even when they have a new install and the schema is correct # So therefor - each `update_n` should be very careful about checking if it needs to actually run diff --git a/changedetectionio/update_worker.py b/changedetectionio/update_worker.py index 63a0aab4..bd119773 100644 --- a/changedetectionio/update_worker.py +++ b/changedetectionio/update_worker.py @@ -1,6 +1,8 @@ +import importlib import os -import threading +import pkgutil import queue +import threading import time from changedetectionio import content_fetcher @@ -229,13 +231,28 @@ class update_worker(threading.Thread): now = time.time() try: - processor = self.datastore.data['watching'][uuid].get('processor','text_json_diff') + processor = self.datastore.data['watching'][uuid].get('processor', 'text_json_diff') # @todo some way to switch by name if processor == 'restock_diff': update_handler = restock_diff.perform_site_check(datastore=self.datastore) else: # Used as a default and also by some tests + discovered_plugins = { + name: importlib.import_module(name) + for finder, name, ispkg + in pkgutil.iter_modules() + if name.startswith('changedetectionio-plugin-') + } + + for module_name, plugin in discovered_plugins.items(): + if hasattr(plugin, 'processors'): + for machine_name, desc in plugin.processors: + if machine_name == processor: + module = importlib.import_module(f"{module_name}.processors.{plugin}") + update_handler = module.perform_site_check(datastore=self.datastore) + #processors.append((machine_name, desc)) + update_handler = text_json_diff.perform_site_check(datastore=self.datastore) changed_detected, update_obj, contents = update_handler.run(uuid, skip_when_checksum_same=queued_item_data.item.get('skip_when_checksum_same'))