From 02de7e36e72819491b757b828b33f63719b60b9d Mon Sep 17 00:00:00 2001 From: dgtlmoon Date: Wed, 7 May 2025 18:24:01 +0200 Subject: [PATCH] WIP --- changedetectionio/blueprint/ui/__init__.py | 10 +++++--- changedetectionio/blueprint/ui/views.py | 2 +- changedetectionio/custom_queue.py | 27 +++++++++++++++++++++ changedetectionio/flask_app.py | 5 ++-- changedetectionio/model/Watch.py | 6 +++++ changedetectionio/realtime/socket_server.py | 2 +- changedetectionio/store.py | 5 ++++ 7 files changed, 49 insertions(+), 8 deletions(-) create mode 100644 changedetectionio/custom_queue.py diff --git a/changedetectionio/blueprint/ui/__init__.py b/changedetectionio/blueprint/ui/__init__.py index fb685435..35b24cbe 100644 --- a/changedetectionio/blueprint/ui/__init__.py +++ b/changedetectionio/blueprint/ui/__init__.py @@ -8,7 +8,7 @@ from changedetectionio.blueprint.ui.edit import construct_blueprint as construct from changedetectionio.blueprint.ui.notification import construct_blueprint as construct_notification_blueprint from changedetectionio.blueprint.ui.views import construct_blueprint as construct_views_blueprint -def construct_blueprint(datastore: ChangeDetectionStore, update_q, running_update_threads, queuedWatchMetaData): +def construct_blueprint(datastore: ChangeDetectionStore, update_q, running_update_threads, queuedWatchMetaData, watch_check_completed): ui_blueprint = Blueprint('ui', __name__, template_folder="templates") # Register the edit blueprint @@ -20,7 +20,7 @@ def construct_blueprint(datastore: ChangeDetectionStore, update_q, running_updat ui_blueprint.register_blueprint(notification_blueprint) # Register the views blueprint - views_blueprint = construct_views_blueprint(datastore, update_q, queuedWatchMetaData) + views_blueprint = construct_views_blueprint(datastore, update_q, queuedWatchMetaData, watch_check_completed) ui_blueprint.register_blueprint(views_blueprint) # Import the login decorator @@ -35,7 +35,6 @@ def construct_blueprint(datastore: ChangeDetectionStore, update_q, running_updat flash('Watch not found', 'error') else: flash("Cleared snapshot history for watch {}".format(uuid)) - return redirect(url_for('watchlist.index')) @ui_blueprint.route("/clear_history", methods=['GET', 'POST']) @@ -47,7 +46,6 @@ def construct_blueprint(datastore: ChangeDetectionStore, update_q, running_updat if confirmtext == 'clear': for uuid in datastore.data['watching'].keys(): datastore.clear_watch_history(uuid) - flash("Cleared snapshot history for all watches") else: flash('Incorrect confirmation text.', 'error') @@ -248,6 +246,10 @@ def construct_blueprint(datastore: ChangeDetectionStore, update_q, running_updat flash(f"{len(uuids)} watches were tagged") + if uuids: + for uuid in uuids: + watch_check_completed.send(watch_uuid=uuid) + return redirect(url_for('watchlist.index')) diff --git a/changedetectionio/blueprint/ui/views.py b/changedetectionio/blueprint/ui/views.py index 15524e58..cf8341aa 100644 --- a/changedetectionio/blueprint/ui/views.py +++ b/changedetectionio/blueprint/ui/views.py @@ -8,7 +8,7 @@ from changedetectionio.store import ChangeDetectionStore from changedetectionio.auth_decorator import login_optionally_required from changedetectionio import html_tools -def construct_blueprint(datastore: ChangeDetectionStore, update_q, queuedWatchMetaData): +def construct_blueprint(datastore: ChangeDetectionStore, update_q, queuedWatchMetaData, watch_check_completed): views_blueprint = Blueprint('ui_views', __name__, template_folder="../ui/templates") @views_blueprint.route("/preview/", methods=['GET']) diff --git a/changedetectionio/custom_queue.py b/changedetectionio/custom_queue.py new file mode 100644 index 00000000..532855bc --- /dev/null +++ b/changedetectionio/custom_queue.py @@ -0,0 +1,27 @@ +import queue +from blinker import signal + +class SignalPriorityQueue(queue.PriorityQueue): + """ + Extended PriorityQueue that sends a signal when items with a UUID are added. + + This class extends the standard PriorityQueue and adds a signal emission + after an item is put into the queue. If the item contains a UUID, the signal + is sent with that UUID as a parameter. + """ + + def __init__(self, maxsize=0): + super().__init__(maxsize) + + def put(self, item, block=True, timeout=None): + # Call the parent's put method first + super().put(item, block, timeout) + + # After putting the item in the queue, check if it has a UUID and emit signal + if hasattr(item, 'item') and isinstance(item.item, dict) and 'uuid' in item.item: + uuid = item.item['uuid'] + # Get the signal and send it if it exists + watch_check_completed = signal('watch_check_completed') + if watch_check_completed: + # Send the watch_uuid parameter + watch_check_completed.send(watch_uuid=uuid) \ No newline at end of file diff --git a/changedetectionio/flask_app.py b/changedetectionio/flask_app.py index f6392936..071296f8 100644 --- a/changedetectionio/flask_app.py +++ b/changedetectionio/flask_app.py @@ -11,6 +11,7 @@ from blinker import signal from changedetectionio.strtobool import strtobool from threading import Event +from changedetectionio.custom_queue import SignalPriorityQueue from flask import ( Flask, @@ -51,7 +52,7 @@ ticker_thread = None extra_stylesheets = [] -update_q = queue.PriorityQueue() +update_q = SignalPriorityQueue() notification_q = queue.Queue() MAX_QUEUE_SIZE = 2000 @@ -456,7 +457,7 @@ def changedetection_app(config=None, datastore_o=None): # watchlist UI buttons etc import changedetectionio.blueprint.ui as ui - app.register_blueprint(ui.construct_blueprint(datastore, update_q, running_update_threads, queuedWatchMetaData)) + app.register_blueprint(ui.construct_blueprint(datastore, update_q, running_update_threads, queuedWatchMetaData, watch_check_completed)) import changedetectionio.blueprint.watchlist as watchlist app.register_blueprint(watchlist.construct_blueprint(datastore=datastore, update_q=update_q, queuedWatchMetaData=queuedWatchMetaData), url_prefix='') diff --git a/changedetectionio/model/Watch.py b/changedetectionio/model/Watch.py index 4d03978b..10848a04 100644 --- a/changedetectionio/model/Watch.py +++ b/changedetectionio/model/Watch.py @@ -1,3 +1,5 @@ +from blinker import signal + from changedetectionio.strtobool import strtobool from changedetectionio.safe_jinja import render as jinja_render from . import watch_base @@ -124,6 +126,10 @@ class model(watch_base): 'remote_server_reply': None, 'track_ldjson_price_data': None }) + watch_check_completed = signal('watch_check_completed') + if watch_check_completed: + watch_check_completed.send(watch_uuid=self.get('uuid')) + return @property diff --git a/changedetectionio/realtime/socket_server.py b/changedetectionio/realtime/socket_server.py index d7801154..91a89432 100644 --- a/changedetectionio/realtime/socket_server.py +++ b/changedetectionio/realtime/socket_server.py @@ -105,7 +105,7 @@ class ChangeDetectionSocketIO: 'unviewed': watch.has_unviewed, } self.socketio.emit("watch_update", watch_data) - logger.debug(f"Socket.IO: Emitted update for watch {watch.uuid}") + logger.debug(f"Socket.IO: Emitted update for watch {watch.get('uuid')}") except Exception as e: logger.error(f"Socket.IO error in handle_watch_update: {str(e)}") diff --git a/changedetectionio/store.py b/changedetectionio/store.py index 461fb1b1..7ee4c00c 100644 --- a/changedetectionio/store.py +++ b/changedetectionio/store.py @@ -17,6 +17,7 @@ import threading import time import uuid as uuid_builder from loguru import logger +from blinker import signal from .processors import get_custom_watch_obj_for_processor from .processors.restock_diff import Restock @@ -166,6 +167,10 @@ class ChangeDetectionStore: self.data['watching'][uuid].update({'last_viewed': int(timestamp)}) self.needs_write = True + watch_check_completed = signal('watch_check_completed') + if watch_check_completed: + watch_check_completed.send(watch_uuid=uuid) + def remove_password(self): self.__data['settings']['application']['password'] = False self.needs_write = True