Compare commits

...

8 Commits

13 changed files with 80 additions and 27 deletions

View File

@@ -67,7 +67,6 @@ FlaskCompress(app)
# Stop browser caching of assets
app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 0
app.config.exit = Event()
app.config['NEW_VERSION_AVAILABLE'] = False
@@ -470,7 +469,7 @@ def changedetection_app(config=None, datastore_o=None):
continue
if watch.get('last_error'):
errored_count += 1
if search_q:
if (watch.get('title') and search_q in watch.get('title').lower()) or search_q in watch.get('url', '').lower():
sorted_watches.append(watch)
@@ -533,7 +532,7 @@ def changedetection_app(config=None, datastore_o=None):
@login_optionally_required
def ajax_callback_send_notification_test(watch_uuid=None):
# Watch_uuid could be unset in the case its used in tag editor, global setings
# Watch_uuid could be unset in the case it`s used in tag editor, global settings
import apprise
import random
from .apprise_asset import asset
@@ -542,13 +541,15 @@ def changedetection_app(config=None, datastore_o=None):
from changedetectionio.apprise_plugin import apprise_custom_api_call_wrapper
is_global_settings_form = request.args.get('mode', '') == 'global-settings'
is_group_settings_form = request.args.get('mode', '') == 'group-settings'
# Use an existing random one on the global/main settings form
if not watch_uuid and (is_global_settings_form or is_group_settings_form):
if not watch_uuid and (is_global_settings_form or is_group_settings_form) \
and datastore.data.get('watching'):
logger.debug(f"Send test notification - Choosing random Watch {watch_uuid}")
watch_uuid = random.choice(list(datastore.data['watching'].keys()))
watch = datastore.data['watching'].get(watch_uuid)
watch = datastore.data['watching'].get(watch_uuid)
else:
watch = None
notification_urls = request.form['notification_urls'].strip().splitlines()
@@ -1396,7 +1397,7 @@ def changedetection_app(config=None, datastore_o=None):
url = request.form.get('url').strip()
if datastore.url_exists(url):
flash(f'Warning, URL {url} already exists', "notice")
add_paused = request.form.get('edit_and_watch_submit_button') != None
processor = request.form.get('processor', 'text_json_diff')
new_uuid = datastore.add_watch(url=url, tag=request.form.get('tags').strip(), extras={'paused': add_paused, 'processor': processor})

View File

