Compare commits

..

1 Commits

Author SHA1 Message Date
dgtlmoon
6eb71c9eee Realtime - Suppress socket.io errors in logs 2026-03-19 17:42:31 +01:00
5 changed files with 4 additions and 61 deletions

View File

@@ -40,13 +40,12 @@ def construct_blueprint(datastore: ChangeDetectionStore):
contents = '' contents = ''
now = time.time() now = time.time()
try: try:
import asyncio
processor_module = importlib.import_module("changedetectionio.processors.text_json_diff.processor") processor_module = importlib.import_module("changedetectionio.processors.text_json_diff.processor")
update_handler = processor_module.perform_site_check(datastore=datastore, update_handler = processor_module.perform_site_check(datastore=datastore,
watch_uuid=uuid watch_uuid=uuid
) )
asyncio.run(update_handler.call_browser(preferred_proxy_id=preferred_proxy)) update_handler.call_browser(preferred_proxy_id=preferred_proxy)
# title, size is len contents not len xfer # title, size is len contents not len xfer
except content_fetcher_exceptions.Non200ErrorCodeReceived as e: except content_fetcher_exceptions.Non200ErrorCodeReceived as e:
if e.status_code == 404: if e.status_code == 404:

View File

@@ -1,7 +1,6 @@
from babel.numbers import parse_decimal from babel.numbers import parse_decimal
from changedetectionio.model.Watch import model as BaseWatch from changedetectionio.model.Watch import model as BaseWatch
from decimal import Decimal, InvalidOperation
from typing import Union from typing import Union
import re import re
@@ -11,8 +10,6 @@ supports_browser_steps = True
supports_text_filters_and_triggers = True supports_text_filters_and_triggers = True
supports_text_filters_and_triggers_elements = True supports_text_filters_and_triggers_elements = True
supports_request_type = True supports_request_type = True
_price_re = re.compile(r"Price:\s*(\d+(?:\.\d+)?)", re.IGNORECASE)
class Restock(dict): class Restock(dict):
@@ -66,17 +63,6 @@ class Restock(dict):
super().__setitem__(key, value) super().__setitem__(key, value)
def get_price_from_history_str(history_str):
m = _price_re.search(history_str)
if not m:
return None
try:
return str(Decimal(m.group(1)))
except InvalidOperation:
return None
class Watch(BaseWatch): class Watch(BaseWatch):
def __init__(self, *arg, **kw): def __init__(self, *arg, **kw):
super().__init__(*arg, **kw) super().__init__(*arg, **kw)
@@ -90,27 +76,13 @@ class Watch(BaseWatch):
def extra_notification_token_values(self): def extra_notification_token_values(self):
values = super().extra_notification_token_values() values = super().extra_notification_token_values()
values['restock'] = self.get('restock', {}) values['restock'] = self.get('restock', {})
values['restock']['previous_price'] = None
if self.history_n >= 2:
history = self.history
if history and len(history) >=2:
"""Unfortunately for now timestamp is stored as string key"""
sorted_keys = sorted(list(history), key=lambda x: int(x))
sorted_keys.reverse()
price_str = self.get_history_snapshot(timestamp=sorted_keys[-1])
if price_str:
values['restock']['previous_price'] = get_price_from_history_str(price_str)
return values return values
def extra_notification_token_placeholder_info(self): def extra_notification_token_placeholder_info(self):
values = super().extra_notification_token_placeholder_info() values = super().extra_notification_token_placeholder_info()
values.append(('restock.price', "Price detected")) values.append(('restock.price', "Price detected"))
values.append(('restock.in_stock', "In stock status"))
values.append(('restock.original_price', "Original price at first check")) values.append(('restock.original_price', "Original price at first check"))
values.append(('restock.previous_price', "Previous price in history"))
return values return values

View File

