diff --git a/changedetectionio/blueprint/watchlist/templates/watch-overview.html b/changedetectionio/blueprint/watchlist/templates/watch-overview.html index effc2427..658cd366 100644 --- a/changedetectionio/blueprint/watchlist/templates/watch-overview.html +++ b/changedetectionio/blueprint/watchlist/templates/watch-overview.html @@ -389,7 +389,7 @@ window.watchOverviewI18n = {
{# Intersection Observer lazy loading: store real URL in data-src, load only when visible in viewport #} - Favicon thumbnail
- {%- set effective_fetcher = watch.get_fetch_backend if watch.get_fetch_backend != "system" else system_default_fetcher -%} + {%- set _fb = watch.get_fetch_backend if watch.get_fetch_backend != "system" else system_default_fetcher -%} + {# The watch may store a browser-config id - resolve it to the underlying engine so the status icon (built-in or plugin) matches by engine name. #} + {%- set _bc = datastore.browser_config_store.get(_fb) -%} + {%- set effective_fetcher = _bc.base_fetcher if _bc else _fb -%} {%- if effective_fetcher and ("html_webdriver" in effective_fetcher or "html_" in effective_fetcher or "extra_browser_" in effective_fetcher) -%} {{ effective_fetcher|fetcher_status_icons }} {%- endif -%} diff --git a/changedetectionio/content_fetchers/puppeteer.py b/changedetectionio/content_fetchers/puppeteer.py index b163332a..41775ce1 100644 --- a/changedetectionio/content_fetchers/puppeteer.py +++ b/changedetectionio/content_fetchers/puppeteer.py @@ -181,7 +181,7 @@ class fetcher(Fetcher): proxy = None # Capability flags - supports_browser_steps = True + supports_browser_steps = True # @note Not really, it actually starts a playwright session. supports_screenshots = True supports_xpath_element_data = True supports_request_blocking = True diff --git a/changedetectionio/pluggy_interface.py b/changedetectionio/pluggy_interface.py index 6b5a036d..d9f18468 100644 --- a/changedetectionio/pluggy_interface.py +++ b/changedetectionio/pluggy_interface.py @@ -456,10 +456,14 @@ def get_fetcher_capabilities(watch, datastore): 'supports_xpath_element_data': bool } """ - # Resolve the watch's fetch_backend (which may be a browser-config id, engine name or - # 'system') to the concrete engine name via the shared browser-config helper. - from changedetectionio.model.browser_config import base_fetcher_for - fetcher_name = base_fetcher_for(watch.get('fetch_backend', 'system'), datastore) + # Resolve the EFFECTIVE browser to a concrete engine name, mirroring resolve_content_fetcher: + # a group override wins over the watch's own fetch_backend. Then map that (browser-config id, + # engine name or 'system') to the engine so capability checks (Visual Selector etc.) reflect + # what will actually fetch the page. + from changedetectionio.model.browser_config import base_fetcher_for, resolve_browser_config_override + override = resolve_browser_config_override(watch, datastore) + selected = override['config_id'] if override else watch.get('fetch_backend', 'system') + fetcher_name = base_fetcher_for(selected, datastore) # Get the fetcher class from changedetectionio import content_fetchers diff --git a/changedetectionio/tests/test_browser_config.py b/changedetectionio/tests/test_browser_config.py index d9aa8ca0..e3d9e71a 100644 --- a/changedetectionio/tests/test_browser_config.py +++ b/changedetectionio/tests/test_browser_config.py @@ -92,6 +92,10 @@ def test_watch_browser_picker_and_resolution(client, live_server, measure_memory follow_redirects=True) assert datastore.data['watching'][uuid]['fetch_backend'] == cid + # Watchlist renders fine for a watch whose fetch_backend is a browser-config id - the + # status icon resolves to the underlying base engine (html_webdriver) as before. + assert client.get(url_for("watchlist.index")).status_code == 200 + # Resolver maps the browser id -> engine + FetcherConfig _cls, backend_name, _url, browser_config = resolve_content_fetcher(datastore.data['watching'][uuid], datastore) assert backend_name == 'html_webdriver' @@ -251,6 +255,13 @@ def test_group_browser_config_override(client, live_server, measure_memory_usage assert browser_config.locale == 'fr-FR' assert browser_config.viewport_width == 375 + # Capabilities (used to gate the Visual Selector tab) must reflect the OVERRIDING browser's + # engine, not the watch's own fetch_backend - the user browser is html_webdriver here. + from changedetectionio.pluggy_interface import get_fetcher_capabilities + caps = get_fetcher_capabilities(datastore.data['watching'][uuid], datastore) + assert caps['supports_screenshots'] is True + assert caps['supports_xpath_element_data'] is True + def test_group_override_with_builtin_browser(client, live_server, measure_memory_usage, datastore_path): """A group can also override with a built-in engine (e.g. html_webdriver), not just a user browser."""