@@ -588,6 +588,8 @@ class globalSettingsApplicationForm(commonSettingsForm):
global_ignore_text = StringListField('Ignore Text', [ValidateListRegex()])
global_subtractive_selectors = StringListField('Remove elements', [ValidateCSSJSONXPATHInput(allow_json=False)])
ignore_whitespace = BooleanField('Ignore whitespace')
keep_history_n = IntegerField('Number of snapshots to keep in history for each watch')
keep_history_seconds = IntegerField('Number of snapshots to keep - maximum age (todo/seconds)')
password = SaltyPasswordField()
pager_size = IntegerField('Pager size',
render_kw={"style": "width: 5em;"},

View File

@@ -40,6 +40,8 @@ class model(dict):
'global_ignore_text': [], # List of text to ignore when calculating the comparison checksum
'global_subtractive_selectors': [],
'ignore_whitespace': True,
'keep_history_n': None, # Number of snapshots to keep
'keep_history_seconds': None, # Or time ago back to keep
'notification_body': default_notification_body,
'notification_format': default_notification_format,
'notification_title': default_notification_title,

View File

@@ -625,6 +625,9 @@ class model(watch_base):
if index > 1 and os.path.isfile(filepath):
os.remove(filepath)
def post_process(self):
x=1
@property
def get_browsersteps_available_screenshots(self):

View File

@@ -33,6 +33,8 @@ class watch_base(dict):
'headers': {}, # Extra headers to send
'ignore_text': [], # List of text to ignore when calculating the comparison checksum
'in_stock_only': True, # Only trigger change on going to instock from out-of-stock
'keep_history_n': None, # Number of snapshots to keep
'keep_history_seconds': None, # Or time ago back to keep
'include_filters': [],
'last_checked': 0,
'last_error': False,

View File

@@ -331,13 +331,21 @@ class perform_site_check(difference_detection_processor):
if result:
blocked = True
# The main thing that all this at the moment comes down to :)
if watch.get('previous_md5') != fetched_md5:
changed_detected = True
# Looks like something changed, but did it match all the rules?
if blocked:
changed_detected = False
else:
# The main thing that all this at the moment comes down to :)
if watch.get('previous_md5') != fetched_md5:
changed_detected = True
# Always record the new checksum
update_obj["previous_md5"] = fetched_md5
# On the first run of a site, watch['previous_md5'] will be None, set it the current one.
if not watch.get('previous_md5'):
watch['previous_md5'] = fetched_md5
logger.debug(f"Watch UUID {watch.get('uuid')} content check - Previous MD5: {watch.get('previous_md5')}, Fetched MD5 {fetched_md5}")
@@ -357,12 +365,6 @@ class perform_site_check(difference_detection_processor):
else:
logger.debug(f"check_unique_lines: UUID {watch.get('uuid')} had unique content")
# Always record the new checksum
update_obj["previous_md5"] = fetched_md5
# On the first run of a site, watch['previous_md5'] will be None, set it the current one.
if not watch.get('previous_md5'):
watch['previous_md5'] = fetched_md5
# stripped_text_from_html - Everything after filters and NO 'ignored' content
return changed_detected, update_obj, stripped_text_from_html

View File

@@ -26,8 +26,7 @@ function set_active_tab() {
if (tab.length) {
tab[0].parentElement.className = "active";
}
// hash could move the page down
window.scrollTo(0, 0);
}
function focus_error_tab() {

View File

@@ -148,7 +148,7 @@ body.spinner-active {
}
.tabs ul li a {
.tab-pane-inner {
// .tab-pane-inner will have the #id that the tab button jumps/anchors to
scroll-margin-top: 200px;
}

View File

@@ -605,8 +605,7 @@ body.spinner-active #pure-menu-horizontal-spinner {
background-color: var(--color-background-menu-link-hover);
color: var(--color-text-menu-link-hover); }
.tabs ul li a {
.tab-pane-inner {
scroll-margin-top: 200px; }
section.content {

View File

@@ -129,6 +129,13 @@
Note: Simply changing the User-Agent often does not defeat anti-robot technologies, it's important to consider <a href="https://changedetection.io/tutorial/what-are-main-types-anti-robot-mechanisms">all of the ways that the browser is detected</a>.
</span>
</div>
<div class="pure-control-group">
{{ render_field(form.application.form.keep_history_n) }}
<span class="pure-form-message-inline">Blank - keep all</span>
{{ render_field(form.application.form.keep_history_seconds) }}
<span class="pure-form-message-inline">Blank - keep all</span>
</div>
<div class="pure-control-group">
<br>
Tip: <a href="https://github.com/dgtlmoon/changedetection.io/wiki/Proxy-configuration#brightdata-proxy-support">Connect using Bright Data and Oxylabs Proxies, find out more here.</a>

View File

@@ -65,11 +65,8 @@ def test_check_block_changedetection_text_NOT_present(client, live_server, measu
live_server_setup(live_server)
# Use a mix of case in ZzZ to prove it works case-insensitive.
ignore_text = "out of stoCk\r\nfoobar"
set_original_ignore_response()
# Give the endpoint time to spin up
time.sleep(1)
# Add our URL to the import page
test_url = url_for('test_endpoint', _external=True)
@@ -127,13 +124,24 @@ def test_check_block_changedetection_text_NOT_present(client, live_server, measu
assert b'unviewed' not in res.data
assert b'/test-endpoint' in res.data
# 2548
# Going back to the ORIGINAL should NOT trigger a change
set_original_ignore_response()
client.get(url_for("form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
res = client.get(url_for("index"))
assert b'unviewed' not in res.data
# Now we set a change where the text is gone, it should now trigger
# Now we set a change where the text is gone AND its different content, it should now trigger
set_modified_response_minus_block_text()
client.get(url_for("form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
res = client.get(url_for("index"))
assert b'unviewed' in res.data
res = client.get(url_for("form_delete", uuid="all"), follow_redirects=True)
assert b'Deleted' in res.data

View File

@@ -429,3 +429,24 @@ def test_global_send_test_notification(client, live_server, measure_memory_usage
follow_redirects=True
)
#2727 - be sure a test notification when there are zero watches works ( should all be deleted now)
os.unlink("test-datastore/notification.txt")
######### Test global/system settings
res = client.post(
url_for("ajax_callback_send_notification_test")+"?mode=global-settings",
data={"notification_urls": test_notification_url},
follow_redirects=True
)
assert res.status_code != 400
assert res.status_code != 500
# Give apprise time to fire
time.sleep(4)
with open("test-datastore/notification.txt", 'r') as f:
x = f.read()
assert 'change detection is cool 网站监测 内容更新了' in x

View File

@@ -81,7 +81,8 @@ class update_worker(threading.Thread):
'watch_url': watch.get('url') if watch else None,
})
n_object.update(watch.extra_notification_token_values())
if watch:
n_object.update(watch.extra_notification_token_values())
logger.trace(f"Main rendered notification placeholders (diff_added etc) calculated in {time.time()-now:.3f}s")
logger.debug("Queued notification for sending")
@@ -568,6 +569,12 @@ class update_worker(threading.Thread):
except Exception as e:
pass
try:
watch.post_process()
except Exception as e:
logger.critical(e)
self.datastore.update_watch(uuid=uuid, update_obj={'fetch_time': round(time.time() - now, 3),
'last_checked': round(time.time()),
'check_count': count