@@ -422,28 +422,3 @@ def test_plaintext_even_if_xml_content_and_can_apply_filters(client, live_server
assert b'<foobar' not in res.data assert b'<foobar' not in res.data
res = delete_all_watches(client) res = delete_all_watches(client)
def test_last_error_cleared_on_same_checksum(client, live_server, datastore_path):
"""last_error should be cleared even when content is unchanged (checksumFromPreviousCheckWasTheSame path)"""
set_original_response(datastore_path=datastore_path)
uuid = client.application.config.get('DATASTORE').add_watch(url=url_for('test_endpoint', _external=True))
# First check - establishes baseline checksum
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
# Inject a stale last_error directly (simulates a prior failed check)
datastore = client.application.config.get('DATASTORE')
datastore.update_watch(uuid=uuid, update_obj={'last_error': 'Some previous error'})
assert datastore.data['watching'][uuid].get('last_error') == 'Some previous error'
# Second check - same content, so checksumFromPreviousCheckWasTheSame will fire
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
# last_error must be cleared even though no change was detected
assert datastore.data['watching'][uuid].get('last_error') == False
delete_all_watches(client)

View File

@@ -350,7 +350,6 @@ def test_change_with_notification_values(client, live_server, measure_memory_usa
res = client.get(url_for("settings.settings_page")) res = client.get(url_for("settings.settings_page"))
assert b'{{restock.original_price}}' in res.data assert b'{{restock.original_price}}' in res.data
assert b'{{restock.previous_price}}' in res.data
assert b'Original price at first check' in res.data assert b'Original price at first check' in res.data
##################### #####################
@@ -359,7 +358,7 @@ def test_change_with_notification_values(client, live_server, measure_memory_usa
url_for("settings.settings_page"), url_for("settings.settings_page"),
data={"application-notification_urls": notification_url, data={"application-notification_urls": notification_url,
"application-notification_title": "title new price {{restock.price}}", "application-notification_title": "title new price {{restock.price}}",
"application-notification_body": "new price {{restock.price}} previous price {{restock.previous_price}} instock {{restock.in_stock}}", "application-notification_body": "new price {{restock.price}}",
"application-notification_format": default_notification_format, "application-notification_format": default_notification_format,
"requests-time_between_check-minutes": 180, "requests-time_between_check-minutes": 180,
'application-fetch_backend': "html_requests"}, 'application-fetch_backend': "html_requests"},
@@ -373,6 +372,8 @@ def test_change_with_notification_values(client, live_server, measure_memory_usa
assert b"Settings updated." in res.data assert b"Settings updated." in res.data
set_original_response(props_markup=instock_props[0], price='960.45', datastore_path=datastore_path)
# A change in price, should trigger a change by default # A change in price, should trigger a change by default
set_original_response(props_markup=instock_props[0], price='1950.45', datastore_path=datastore_path) set_original_response(props_markup=instock_props[0], price='1950.45', datastore_path=datastore_path)
client.get(url_for("ui.form_watch_checknow")) client.get(url_for("ui.form_watch_checknow"))
@@ -383,7 +384,6 @@ def test_change_with_notification_values(client, live_server, measure_memory_usa
notification = f.read() notification = f.read()
assert "new price 1950.45" in notification assert "new price 1950.45" in notification
assert "title new price 1950.45" in notification assert "title new price 1950.45" in notification
assert "previous price 960.45" in notification
## Now test the "SEND TEST NOTIFICATION" is working ## Now test the "SEND TEST NOTIFICATION" is working
os.unlink(os.path.join(datastore_path, "notification.txt")) os.unlink(os.path.join(datastore_path, "notification.txt"))

View File

@@ -284,9 +284,6 @@ async def async_update_worker(worker_id, q, notification_q, app, datastore, exec
logger.debug(f'[{uuid}] - checksumFromPreviousCheckWasTheSame - Checksum from previous check was the same, nothing todo here.') logger.debug(f'[{uuid}] - checksumFromPreviousCheckWasTheSame - Checksum from previous check was the same, nothing todo here.')
# Reset the edited flag since we successfully completed the check # Reset the edited flag since we successfully completed the check
watch.reset_watch_edited_flag() watch.reset_watch_edited_flag()
# Page was fetched successfully - clear any previous error state
datastore.update_watch(uuid=uuid, update_obj={'last_error': False})
cleanup_error_artifacts(uuid, datastore)
except content_fetchers_exceptions.BrowserConnectError as e: except content_fetchers_exceptions.BrowserConnectError as e:
datastore.update_watch(uuid=uuid, datastore.update_watch(uuid=uuid,