From 26420503af3a5c10c3bd57c074168e4e7fc6718c Mon Sep 17 00:00:00 2001 From: dgtlmoon Date: Wed, 10 Sep 2025 12:14:28 +0200 Subject: [PATCH] WIP --- .../settings/templates/settings.html | 17 ++++----- .../watchlist/templates/watch-overview.html | 13 +++++-- changedetectionio/forms.py | 6 +-- changedetectionio/model/App.py | 2 +- changedetectionio/store.py | 2 +- changedetectionio/tests/test_backend.py | 37 +++++++++---------- 6 files changed, 40 insertions(+), 37 deletions(-) diff --git a/changedetectionio/blueprint/settings/templates/settings.html b/changedetectionio/blueprint/settings/templates/settings.html index db4512dde..bf0ab4fc0 100644 --- a/changedetectionio/blueprint/settings/templates/settings.html +++ b/changedetectionio/blueprint/settings/templates/settings.html @@ -75,20 +75,12 @@
{{ render_checkbox_field(form.application.form.rss_hide_muted_watches) }}
-
- {{ render_field(form.application.form.pager_size) }} - Number of items per page in the watch overview list, 0 to disable. -
{{ render_field(form.application.form.rss_content_format) }} Love RSS? Does your reader support HTML? Set it here
- {{ render_ternary_field(form.application.form.use_page_title_in_list, BooleanField=true) }} - Note: This will automatically apply to all existing watches. -
-
- {{ render_ternary_field(form.application.form.empty_pages_are_a_change, BooleanField=true) }} + {{ render_checkbox_field(form.application.form.empty_pages_are_a_change) }} When a request returns no content, or the HTML does not contain any text, is this considered a change?
{% if form.requests.proxy %} @@ -260,6 +252,13 @@ nav {{ render_checkbox_field(form.application.form.ui.form.favicons_enabled, class="") }} Enable or Disable Favicons next to the watch list +
+ {{ render_checkbox_field(form.application.form.ui.use_page_title_in_list) }} +
+
+ {{ render_field(form.application.form.pager_size) }} + Number of items per page in the watch overview list, 0 to disable. +
diff --git a/changedetectionio/blueprint/watchlist/templates/watch-overview.html b/changedetectionio/blueprint/watchlist/templates/watch-overview.html index bf6d14d1d..d4483c3b2 100644 --- a/changedetectionio/blueprint/watchlist/templates/watch-overview.html +++ b/changedetectionio/blueprint/watchlist/templates/watch-overview.html @@ -118,7 +118,8 @@ document.addEventListener('DOMContentLoaded', function() { {%- set checking_now = is_checking_now(watch) -%} {%- set history_n = watch.history_n -%} {%- set favicon = watch.get_favicon_filename() -%} - {# Mirror in changedetectionio/static/js/realtime.js for the frontend #} + {%- set system_use_url_watchlist = datastore.data['settings']['application']['ui'].get('use_page_title_in_list') -%} + {# Class settings mirrored in changedetectionio/static/js/realtime.js for the frontend #} {%- set row_classes = [ loop.cycle('pure-table-odd', 'pure-table-even'), 'processor-' ~ watch['processor'], @@ -133,7 +134,8 @@ document.addEventListener('DOMContentLoaded', function() { 'checking-now' if checking_now else '', 'notification_muted' if watch.notification_muted else '', 'single-history' if history_n == 1 else '', - 'multiple-history' if history_n >= 2 else '', + 'multiple-history' if history_n >= 2 else '', + 'use-html-title' if system_use_url_watchlist else 'no-html-title', ] -%}
{{ loop.index+pagination.skip }}
@@ -155,7 +157,12 @@ document.addEventListener('DOMContentLoaded', function() { {% endif %}
- {{watch.label}}   + {% if system_use_url_watchlist or watch.get('use_page_title_in_list') %} + {{watch.label}} + {% else %} + {{watch.url}} + {% endif %} +   {%- if watch['processor'] == 'text_json_diff' -%} diff --git a/changedetectionio/forms.py b/changedetectionio/forms.py index eec4ade40..fa111f426 100644 --- a/changedetectionio/forms.py +++ b/changedetectionio/forms.py @@ -550,7 +550,6 @@ class commonSettingsForm(Form): self.notification_title.extra_notification_tokens = kwargs.get('extra_notification_tokens', {}) self.notification_urls.extra_notification_tokens = kwargs.get('extra_notification_tokens', {}) - use_page_title_in_list = TernaryNoneBooleanField('Use page in watch overview list', default=None) #BooleanField=True fetch_backend = RadioField(u'Fetch Method', choices=content_fetchers.available_fetchers(), validators=[ValidateContentFetcherIsReady()]) notification_body = TextAreaField('Notification Body', default='{{ watch_url }} had a change.', validators=[validators.Optional(), ValidateJinja2Template()]) notification_format = SelectField('Notification format', choices=valid_notification_formats.keys()) @@ -757,6 +756,7 @@ class globalSettingsApplicationUIForm(Form): open_diff_in_new_tab = BooleanField("Open 'History' page in a new tab", default=True, validators=[validators.Optional()]) socket_io_enabled = BooleanField('Realtime UI Updates Enabled', default=True, validators=[validators.Optional()]) favicons_enabled = BooleanField('Favicons Enabled', default=True, validators=[validators.Optional()]) + use_page_title_in_list = BooleanField('Use page <title> in watch overview list') #BooleanField=True # datastore.data['settings']['application'].. class globalSettingsApplicationForm(commonSettingsForm): @@ -766,7 +766,7 @@ class globalSettingsApplicationForm(commonSettingsForm): validators=[validators.Optional()], render_kw={"placeholder": os.getenv('BASE_URL', 'Not set')} ) - empty_pages_are_a_change = TernaryNoneBooleanField('Treat empty pages as a change?', default=False) + empty_pages_are_a_change = BooleanField('Treat empty pages as a change?', default=False) fetch_backend = RadioField('Fetch Method', default="html_requests", choices=content_fetchers.available_fetchers(), validators=[ValidateContentFetcherIsReady()]) global_ignore_text = StringListField('Ignore Text', [ValidateListRegex()]) global_subtractive_selectors = StringListField('Remove elements', [ValidateCSSJSONXPATHInput(allow_json=False)]) @@ -781,7 +781,7 @@ class globalSettingsApplicationForm(commonSettingsForm): removepassword_button = SubmitField('Remove password', render_kw={"class": "pure-button pure-button-primary"}) render_anchor_tag_content = BooleanField('Render anchor tag content', default=False) - shared_diff_access = BooleanField('Allow access to view diff page when password is enabled', default=False, validators=[validators.Optional()]) + shared_diff_access = BooleanField('Allow anonymous access to watch history page when password is enabled', default=False, validators=[validators.Optional()]) rss_hide_muted_watches = BooleanField('Hide muted watches from RSS feed', default=True, validators=[validators.Optional()]) filter_failure_notification_threshold_attempts = IntegerField('Number of times the filter can be missing before sending a notification', diff --git a/changedetectionio/model/App.py b/changedetectionio/model/App.py index 0da8beeeb..b87e04822 100644 --- a/changedetectionio/model/App.py +++ b/changedetectionio/model/App.py @@ -59,9 +59,9 @@ class model(dict): 'shared_diff_access': False, 'tags': {}, #@todo use Tag.model initialisers 'timezone': None, # Default IANA timezone name - 'use_page_title_in_list': True, 'webdriver_delay': None , # Extra delay in seconds before extracting text 'ui': { + 'use_page_title_in_list': True, 'open_diff_in_new_tab': True, 'socket_io_enabled': True, 'favicons_enabled': True diff --git a/changedetectionio/store.py b/changedetectionio/store.py index b1a7330cc..88e369e2c 100644 --- a/changedetectionio/store.py +++ b/changedetectionio/store.py @@ -975,7 +975,7 @@ class ChangeDetectionStore: del self.data['watching'][uuid]['extract_title_as_title'] if self.data['settings']['application'].get('extract_title_as_title'): - self.data['settings']['application']['use_page_title_in_list'] = self.data['settings']['application'].get('extract_title_as_title') + self.data['settings']['application']['ui']['use_page_title_in_list'] = self.data['settings']['application'].get('extract_title_as_title') def add_notification_url(self, notification_url): diff --git a/changedetectionio/tests/test_backend.py b/changedetectionio/tests/test_backend.py index 3df8d6bf3..c250e32d8 100644 --- a/changedetectionio/tests/test_backend.py +++ b/changedetectionio/tests/test_backend.py @@ -89,7 +89,7 @@ def test_check_basic_change_detection_functionality(client, live_server, measure assert b'CDATA' in res.data assert expected_url.encode('utf-8') in res.data - +# # Following the 'diff' link, it should no longer display as 'unviewed' even after we recheck it a few times res = client.get(url_for("ui.ui_views.diff_history_page", uuid=uuid)) assert b'selected=""' in res.data, "Confirm diff history page loaded" @@ -104,26 +104,34 @@ def test_check_basic_change_detection_functionality(client, live_server, measure wait_for_all_checks(client) - # Do this a few times.. ensures we dont accidently set the status - for n in range(2): - client.get(url_for("ui.form_watch_checknow"), follow_redirects=True) + # Do this a few times.. ensures we don't accidently set the status + for n in range(2): + res = client.get(url_for("ui.form_watch_checknow"), follow_redirects=True) # Give the thread time to pick it up wait_for_all_checks(client) # It should report nothing found (no new 'unviewed' class) res = client.get(url_for("watchlist.index")) + + assert b'unviewed' not in res.data assert b'class="has-unviewed' not in res.data - assert b'head title' not in res.data # Should not be present because this is off by default + assert b'head title' in res.data # Should be ON by default assert b'test-endpoint' in res.data - set_original_response() + # Recheck it but only with a title change, content wasnt changed + set_original_response(extra_title=" and more") - # Enable auto pickup of <title> in settings + client.get(url_for("ui.form_watch_checknow"), follow_redirects=True) + wait_for_all_checks(client) + res = client.get(url_for("watchlist.index")) + assert b'head title and more' in res.data + + # disable <title> pickup res = client.post( url_for("settings.settings_page"), - data={"application-use_page_title_in_list": "1", "requests-time_between_check-minutes": 180, + data={"application-ui-use_page_title_in_list": "", "requests-time_between_check-minutes": 180, 'application-fetch_backend': "html_requests"}, follow_redirects=True ) @@ -134,17 +142,7 @@ def test_check_basic_change_detection_functionality(client, live_server, measure res = client.get(url_for("watchlist.index")) assert b'unviewed' in res.data assert b'class="has-unviewed' in res.data - - # It should have picked up the <title> - assert b'head title' in res.data - - - # Recheck it but only with a title change - set_original_response(extra_title=" and more") - client.get(url_for("ui.form_watch_checknow"), follow_redirects=True) - wait_for_all_checks(client) - res = client.get(url_for("watchlist.index")) - assert b'head title and more' in res.data + assert b'head title' not in res.data # should now be off # Be sure the last_viewed is going to be greater than the last snapshot @@ -152,7 +150,6 @@ def test_check_basic_change_detection_functionality(client, live_server, measure # hit the mark all viewed link res = client.get(url_for("ui.mark_all_viewed"), follow_redirects=True) - time.sleep(0.2) assert b'class="has-unviewed' not in res.data assert b'unviewed' not in res.data