From 316cca090113730650f57f600c2a14e3b840dfa2 Mon Sep 17 00:00:00 2001 From: dgtlmoon Date: Wed, 26 Mar 2025 16:07:17 +0100 Subject: [PATCH 1/2] Set a graph % of ETA time completed of checking the watch --- .../blueprint/watchlist/__init__.py | 7 ++--- .../watchlist/templates/watch-overview.html | 28 +++++++++++++++---- changedetectionio/flask_app.py | 12 +++++--- changedetectionio/static/js/watch-overview.js | 27 ++++++++++++++++++ changedetectionio/update_worker.py | 10 +++---- 5 files changed, 64 insertions(+), 20 deletions(-) diff --git a/changedetectionio/blueprint/watchlist/__init__.py b/changedetectionio/blueprint/watchlist/__init__.py index fb57b2ee427..300eeebdcde 100644 --- a/changedetectionio/blueprint/watchlist/__init__.py +++ b/changedetectionio/blueprint/watchlist/__init__.py @@ -1,7 +1,5 @@ -import flask_login import os import time -import timeago from flask import Blueprint, request, make_response, render_template, redirect, url_for, flash, session from flask_login import current_user @@ -10,7 +8,6 @@ from changedetectionio import forms from changedetectionio.store import ChangeDetectionStore from changedetectionio.auth_decorator import login_optionally_required -from changedetectionio.strtobool import strtobool def construct_blueprint(datastore: ChangeDetectionStore, update_q, queuedWatchMetaData): watchlist_blueprint = Blueprint('watchlist', __name__, template_folder="templates") @@ -77,7 +74,6 @@ def index(): sorted_tags = sorted(datastore.data['settings']['application'].get('tags').items(), key=lambda x: x[1]['title']) output = render_template( "watch-overview.html", - # Don't link to hosting when we're on the hosting environment active_tag=active_tag, active_tag_uuid=active_tag_uuid, app_rss_token=datastore.data['settings']['application'].get('rss_access_token'), @@ -88,9 +84,10 @@ def index(): has_proxies=datastore.proxy_list, has_unviewed=datastore.has_unviewed, hosted_sticky=os.getenv("SALTED_PASS", False) == False, + now_time_server=time.time(), pagination=pagination, queued_uuids=[q_uuid.item['uuid'] for q_uuid in update_q.queue], - search_q=request.args.get('q','').strip(), + search_q=request.args.get('q', '').strip(), sort_attribute=request.args.get('sort') if request.args.get('sort') else request.cookies.get('sort'), sort_order=request.args.get('order') if request.args.get('order') else request.cookies.get('order'), system_default_fetcher=datastore.data['settings']['application'].get('fetch_backend'), diff --git a/changedetectionio/blueprint/watchlist/templates/watch-overview.html b/changedetectionio/blueprint/watchlist/templates/watch-overview.html index 2af9e61fde3..cd5bc2a6ec9 100644 --- a/changedetectionio/blueprint/watchlist/templates/watch-overview.html +++ b/changedetectionio/blueprint/watchlist/templates/watch-overview.html @@ -3,7 +3,16 @@ {% from '_helpers.html' import render_simple_field, render_field, render_nolabel_field, sort_by_title %} - + + +
@@ -91,8 +100,8 @@ {% endif %} {% for watch in (watches|sort(attribute=sort_attribute, reverse=sort_order == 'asc'))|pagination_slice(skip=pagination.skip) %} - {% set is_unviewed = watch.newest_history_key| int > watch.last_viewed and watch.history_n>=2 %} - + {% set is_unviewed = watch.newest_history_key| int > watch.last_viewed and watch.history_n>=2 %} + {% set checking_now = is_checking_now(watch) %} + {% if watch.uuid in queued_uuids %}queued{% endif %} + {% if checking_now %}checking-now{% endif %} + "> {{ loop.index+pagination.skip }} {% if not watch.paused %} @@ -178,7 +189,14 @@ {% endif %} {% endif %} - {{watch|format_last_checked_time|safe}} + {#last_checked becomes fetch-start-time#} + + {% if checking_now %} + Checking now + {% else %} + {{watch|format_last_checked_time|safe}} + {% endif %} + {% if watch.history_n >=2 and watch.last_changed >0 %} {{watch.last_changed|format_timestamp_timeago}} {% else %} diff --git a/changedetectionio/flask_app.py b/changedetectionio/flask_app.py index b914393730e..e7c85d91ef2 100644 --- a/changedetectionio/flask_app.py +++ b/changedetectionio/flask_app.py @@ -123,14 +123,18 @@ def _jinja2_filter_format_number_locale(value: float) -> str: return formatted_value +@app.template_global('is_checking_now') +def _watch_is_checking_now(watch_obj, format="%Y-%m-%d %H:%M:%S"): + # Worker thread tells us which UUID it is currently processing. + for t in running_update_threads: + if t.current_uuid == watch_obj['uuid']: + return True + + # We use the whole watch object from the store/JSON so we can see if there's some related status in terms of a thread # running or something similar. @app.template_filter('format_last_checked_time') def _jinja2_filter_datetime(watch_obj, format="%Y-%m-%d %H:%M:%S"): - # Worker thread tells us which UUID it is currently processing. - for t in running_update_threads: - if t.current_uuid == watch_obj['uuid']: - return ' Checking now' if watch_obj['last_checked'] == 0: return 'Not yet' diff --git a/changedetectionio/static/js/watch-overview.js b/changedetectionio/static/js/watch-overview.js index 57541dfe528..e3bc3359ae0 100644 --- a/changedetectionio/static/js/watch-overview.js +++ b/changedetectionio/static/js/watch-overview.js @@ -48,6 +48,8 @@ $(function () { $('input[type=checkbox]').not(this).prop('checked', this.checked); }); + const time_check_step_size_seconds=1; + // checkboxes - show/hide buttons $("input[type=checkbox]").click(function (e) { if ($('input[type=checkbox]:checked').length) { @@ -57,5 +59,30 @@ $(function () { } }); + setInterval(function () { + // Background ETA completion for 'checking now' + $(".watch-table .checking-now .last-checked").each(function () { + const eta_complete = parseFloat($(this).data('eta_complete')); + const fetch_duration = parseInt($(this).data('fetchduration')); + + if (eta_complete + 2 > nowtimeserver && fetch_duration > 3) { + const remaining_seconds = Math.abs(eta_complete) - nowtimeserver - 1; + + let r = (1.0 - (remaining_seconds / fetch_duration)) * 100; + if (r < 10) { + r = 10; + } + if (r >= 90) { + r = 100; + } + $(this).css('background-size', `${r}% 100%`); + //$(this).text(`${r}% remain ${remaining_seconds}`); + } else { + $(this).css('background-size', `100% 100%`); + } + }); + + nowtimeserver = nowtimeserver + time_check_step_size_seconds; + }, time_check_step_size_seconds * 1000); }); diff --git a/changedetectionio/update_worker.py b/changedetectionio/update_worker.py index 28647bada95..c92aef1d637 100644 --- a/changedetectionio/update_worker.py +++ b/changedetectionio/update_worker.py @@ -253,8 +253,9 @@ def run(self): pass else: - fetch_start_time = time.time() + uuid = queued_item_data.item.get('uuid') + fetch_start_time = time.time() # Also used for a unique history key for now self.current_uuid = uuid if uuid in list(self.datastore.data['watching'].keys()) and self.datastore.data['watching'][uuid].get('url'): changed_detected = False @@ -262,8 +263,10 @@ def run(self): process_changedetection_results = True update_obj = {} + # Clear last errors (move to preflight func?) self.datastore.data['watching'][uuid]['browser_steps_last_error_step'] = None + self.datastore.data['watching'][uuid]['last_checked'] = fetch_start_time watch = self.datastore.data['watching'].get(uuid) @@ -287,10 +290,6 @@ def run(self): update_handler.call_browser() - # In reality, the actual time of when the change was detected could be a few seconds after this - # For example it should include when the page stopped rendering if using a playwright/chrome type fetch - fetch_start_time = time.time() - changed_detected, update_obj, contents = update_handler.run_changedetection(watch=watch) # Re #342 @@ -587,7 +586,6 @@ def run(self): pass self.datastore.update_watch(uuid=uuid, update_obj={'fetch_time': round(time.time() - fetch_start_time, 3), - 'last_checked': int(fetch_start_time), 'check_count': count }) From 01dd67b1ad9ecde5c88554c451deba3f9f2d58a5 Mon Sep 17 00:00:00 2001 From: dgtlmoon Date: Wed, 26 Mar 2025 16:13:26 +0100 Subject: [PATCH 2/2] Use int --- changedetectionio/update_worker.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changedetectionio/update_worker.py b/changedetectionio/update_worker.py index c92aef1d637..38a8f73a61e 100644 --- a/changedetectionio/update_worker.py +++ b/changedetectionio/update_worker.py @@ -255,7 +255,7 @@ def run(self): else: uuid = queued_item_data.item.get('uuid') - fetch_start_time = time.time() # Also used for a unique history key for now + fetch_start_time = round(time.time()) # Also used for a unique history key for now self.current_uuid = uuid if uuid in list(self.datastore.data['watching'].keys()) and self.datastore.data['watching'][uuid].get('url'): changed_detected = False