Compare commits

..

1 Commits

Author SHA1 Message Date
dgtlmoon
88752877ad IPv6 tidy-up
Re #3248
2025-06-11 11:07:08 +02:00
9 changed files with 40 additions and 66 deletions

View File

@@ -2,7 +2,7 @@
# Read more https://github.com/dgtlmoon/changedetection.io/wiki
__version__ = '0.50.3'
__version__ = '0.50.2'
from changedetectionio.strtobool import strtobool
from json.decoder import JSONDecodeError

View File

@@ -159,20 +159,12 @@ def construct_blueprint(datastore: ChangeDetectionStore, update_q, worker_handle
def mark_all_viewed():
# Save the current newest history as the most recently viewed
with_errors = request.args.get('with_errors') == "1"
tag_limit = request.args.get('tag')
logger.debug(f"Limiting to tag {tag_limit}")
now = int(time.time())
for watch_uuid, watch in datastore.data['watching'].items():
if with_errors and not watch.get('last_error'):
continue
datastore.set_last_viewed(watch_uuid, int(time.time()))
if tag_limit and ( not watch.get('tags') or tag_limit not in watch['tags'] ):
logger.debug(f"Skipping watch {watch_uuid}")
continue
datastore.set_last_viewed(watch_uuid, now)
return redirect(url_for('watchlist.index', tag=tag_limit))
return redirect(url_for('watchlist.index'))
@ui_blueprint.route("/delete", methods=['GET'])
@login_optionally_required

View File

@@ -214,14 +214,9 @@ document.addEventListener('DOMContentLoaded', function() {
<li id="post-list-mark-views" class="{%- if has_unviewed -%}has-unviewed{%- endif -%}" style="display: none;" >
<a href="{{url_for('ui.mark_all_viewed',with_errors=request.args.get('with_errors',0)) }}" class="pure-button button-tag " id="mark-all-viewed">Mark all viewed</a>
</li>
{%- if active_tag_uuid -%}
<li id="post-list-mark-views-tag">
<a href="{{url_for('ui.mark_all_viewed', tag=active_tag_uuid) }}" class="pure-button button-tag " id="mark-all-viewed">Mark all viewed in '{{active_tag.title}}'</a>
</li>
{%- endif -%}
<li>
<a href="{{ url_for('ui.form_watch_checknow', tag=active_tag_uuid, with_errors=request.args.get('with_errors',0)) }}" class="pure-button button-tag" id="recheck-all">Recheck
all {% if active_tag_uuid %} in '{{active_tag.title}}'{%endif%}</a>
all {%- if active_tag_uuid-%} in "{{active_tag.title}}"{%endif%}</a>
</li>
<li>
<a href="{{ url_for('rss.feed', tag=active_tag_uuid, token=app_rss_token)}}"><img alt="RSS Feed" id="feed-icon" src="{{url_for('static_content', group='images', filename='generic_feed-icon.svg')}}" height="15"></a>

View File

@@ -100,7 +100,7 @@ watch_api = Api(app, decorators=[csrf.exempt])
def init_app_secret(datastore_path):
secret = ""
path = os.path.join(datastore_path, "secret.txt")
path = "{}/secret.txt".format(datastore_path)
try:
with open(path, "r") as f:

View File

@@ -738,7 +738,7 @@ class globalSettingsRequestForm(Form):
return False
class globalSettingsApplicationUIForm(Form):
open_diff_in_new_tab = BooleanField("Open 'History' page in a new tab", default=True, validators=[validators.Optional()])
open_diff_in_new_tab = BooleanField('Open diff page in a new tab', default=True, validators=[validators.Optional()])
socket_io_enabled = BooleanField('Realtime UI Updates Enabled', default=True, validators=[validators.Optional()])
# datastore.data['settings']['application']..

View File

@@ -48,9 +48,9 @@ $(document).ready(function () {
// Connect to Socket.IO on the same host/port, with path from template
const socket = io({
path: socketio_url, // This will be the path prefix like "/app/socket.io" from the template
transports: ['websocket', 'polling'],
reconnectionDelay: 3000,
reconnectionAttempts: 25
transports: ['polling', 'websocket'], // Try WebSocket but fall back to polling
reconnectionDelay: 1000,
reconnectionAttempts: 15
});
// Connection status logging
@@ -98,12 +98,6 @@ $(document).ready(function () {
console.log(`Stub handler for notification_event ${data.watch_uuid}`)
});
socket.on('watch_deleted', function (data) {
$('tr[data-watch-uuid="' + data.uuid + '"] td').fadeOut(500, function () {
$(this).closest('tr').remove();
});
});
// Listen for periodically emitted watch data
console.log('Adding watch_update event listener');

View File

@@ -16,12 +16,6 @@ $(function () {
$('#op_extradata').val(prompt("Enter a tag name"));
});
$('.history-link').click(function (e) {
// Incase they click 'back' in the browser, it should be removed.
$(this).closest('tr').removeClass('unviewed');
});
$('.with-share-link > *').click(function () {
$("#copied-clipboard").remove();

View File

@@ -13,7 +13,6 @@ import json
import os
import re
import secrets
import sys
import threading
import time
import uuid as uuid_builder
@@ -46,7 +45,7 @@ class ChangeDetectionStore:
# logging.basicConfig(filename='/dev/stdout', level=logging.INFO)
self.__data = App.model()
self.datastore_path = datastore_path
self.json_store_path = os.path.join(self.datastore_path, "url-watches.json")
self.json_store_path = "{}/url-watches.json".format(self.datastore_path)
logger.info(f"Datastore path is '{self.json_store_path}'")
self.needs_write = False
self.start_time = time.time()
@@ -119,12 +118,14 @@ class ChangeDetectionStore:
test_list = self.proxy_list
# Helper to remove password protection
password_reset_lockfile = os.path.join(self.datastore_path, "removepassword.lock")
password_reset_lockfile = "{}/removepassword.lock".format(self.datastore_path)
if path.isfile(password_reset_lockfile):
self.__data['settings']['application']['password'] = False
unlink(password_reset_lockfile)
if not 'app_guid' in self.__data:
import os
import sys
if "pytest" in sys.modules or "PYTEST_CURRENT_TEST" in os.environ:
self.__data['app_guid'] = "test-" + str(uuid_builder.uuid4())
else:
@@ -385,9 +386,9 @@ class ChangeDetectionStore:
return new_uuid
def visualselector_data_is_ready(self, watch_uuid):
output_path = os.path.join(self.datastore_path, watch_uuid)
screenshot_filename = os.path.join(output_path, "last-screenshot.png")
elements_index_filename = os.path.join(output_path, "elements.deflate")
output_path = "{}/{}".format(self.datastore_path, watch_uuid)
screenshot_filename = "{}/last-screenshot.png".format(output_path)
elements_index_filename = "{}/elements.deflate".format(output_path)
if path.isfile(screenshot_filename) and path.isfile(elements_index_filename) :
return True
@@ -473,7 +474,7 @@ class ChangeDetectionStore:
# Load from external config file
if path.isfile(proxy_list_file):
with open(os.path.join(self.datastore_path, "proxies.json")) as f:
with open("{}/proxies.json".format(self.datastore_path)) as f:
proxy_list = json.load(f)
# Mapping from UI config if available
@@ -731,10 +732,10 @@ class ChangeDetectionStore:
logger.critical(f"Applying update_{update_n}")
# Wont exist on fresh installs
if os.path.exists(self.json_store_path):
shutil.copyfile(self.json_store_path, os.path.join(self.datastore_path, f"url-watches-before-{update_n}.json"))
shutil.copyfile(self.json_store_path, self.datastore_path+"/url-watches-before-{}.json".format(update_n))
try:
update_method = getattr(self, f"update_{update_n}")()
update_method = getattr(self, "update_{}".format(update_n))()
except Exception as e:
logger.error(f"Error while trying update_{update_n}")
logger.error(e)

View File

@@ -236,41 +236,39 @@ def test_group_tag_notification(client, live_server, measure_memory_usage):
assert b'Deleted' in res.data
def test_limit_tag_ui(client, live_server, measure_memory_usage):
test_url = url_for('test_random_content_endpoint', _external=True)
test_url = url_for('test_endpoint', _external=True)
urls=[]
# A space can label the tag, only the first one will have a tag
client.post(
for i in range(20):
urls.append(test_url+"?x="+str(i)+" test-tag")
for i in range(20):
urls.append(test_url+"?non-grouped="+str(i))
res = client.post(
url_for("imports.import_page"),
data={"urls": f"{test_url} test-tag\r\n{test_url}"},
data={"urls": "\r\n".join(urls)},
follow_redirects=True
)
tag_uuid = get_UUID_for_tag_name(client, name="test-tag")
assert tag_uuid
assert b"40 Imported" in res.data
res = client.get(url_for("watchlist.index"))
assert b'test-tag' in res.data
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)
# Should be both unviewed
res = client.get(url_for("watchlist.index"))
assert res.data.count(b' unviewed ') == 2
# All should be here
assert res.data.count(b'processor-text_json_diff') == 40
tag_uuid = get_UUID_for_tag_name(client, name="test-tag")
# Now we recheck only the tag
client.get(url_for('ui.mark_all_viewed', tag=tag_uuid), follow_redirects=True)
wait_for_all_checks(client)
with open('/tmp/fuck.html', 'wb') as f:
f.write(res.data)
# Should be only 1 unviewed
res = client.get(url_for("watchlist.index"))
assert res.data.count(b' unviewed ') == 1
res = client.get(url_for("watchlist.index", tag=tag_uuid))
# Just a subset should be here
assert b'test-tag' in res.data
assert res.data.count(b'processor-text_json_diff') == 20
assert b"object at" not in res.data
res = client.get(url_for("ui.form_delete", uuid="all"), follow_redirects=True)
assert b'Deleted' in res.data
res = client.get(url_for("tags.delete_all"), follow_redirects=True)