diff --git a/changedetectionio/api/Import.py b/changedetectionio/api/Import.py
index 9b0cec4e4..81b3d29b1 100644
--- a/changedetectionio/api/Import.py
+++ b/changedetectionio/api/Import.py
@@ -194,6 +194,15 @@ class Import(Resource):
urls_to_import.append(url)
+ # PAGE_WATCH_LIMIT - refuse the whole batch rather than importing an arbitrary prefix of
+ # it, so a 429 always means "nothing was created" and the caller can retry as-is
+ watch_limit = self.datastore.watch_limit
+ if watch_limit is not None:
+ current_watch_count = len(self.datastore.data['watching'])
+ if current_watch_count + len(urls_to_import) > watch_limit:
+ return (f"Watch limit reached ({current_watch_count}/{watch_limit} watches), importing "
+ f"{len(urls_to_import)} URL(s) would exceed it. No watches were imported.", 429)
+
# For small imports, process synchronously for immediate feedback
if len(urls_to_import) < IMPORT_SWITCH_TO_BACKGROUND_THRESHOLD:
added = []
diff --git a/changedetectionio/api/Watch.py b/changedetectionio/api/Watch.py
index 127599d29..377e8d161 100644
--- a/changedetectionio/api/Watch.py
+++ b/changedetectionio/api/Watch.py
@@ -560,6 +560,12 @@ class CreateWatch(Resource):
del extras['url']
+ # PAGE_WATCH_LIMIT - checked up front so a blocked add is reported as 429 rather than
+ # being guessed at from add_watch() returning None
+ if self.datastore.watch_limit_reached():
+ current_watch_count = len(self.datastore.data['watching'])
+ return f"Watch limit reached ({current_watch_count}/{self.datastore.watch_limit} watches). Cannot add more watches.", 429
+
new_uuid = self.datastore.add_watch(url=url, extras=extras, tag=tags)
# Save processor config to separate JSON file
@@ -570,16 +576,6 @@ class CreateWatch(Resource):
# worker_pool.queue_item_async_safe(self.update_q, queuedWatchMetaData.PrioritizedItem(priority=1, item={'uuid': new_uuid}))
return {'uuid': new_uuid}, 201
else:
- # Check if it was a limit issue
- page_watch_limit = os.getenv('PAGE_WATCH_LIMIT')
- if page_watch_limit:
- try:
- page_watch_limit = int(page_watch_limit)
- current_watch_count = len(self.datastore.data['watching'])
- if current_watch_count >= page_watch_limit:
- return f"Watch limit reached ({current_watch_count}/{page_watch_limit} watches). Cannot add more watches.", 429
- except ValueError:
- pass
return "Invalid or unsupported URL", 400
@auth.check_token
diff --git a/changedetectionio/blueprint/imports/importer.py b/changedetectionio/blueprint/imports/importer.py
index cbee99997..29577e7cb 100644
--- a/changedetectionio/blueprint/imports/importer.py
+++ b/changedetectionio/blueprint/imports/importer.py
@@ -17,6 +17,7 @@ class Importer():
self.good = 0
self.remaining_data = []
self.import_profile = None
+ self.limit_reported = False
@abstractmethod
def run(self,
@@ -25,6 +26,21 @@ class Importer():
datastore):
pass
+ def watch_limit_hit(self, datastore, flash):
+ """True once PAGE_WATCH_LIMIT leaves no room - the caller must then stop importing.
+
+ Asked before each add_watch() so the limit is reported once for the whole file.
+ add_watch() would otherwise flash the same error again for every remaining row.
+ """
+ if not datastore.watch_limit_reached():
+ return False
+
+ if not self.limit_reported:
+ self.limit_reported = True
+ flash(datastore.watch_limit_message(), 'error')
+
+ return True
+
class import_url_list(Importer):
"""
@@ -44,7 +60,7 @@ class import_url_list(Importer):
if (len(urls) > 5000):
flash(gettext("Importing 5,000 of the first URLs from your list, the rest can be imported again."))
- for url in urls:
+ for idx, url in enumerate(urls):
url = url.strip()
if not len(url):
continue
@@ -59,6 +75,12 @@ class import_url_list(Importer):
# Up to 5000 per batch so we dont flood the server
# @todo validators.url will fail when you add your own IP etc
if len(url) and 'http' in url.lower() and good < 5000:
+ if self.watch_limit_hit(datastore, flash):
+ # Hand back every line we didn't get to (originals, tags included) so they
+ # land in the textarea to retry once there's room
+ self.remaining_data.extend(u.strip() for u in urls[idx:] if u.strip())
+ break
+
extras = None
if processor:
extras = {'processor': processor}
@@ -107,6 +129,9 @@ class import_distill_io_json(Importer):
extras = {'title': d.get('name', None)}
if len(d['uri']) and good < 5000:
+ if self.watch_limit_hit(datastore, flash):
+ break
+
try:
# @todo we only support CSS ones at the moment
if d_config['selections'][0]['frames'][0]['excludes'][0]['type'] == 'css':
@@ -200,6 +225,9 @@ class import_xlsx_wachete(Importer):
# Don't bother processing anything else on this row
continue
+ if self.watch_limit_hit(datastore, flash):
+ break
+
new_uuid = datastore.add_watch(url=data['url'].strip(),
extras=extras,
tag=data.get('folder'),
@@ -281,6 +309,9 @@ class import_xlsx_custom(Importer):
# At minimum a URL is required.
if url:
+ if self.watch_limit_hit(datastore, flash):
+ break
+
new_uuid = datastore.add_watch(url=url,
extras=extras,
tag=tags,
diff --git a/changedetectionio/blueprint/settings/__init__.py b/changedetectionio/blueprint/settings/__init__.py
index d00205d52..c05a55acb 100644
--- a/changedetectionio/blueprint/settings/__init__.py
+++ b/changedetectionio/blueprint/settings/__init__.py
@@ -261,6 +261,8 @@ def construct_blueprint(datastore: ChangeDetectionStore):
llm_show_costs=llm_show_costs,
python_version=python_version,
uptime_seconds=uptime_seconds,
+ # None unless PAGE_WATCH_LIMIT is set, which hides the row entirely
+ watch_limit=datastore.watch_limit,
available_timezones=sorted(available_timezones()),
emailprefix=os.getenv('NOTIFICATION_MAIL_BUTTON_PREFIX', False),
extra_notification_token_placeholder_info=datastore.get_unique_notification_token_placeholders_available(),
diff --git a/changedetectionio/blueprint/settings/templates/settings.html b/changedetectionio/blueprint/settings/templates/settings.html
index 1d5ffa630..0f8ea7fc8 100644
--- a/changedetectionio/blueprint/settings/templates/settings.html
+++ b/changedetectionio/blueprint/settings/templates/settings.html
@@ -391,6 +391,9 @@ nav
{{ _('Uptime:') }} {{ uptime_seconds|format_duration }}
{{ _('Python version:') }} {{ python_version }}
+ {% if watch_limit is not none %}
+
{{ _('Maximum number of page watches:') }} {{ watch_limit }}
+ {% endif %}
{{ _('Plugins active:') }}
{% if active_plugins %}
diff --git a/changedetectionio/blueprint/ui/__init__.py b/changedetectionio/blueprint/ui/__init__.py
index ac5537125..5c4d85aa1 100644
--- a/changedetectionio/blueprint/ui/__init__.py
+++ b/changedetectionio/blueprint/ui/__init__.py
@@ -293,6 +293,9 @@ def construct_blueprint(datastore: ChangeDetectionStore, update_q, worker_pool,
uuid = list(datastore.data['watching'].keys()).pop()
new_uuid = datastore.clone(uuid)
+ if not new_uuid:
+ # Refused (e.g. PAGE_WATCH_LIMIT) - the reason is already flashed
+ return redirect(url_for('watchlist.index'))
if not datastore.data['watching'].get(uuid).get('paused'):
worker_pool.queue_item_async_safe(update_q, queuedWatchMetaData.PrioritizedItem(priority=5, item={'uuid': new_uuid}))
diff --git a/changedetectionio/store/__init__.py b/changedetectionio/store/__init__.py
index 28ac5df04..251124496 100644
--- a/changedetectionio/store/__init__.py
+++ b/changedetectionio/store/__init__.py
@@ -5,7 +5,8 @@ from changedetectionio.strtobool import strtobool
from changedetectionio.validate_url import is_safe_valid_url
from flask import (
- flash
+ flash,
+ has_request_context
)
from flask_babel import gettext
@@ -661,9 +662,8 @@ class ChangeDetectionStore(DatastoreUpdatesMixin, FileSavingDataStore):
# NOTE: dict() is shallow copy but safe since add_watch() deepcopies it
with self.lock:
extras = dict(self.data['watching'][uuid])
- new_uuid = self.add_watch(url=url, extras=extras)
- watch = self.data['watching'][new_uuid]
- return new_uuid
+ # None when add_watch() refused it (e.g. PAGE_WATCH_LIMIT), having already flashed why
+ return self.add_watch(url=url, extras=extras)
def url_exists(self, url):
@@ -679,6 +679,38 @@ class ChangeDetectionStore(DatastoreUpdatesMixin, FileSavingDataStore):
self.__data['watching'][uuid].clear_watch()
self.__data['watching'][uuid].commit()
+ @property
+ def watch_limit(self):
+ """Total watches allowed by PAGE_WATCH_LIMIT, or None when there is no limit.
+
+ None means "unlimited" and is the normal case - the env var being absent, empty or
+ unparseable all leave the limit switched off entirely. There is no default.
+ """
+ limit = os.getenv('PAGE_WATCH_LIMIT')
+ if not limit:
+ return None
+ try:
+ return int(limit)
+ except ValueError:
+ logger.warning(f"Invalid PAGE_WATCH_LIMIT value: {limit}, ignoring limit check")
+ return None
+
+ def watch_limit_reached(self):
+ """True when the limit is set and leaves no room for another watch.
+
+ add_watch() enforces this on its own, but it can only return None. Callers that can
+ report something better - a 429 in the API, one flash instead of one per row in the
+ importers - should check this first.
+ """
+ limit = self.watch_limit
+ return limit is not None and len(self.__data['watching']) >= limit
+
+ def watch_limit_message(self):
+ """The single wording for a blocked add, so every UI surface says the same thing."""
+ return gettext("Watch limit reached ({current}/{limit} watches). Cannot add more watches.").format(
+ current=len(self.__data['watching']), limit=self.watch_limit
+ )
+
def add_watch(self, url, tag='', extras=None, tag_uuids=None, save_immediately=True, seed_data_dir=None):
"""
seed_data_dir: optional path to an existing directory (already in the watch's
@@ -742,25 +774,21 @@ class ChangeDetectionStore(DatastoreUpdatesMixin, FileSavingDataStore):
return False
if not is_safe_valid_url(url):
- from flask import has_request_context
if has_request_context():
flash(gettext('Watch protocol is not permitted or invalid URL format'), 'error')
else:
logger.error(f"add_watch: URL '{url}' is not permitted or invalid, skipping.")
return None
- # Check PAGE_WATCH_LIMIT if set
- page_watch_limit = os.getenv('PAGE_WATCH_LIMIT')
- if page_watch_limit:
- try:
- page_watch_limit = int(page_watch_limit)
- current_watch_count = len(self.__data['watching'])
- if current_watch_count >= page_watch_limit:
- logger.error(f"Watch limit reached: {current_watch_count}/{page_watch_limit} watches. Cannot add {url}")
- flash(gettext("Watch limit reached ({current}/{limit} watches). Cannot add more watches.").format(current=current_watch_count, limit=page_watch_limit), 'error')
- return None
- except ValueError:
- logger.warning(f"Invalid PAGE_WATCH_LIMIT value: {page_watch_limit}, ignoring limit check")
+ # Backstop for PAGE_WATCH_LIMIT - every add path funnels through here, so nothing can
+ # get past the limit even if a caller forgets to pre-check watch_limit_reached().
+ if self.watch_limit_reached():
+ logger.error(f"Watch limit reached: {len(self.__data['watching'])}/{self.watch_limit} watches. Cannot add {url}")
+ # The CLI (-u) and the API's background import thread have no request context,
+ # where flash() raises instead of reporting anything
+ if has_request_context():
+ flash(self.watch_limit_message(), 'error')
+ return None
if tag and type(tag) == str:
# Then it's probably a string of the actual tag by name, split and add it
diff --git a/changedetectionio/translations/cs/LC_MESSAGES/messages.mo b/changedetectionio/translations/cs/LC_MESSAGES/messages.mo
index 792bac3ea..193001c73 100644
Binary files a/changedetectionio/translations/cs/LC_MESSAGES/messages.mo and b/changedetectionio/translations/cs/LC_MESSAGES/messages.mo differ
diff --git a/changedetectionio/translations/cs/LC_MESSAGES/messages.po b/changedetectionio/translations/cs/LC_MESSAGES/messages.po
index 9120231d3..5b4cfa8d5 100644
--- a/changedetectionio/translations/cs/LC_MESSAGES/messages.po
+++ b/changedetectionio/translations/cs/LC_MESSAGES/messages.po
@@ -861,6 +861,10 @@ msgstr ""
msgid "Python version:"
msgstr "Verze Pythonu:"
+#: changedetectionio/blueprint/settings/templates/settings.html
+msgid "Maximum number of page watches:"
+msgstr "Maximální počet sledování stránek:"
+
#: changedetectionio/blueprint/settings/templates/settings.html
msgid "Plugins active:"
msgstr "Pluginy aktivní:"
@@ -3974,6 +3978,11 @@ msgstr "Změny textu webové stránky/HTML, JSON a PDF"
msgid "Detects all text changes where possible"
msgstr "Detekuje všechny změny textu, kde je to možné"
+#: changedetectionio/store/__init__.py
+#, python-brace-format
+msgid "Watch limit reached ({current}/{limit} watches). Cannot add more watches."
+msgstr "Dosažen limit sledování ({current}/{limit}). Nelze přidat další."
+
#: changedetectionio/store/__init__.py
#, python-brace-format
msgid "Error fetching metadata for {}"
@@ -3983,11 +3992,6 @@ msgstr ""
msgid "Watch protocol is not permitted or invalid URL format"
msgstr ""
-#: changedetectionio/store/__init__.py
-#, python-brace-format
-msgid "Watch limit reached ({current}/{limit} watches). Cannot add more watches."
-msgstr ""
-
#: changedetectionio/templates/_common_fields.html
msgid "Body for all notifications — You can use"
msgstr "Tělo pro všechna oznámení — Můžete použít"
diff --git a/changedetectionio/translations/de/LC_MESSAGES/messages.mo b/changedetectionio/translations/de/LC_MESSAGES/messages.mo
index aa83c6ec5..375b2274d 100644
Binary files a/changedetectionio/translations/de/LC_MESSAGES/messages.mo and b/changedetectionio/translations/de/LC_MESSAGES/messages.mo differ
diff --git a/changedetectionio/translations/de/LC_MESSAGES/messages.po b/changedetectionio/translations/de/LC_MESSAGES/messages.po
index f5fdd3c6e..f49dba024 100644
--- a/changedetectionio/translations/de/LC_MESSAGES/messages.po
+++ b/changedetectionio/translations/de/LC_MESSAGES/messages.po
@@ -877,6 +877,10 @@ msgstr ""
msgid "Python version:"
msgstr "Python-Version:"
+#: changedetectionio/blueprint/settings/templates/settings.html
+msgid "Maximum number of page watches:"
+msgstr "Maximale Anzahl an Seitenüberwachungen:"
+
#: changedetectionio/blueprint/settings/templates/settings.html
msgid "Plugins active:"
msgstr "Aktive Plugins:"
@@ -4026,6 +4030,11 @@ msgstr "Änderungen an Webseitentext/HTML, JSON und PDF"
msgid "Detects all text changes where possible"
msgstr "Erkennt nach Möglichkeit alle Textänderungen"
+#: changedetectionio/store/__init__.py
+#, python-brace-format
+msgid "Watch limit reached ({current}/{limit} watches). Cannot add more watches."
+msgstr "Überwachungslimit erreicht ({current}/{limit}). Keine weiteren möglich."
+
#: changedetectionio/store/__init__.py
#, python-brace-format
msgid "Error fetching metadata for {}"
@@ -4035,11 +4044,6 @@ msgstr "Fehler beim Abrufen der Metadaten für {}"
msgid "Watch protocol is not permitted or invalid URL format"
msgstr "Das Protokoll wird nicht unterstützt oder das URL-Format ist ungültig."
-#: changedetectionio/store/__init__.py
-#, python-brace-format
-msgid "Watch limit reached ({current}/{limit} watches). Cannot add more watches."
-msgstr ""
-
#: changedetectionio/templates/_common_fields.html
msgid "Body for all notifications — You can use"
msgstr "Inhalt für alle Benachrichtigungen — Sie können verwenden"
diff --git a/changedetectionio/translations/en_GB/LC_MESSAGES/messages.po b/changedetectionio/translations/en_GB/LC_MESSAGES/messages.po
index dda350109..d67bcb06b 100644
--- a/changedetectionio/translations/en_GB/LC_MESSAGES/messages.po
+++ b/changedetectionio/translations/en_GB/LC_MESSAGES/messages.po
@@ -859,6 +859,10 @@ msgstr ""
msgid "Python version:"
msgstr ""
+#: changedetectionio/blueprint/settings/templates/settings.html
+msgid "Maximum number of page watches:"
+msgstr ""
+
#: changedetectionio/blueprint/settings/templates/settings.html
msgid "Plugins active:"
msgstr ""
@@ -3966,6 +3970,11 @@ msgstr ""
msgid "Detects all text changes where possible"
msgstr ""
+#: changedetectionio/store/__init__.py
+#, python-brace-format
+msgid "Watch limit reached ({current}/{limit} watches). Cannot add more watches."
+msgstr ""
+
#: changedetectionio/store/__init__.py
#, python-brace-format
msgid "Error fetching metadata for {}"
@@ -3975,11 +3984,6 @@ msgstr ""
msgid "Watch protocol is not permitted or invalid URL format"
msgstr ""
-#: changedetectionio/store/__init__.py
-#, python-brace-format
-msgid "Watch limit reached ({current}/{limit} watches). Cannot add more watches."
-msgstr ""
-
#: changedetectionio/templates/_common_fields.html
msgid "Body for all notifications — You can use"
msgstr ""
diff --git a/changedetectionio/translations/en_US/LC_MESSAGES/messages.po b/changedetectionio/translations/en_US/LC_MESSAGES/messages.po
index 1c0ca7f50..77bdaebe8 100644
--- a/changedetectionio/translations/en_US/LC_MESSAGES/messages.po
+++ b/changedetectionio/translations/en_US/LC_MESSAGES/messages.po
@@ -859,6 +859,10 @@ msgstr ""
msgid "Python version:"
msgstr ""
+#: changedetectionio/blueprint/settings/templates/settings.html
+msgid "Maximum number of page watches:"
+msgstr ""
+
#: changedetectionio/blueprint/settings/templates/settings.html
msgid "Plugins active:"
msgstr ""
@@ -3966,6 +3970,11 @@ msgstr ""
msgid "Detects all text changes where possible"
msgstr ""
+#: changedetectionio/store/__init__.py
+#, python-brace-format
+msgid "Watch limit reached ({current}/{limit} watches). Cannot add more watches."
+msgstr ""
+
#: changedetectionio/store/__init__.py
#, python-brace-format
msgid "Error fetching metadata for {}"
@@ -3975,11 +3984,6 @@ msgstr ""
msgid "Watch protocol is not permitted or invalid URL format"
msgstr ""
-#: changedetectionio/store/__init__.py
-#, python-brace-format
-msgid "Watch limit reached ({current}/{limit} watches). Cannot add more watches."
-msgstr ""
-
#: changedetectionio/templates/_common_fields.html
msgid "Body for all notifications — You can use"
msgstr ""
diff --git a/changedetectionio/translations/es/LC_MESSAGES/messages.mo b/changedetectionio/translations/es/LC_MESSAGES/messages.mo
index 9500ca7ed..80d883b9e 100644
Binary files a/changedetectionio/translations/es/LC_MESSAGES/messages.mo and b/changedetectionio/translations/es/LC_MESSAGES/messages.mo differ
diff --git a/changedetectionio/translations/es/LC_MESSAGES/messages.po b/changedetectionio/translations/es/LC_MESSAGES/messages.po
index 7e13c25b6..a444474e8 100644
--- a/changedetectionio/translations/es/LC_MESSAGES/messages.po
+++ b/changedetectionio/translations/es/LC_MESSAGES/messages.po
@@ -897,6 +897,10 @@ msgstr "Tiempo de actividad:"
msgid "Python version:"
msgstr "Versión de Python:"
+#: changedetectionio/blueprint/settings/templates/settings.html
+msgid "Maximum number of page watches:"
+msgstr "Número máximo de monitores de páginas:"
+
#: changedetectionio/blueprint/settings/templates/settings.html
msgid "Plugins active:"
msgstr "Complementos activos:"
@@ -4039,6 +4043,11 @@ msgstr "Cambios en el texto/HTML, JSON y PDF de la página web"
msgid "Detects all text changes where possible"
msgstr "Detecta todos los cambios de texto siempre que sea posible"
+#: changedetectionio/store/__init__.py
+#, python-brace-format
+msgid "Watch limit reached ({current}/{limit} watches). Cannot add more watches."
+msgstr "Límite de monitores alcanzado ({current}/{limit}). No se pueden añadir más."
+
#: changedetectionio/store/__init__.py
#, python-brace-format
msgid "Error fetching metadata for {}"
@@ -4048,11 +4057,6 @@ msgstr "Error al obtener metadatos para{}"
msgid "Watch protocol is not permitted or invalid URL format"
msgstr "El protocolo de visualización no está permitido o el formato de URL no es válido"
-#: changedetectionio/store/__init__.py
-#, python-brace-format
-msgid "Watch limit reached ({current}/{limit} watches). Cannot add more watches."
-msgstr "Límite de visualización alcanzado ({current} /{limit} monitores). No se pueden agregar más monitores."
-
#: changedetectionio/templates/_common_fields.html
msgid "Body for all notifications — You can use"
msgstr "Cuerpo de todas las notificaciones: puedes utilizar"
diff --git a/changedetectionio/translations/fr/LC_MESSAGES/messages.mo b/changedetectionio/translations/fr/LC_MESSAGES/messages.mo
index d5847fa4e..699937114 100644
Binary files a/changedetectionio/translations/fr/LC_MESSAGES/messages.mo and b/changedetectionio/translations/fr/LC_MESSAGES/messages.mo differ
diff --git a/changedetectionio/translations/fr/LC_MESSAGES/messages.po b/changedetectionio/translations/fr/LC_MESSAGES/messages.po
index 1dfb0cda4..f2130b245 100644
--- a/changedetectionio/translations/fr/LC_MESSAGES/messages.po
+++ b/changedetectionio/translations/fr/LC_MESSAGES/messages.po
@@ -865,6 +865,10 @@ msgstr ""
msgid "Python version:"
msgstr "Version Python :"
+#: changedetectionio/blueprint/settings/templates/settings.html
+msgid "Maximum number of page watches:"
+msgstr "Nombre maximum de moniteurs de pages :"
+
#: changedetectionio/blueprint/settings/templates/settings.html
msgid "Plugins active:"
msgstr "Plugins actifs :"
@@ -3979,6 +3983,11 @@ msgstr "Modifications du texte de la page Web/HTML, JSON et PDF"
msgid "Detects all text changes where possible"
msgstr "Détecte toutes les modifications de texte lorsque cela est possible"
+#: changedetectionio/store/__init__.py
+#, python-brace-format
+msgid "Watch limit reached ({current}/{limit} watches). Cannot add more watches."
+msgstr "Limite de moniteurs atteinte ({current}/{limit}). Impossible d'en ajouter."
+
#: changedetectionio/store/__init__.py
#, python-brace-format
msgid "Error fetching metadata for {}"
@@ -3988,11 +3997,6 @@ msgstr ""
msgid "Watch protocol is not permitted or invalid URL format"
msgstr ""
-#: changedetectionio/store/__init__.py
-#, python-brace-format
-msgid "Watch limit reached ({current}/{limit} watches). Cannot add more watches."
-msgstr ""
-
#: changedetectionio/templates/_common_fields.html
msgid "Body for all notifications — You can use"
msgstr "Corps pour toutes les notifications — Vous pouvez utiliser"
diff --git a/changedetectionio/translations/it/LC_MESSAGES/messages.mo b/changedetectionio/translations/it/LC_MESSAGES/messages.mo
index 61fb6a6ac..939ad1f79 100644
Binary files a/changedetectionio/translations/it/LC_MESSAGES/messages.mo and b/changedetectionio/translations/it/LC_MESSAGES/messages.mo differ
diff --git a/changedetectionio/translations/it/LC_MESSAGES/messages.po b/changedetectionio/translations/it/LC_MESSAGES/messages.po
index 640d7c0d1..520a83745 100644
--- a/changedetectionio/translations/it/LC_MESSAGES/messages.po
+++ b/changedetectionio/translations/it/LC_MESSAGES/messages.po
@@ -861,6 +861,10 @@ msgstr ""
msgid "Python version:"
msgstr ""
+#: changedetectionio/blueprint/settings/templates/settings.html
+msgid "Maximum number of page watches:"
+msgstr "Numero massimo di monitoraggi di pagine:"
+
#: changedetectionio/blueprint/settings/templates/settings.html
msgid "Plugins active:"
msgstr ""
@@ -3968,6 +3972,11 @@ msgstr "Modifiche testo/HTML, JSON e PDF"
msgid "Detects all text changes where possible"
msgstr "Rileva tutte le modifiche di testo possibili"
+#: changedetectionio/store/__init__.py
+#, python-brace-format
+msgid "Watch limit reached ({current}/{limit} watches). Cannot add more watches."
+msgstr "Limite di monitoraggi raggiunto ({current}/{limit}). Impossibile aggiungerne altri."
+
#: changedetectionio/store/__init__.py
#, python-brace-format
msgid "Error fetching metadata for {}"
@@ -3977,11 +3986,6 @@ msgstr "Errore nel recupero metadati per {}"
msgid "Watch protocol is not permitted or invalid URL format"
msgstr "Protocollo non consentito o formato URL non valido"
-#: changedetectionio/store/__init__.py
-#, python-brace-format
-msgid "Watch limit reached ({current}/{limit} watches). Cannot add more watches."
-msgstr ""
-
#: changedetectionio/templates/_common_fields.html
msgid "Body for all notifications — You can use"
msgstr "Corpo per tutte le notifiche — Puoi usare"
diff --git a/changedetectionio/translations/ja/LC_MESSAGES/messages.mo b/changedetectionio/translations/ja/LC_MESSAGES/messages.mo
index a998d5e1f..b13b7264f 100644
Binary files a/changedetectionio/translations/ja/LC_MESSAGES/messages.mo and b/changedetectionio/translations/ja/LC_MESSAGES/messages.mo differ
diff --git a/changedetectionio/translations/ja/LC_MESSAGES/messages.po b/changedetectionio/translations/ja/LC_MESSAGES/messages.po
index 3f947220a..4438c9baf 100644
--- a/changedetectionio/translations/ja/LC_MESSAGES/messages.po
+++ b/changedetectionio/translations/ja/LC_MESSAGES/messages.po
@@ -866,6 +866,10 @@ msgstr "稼働時間:"
msgid "Python version:"
msgstr "Pythonバージョン:"
+#: changedetectionio/blueprint/settings/templates/settings.html
+msgid "Maximum number of page watches:"
+msgstr "ページウォッチの最大数:"
+
#: changedetectionio/blueprint/settings/templates/settings.html
msgid "Plugins active:"
msgstr "有効なプラグイン:"
@@ -3985,6 +3989,11 @@ msgstr "ウェブページのテキスト/HTML、JSONおよびPDFの変更"
msgid "Detects all text changes where possible"
msgstr "可能な限りすべてのテキスト変更を検知します"
+#: changedetectionio/store/__init__.py
+#, python-brace-format
+msgid "Watch limit reached ({current}/{limit} watches). Cannot add more watches."
+msgstr "ウォッチの上限に達しました({current}/{limit} ウォッチ)。これ以上ウォッチを追加できません。"
+
#: changedetectionio/store/__init__.py
#, python-brace-format
msgid "Error fetching metadata for {}"
@@ -3994,11 +4003,6 @@ msgstr "{} のメタデータ取得中にエラーが発生しました"
msgid "Watch protocol is not permitted or invalid URL format"
msgstr "ウォッチのプロトコルが許可されていないか、URL形式が無効です"
-#: changedetectionio/store/__init__.py
-#, python-brace-format
-msgid "Watch limit reached ({current}/{limit} watches). Cannot add more watches."
-msgstr "ウォッチの上限に達しました({current}/{limit} ウォッチ)。これ以上ウォッチを追加できません。"
-
#: changedetectionio/templates/_common_fields.html
msgid "Body for all notifications — You can use"
msgstr "すべての通知の本文 — 以下を使用できます:"
diff --git a/changedetectionio/translations/ko/LC_MESSAGES/messages.mo b/changedetectionio/translations/ko/LC_MESSAGES/messages.mo
index 16c4b5a45..732915ccc 100644
Binary files a/changedetectionio/translations/ko/LC_MESSAGES/messages.mo and b/changedetectionio/translations/ko/LC_MESSAGES/messages.mo differ
diff --git a/changedetectionio/translations/ko/LC_MESSAGES/messages.po b/changedetectionio/translations/ko/LC_MESSAGES/messages.po
index b91ca21eb..4966b4cde 100644
--- a/changedetectionio/translations/ko/LC_MESSAGES/messages.po
+++ b/changedetectionio/translations/ko/LC_MESSAGES/messages.po
@@ -861,6 +861,10 @@ msgstr "가동 시간:"
msgid "Python version:"
msgstr "파이썬 버전:"
+#: changedetectionio/blueprint/settings/templates/settings.html
+msgid "Maximum number of page watches:"
+msgstr "최대 페이지 모니터링 수:"
+
#: changedetectionio/blueprint/settings/templates/settings.html
msgid "Plugins active:"
msgstr "활성화된 플러그인:"
@@ -3976,6 +3980,11 @@ msgstr "웹페이지 텍스트/HTML, JSON 및 PDF 변경"
msgid "Detects all text changes where possible"
msgstr "가능한 경우 모든 텍스트 변경 사항을 감지합니다."
+#: changedetectionio/store/__init__.py
+#, python-brace-format
+msgid "Watch limit reached ({current}/{limit} watches). Cannot add more watches."
+msgstr "모니터링 한도에 도달했습니다. ({current}/{limit}개) 더 이상 모니터링을 추가할 수 없습니다."
+
#: changedetectionio/store/__init__.py
#, python-brace-format
msgid "Error fetching metadata for {}"
@@ -3985,11 +3994,6 @@ msgstr "{}의 메타데이터를 가져오는 중 오류가 발생했습니다."
msgid "Watch protocol is not permitted or invalid URL format"
msgstr "모니터링 프로토콜이 허용되지 않거나 URL 형식이 올바르지 않습니다."
-#: changedetectionio/store/__init__.py
-#, python-brace-format
-msgid "Watch limit reached ({current}/{limit} watches). Cannot add more watches."
-msgstr "모니터링 한도에 도달했습니다. ({current}/{limit}개) 더 이상 모니터링을 추가할 수 없습니다."
-
#: changedetectionio/templates/_common_fields.html
msgid "Body for all notifications — You can use"
msgstr "모든 알림 본문 — 다음을 사용할 수 있습니다:"
diff --git a/changedetectionio/translations/messages.pot b/changedetectionio/translations/messages.pot
index dc3c06558..799488036 100644
--- a/changedetectionio/translations/messages.pot
+++ b/changedetectionio/translations/messages.pot
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: changedetection.io 0.55.8\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
-"POT-Creation-Date: 2026-09-01 19:10+0200\n"
+"POT-Creation-Date: 2026-09-02 12:06+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME \n"
"Language-Team: LANGUAGE \n"
@@ -858,6 +858,10 @@ msgstr ""
msgid "Python version:"
msgstr ""
+#: changedetectionio/blueprint/settings/templates/settings.html
+msgid "Maximum number of page watches:"
+msgstr ""
+
#: changedetectionio/blueprint/settings/templates/settings.html
msgid "Plugins active:"
msgstr ""
@@ -3965,6 +3969,11 @@ msgstr ""
msgid "Detects all text changes where possible"
msgstr ""
+#: changedetectionio/store/__init__.py
+#, python-brace-format
+msgid "Watch limit reached ({current}/{limit} watches). Cannot add more watches."
+msgstr ""
+
#: changedetectionio/store/__init__.py
#, python-brace-format
msgid "Error fetching metadata for {}"
@@ -3974,11 +3983,6 @@ msgstr ""
msgid "Watch protocol is not permitted or invalid URL format"
msgstr ""
-#: changedetectionio/store/__init__.py
-#, python-brace-format
-msgid "Watch limit reached ({current}/{limit} watches). Cannot add more watches."
-msgstr ""
-
#: changedetectionio/templates/_common_fields.html
msgid "Body for all notifications — You can use"
msgstr ""
diff --git a/changedetectionio/translations/pl/LC_MESSAGES/messages.mo b/changedetectionio/translations/pl/LC_MESSAGES/messages.mo
index 1686f7003..24b602563 100644
Binary files a/changedetectionio/translations/pl/LC_MESSAGES/messages.mo and b/changedetectionio/translations/pl/LC_MESSAGES/messages.mo differ
diff --git a/changedetectionio/translations/pl/LC_MESSAGES/messages.po b/changedetectionio/translations/pl/LC_MESSAGES/messages.po
index 819e032f0..720694d94 100644
--- a/changedetectionio/translations/pl/LC_MESSAGES/messages.po
+++ b/changedetectionio/translations/pl/LC_MESSAGES/messages.po
@@ -919,6 +919,10 @@ msgstr "Czas sprawności:"
msgid "Python version:"
msgstr "Wersja Pythona:"
+#: changedetectionio/blueprint/settings/templates/settings.html
+msgid "Maximum number of page watches:"
+msgstr "Maksymalna liczba obserwacji stron:"
+
#: changedetectionio/blueprint/settings/templates/settings.html
msgid "Plugins active:"
msgstr "Aktywne wtyczki:"
@@ -4127,6 +4131,11 @@ msgstr "Zmiany w treści stron internetowych (HTML), plikach JSON i PDF"
msgid "Detects all text changes where possible"
msgstr "W miarę możliwości wykrywa wszystkie zmiany w tekście"
+#: changedetectionio/store/__init__.py
+#, python-brace-format
+msgid "Watch limit reached ({current}/{limit} watches). Cannot add more watches."
+msgstr "Osiągnięto limit obserwacji ({current}/{limit}). Nie można dodać kolejnych obserwacji."
+
#: changedetectionio/store/__init__.py
#, python-brace-format
msgid "Error fetching metadata for {}"
@@ -4136,11 +4145,6 @@ msgstr "Wystąpił błąd podczas pobierania metadanych dla {}"
msgid "Watch protocol is not permitted or invalid URL format"
msgstr "Protokół „watch” jest niedozwolony lub format adresu URL jest nieprawidłowy"
-#: changedetectionio/store/__init__.py
-#, python-brace-format
-msgid "Watch limit reached ({current}/{limit} watches). Cannot add more watches."
-msgstr "Osiągnięto limit obserwacji ({current}/{limit}). Nie można dodać kolejnych obserwacji."
-
#: changedetectionio/templates/_common_fields.html
msgid "Body for all notifications — You can use"
msgstr "Treść wszystkich powiadomień — Można użyć"
diff --git a/changedetectionio/translations/pt_BR/LC_MESSAGES/messages.mo b/changedetectionio/translations/pt_BR/LC_MESSAGES/messages.mo
index 2662d3d71..7c8dcf41c 100644
Binary files a/changedetectionio/translations/pt_BR/LC_MESSAGES/messages.mo and b/changedetectionio/translations/pt_BR/LC_MESSAGES/messages.mo differ
diff --git a/changedetectionio/translations/pt_BR/LC_MESSAGES/messages.po b/changedetectionio/translations/pt_BR/LC_MESSAGES/messages.po
index 29b4e4617..7cb0343cc 100644
--- a/changedetectionio/translations/pt_BR/LC_MESSAGES/messages.po
+++ b/changedetectionio/translations/pt_BR/LC_MESSAGES/messages.po
@@ -884,6 +884,10 @@ msgstr "Tempo de atividade (Uptime):"
msgid "Python version:"
msgstr "Versão do Python:"
+#: changedetectionio/blueprint/settings/templates/settings.html
+msgid "Maximum number of page watches:"
+msgstr "Número máximo de monitoramentos de páginas:"
+
#: changedetectionio/blueprint/settings/templates/settings.html
msgid "Plugins active:"
msgstr "Plugins ativos:"
@@ -4016,6 +4020,11 @@ msgstr "Mudanças em Texto/HTML de páginas, JSON e PDF"
msgid "Detects all text changes where possible"
msgstr "Detecta todas as mudanças de texto onde possível"
+#: changedetectionio/store/__init__.py
+#, python-brace-format
+msgid "Watch limit reached ({current}/{limit} watches). Cannot add more watches."
+msgstr "Limite de monitoramentos atingido ({current}/{limit}). Não é possível adicionar mais."
+
#: changedetectionio/store/__init__.py
#, python-brace-format
msgid "Error fetching metadata for {}"
@@ -4025,11 +4034,6 @@ msgstr "Erro ao buscar metadados para {}"
msgid "Watch protocol is not permitted or invalid URL format"
msgstr "O protocolo de monitoramento não é permitido ou o formato da URL é inválido"
-#: changedetectionio/store/__init__.py
-#, python-brace-format
-msgid "Watch limit reached ({current}/{limit} watches). Cannot add more watches."
-msgstr "Limite de monitoramentos atingido ({current}/{limit}). Não é possível adicionar mais."
-
#: changedetectionio/templates/_common_fields.html
msgid "Body for all notifications — You can use"
msgstr "Corpo para todas as notificações — Você pode usar"
diff --git a/changedetectionio/translations/ru/LC_MESSAGES/messages.mo b/changedetectionio/translations/ru/LC_MESSAGES/messages.mo
index f331881ec..8a185022e 100644
Binary files a/changedetectionio/translations/ru/LC_MESSAGES/messages.mo and b/changedetectionio/translations/ru/LC_MESSAGES/messages.mo differ
diff --git a/changedetectionio/translations/ru/LC_MESSAGES/messages.po b/changedetectionio/translations/ru/LC_MESSAGES/messages.po
index 893081494..a27e90d78 100644
--- a/changedetectionio/translations/ru/LC_MESSAGES/messages.po
+++ b/changedetectionio/translations/ru/LC_MESSAGES/messages.po
@@ -898,6 +898,10 @@ msgstr "Время работы:"
msgid "Python version:"
msgstr "Версия Python:"
+#: changedetectionio/blueprint/settings/templates/settings.html
+msgid "Maximum number of page watches:"
+msgstr "Максимальное количество отслеживаний страниц:"
+
#: changedetectionio/blueprint/settings/templates/settings.html
msgid "Plugins active:"
msgstr "Плагины активны:"
@@ -4084,6 +4088,11 @@ msgstr "Изменения текста веб-страницы/HTML, JSON и PD
msgid "Detects all text changes where possible"
msgstr "Обнаруживает все изменения текста, где это возможно."
+#: changedetectionio/store/__init__.py
+#, python-brace-format
+msgid "Watch limit reached ({current}/{limit} watches). Cannot add more watches."
+msgstr "Достигнут лимит отслеживаний ({current}/{limit}). Больше добавить нельзя."
+
#: changedetectionio/store/__init__.py
#, python-brace-format
msgid "Error fetching metadata for {}"
@@ -4093,11 +4102,6 @@ msgstr "Ошибка при получении метаданных для {}."
msgid "Watch protocol is not permitted or invalid URL format"
msgstr "Протокол просмотра не разрешен или неверный формат URL."
-#: changedetectionio/store/__init__.py
-#, python-brace-format
-msgid "Watch limit reached ({current}/{limit} watches). Cannot add more watches."
-msgstr "Достигнут лимит просмотра (часы {current}/{limit}). Невозможно добавить больше часов."
-
#: changedetectionio/templates/_common_fields.html
msgid "Body for all notifications — You can use"
msgstr "Текст для всех уведомлений — вы можете использовать"
diff --git a/changedetectionio/translations/tr/LC_MESSAGES/messages.mo b/changedetectionio/translations/tr/LC_MESSAGES/messages.mo
index ed8593aef..0ce9c3e51 100644
Binary files a/changedetectionio/translations/tr/LC_MESSAGES/messages.mo and b/changedetectionio/translations/tr/LC_MESSAGES/messages.mo differ
diff --git a/changedetectionio/translations/tr/LC_MESSAGES/messages.po b/changedetectionio/translations/tr/LC_MESSAGES/messages.po
index 95f686a8c..42c99786f 100644
--- a/changedetectionio/translations/tr/LC_MESSAGES/messages.po
+++ b/changedetectionio/translations/tr/LC_MESSAGES/messages.po
@@ -894,6 +894,10 @@ msgstr "Çalışma Süresi:"
msgid "Python version:"
msgstr "Python sürümü:"
+#: changedetectionio/blueprint/settings/templates/settings.html
+msgid "Maximum number of page watches:"
+msgstr "Maksimum sayfa izleyici sayısı:"
+
#: changedetectionio/blueprint/settings/templates/settings.html
msgid "Plugins active:"
msgstr "Aktif eklentiler:"
@@ -4019,6 +4023,11 @@ msgstr "Web Sayfası Metin/HTML, JSON ve PDF değişiklikleri"
msgid "Detects all text changes where possible"
msgstr "Mümkün olan yerlerde tüm metin değişikliklerini tespit eder"
+#: changedetectionio/store/__init__.py
+#, python-brace-format
+msgid "Watch limit reached ({current}/{limit} watches). Cannot add more watches."
+msgstr "İzleyici sınırına ulaşıldı ({current}/{limit} izleyici). Daha fazla izleyici eklenemez."
+
#: changedetectionio/store/__init__.py
#, python-brace-format
msgid "Error fetching metadata for {}"
@@ -4028,11 +4037,6 @@ msgstr "{} için meta veri getirilirken hata oluştu"
msgid "Watch protocol is not permitted or invalid URL format"
msgstr "İzleyici protokolüne izin verilmiyor veya geçersiz URL formatı"
-#: changedetectionio/store/__init__.py
-#, python-brace-format
-msgid "Watch limit reached ({current}/{limit} watches). Cannot add more watches."
-msgstr "İzleyici sınırına ulaşıldı ({current}/{limit} izleyici). Daha fazla izleyici eklenemez."
-
#: changedetectionio/templates/_common_fields.html
msgid "Body for all notifications — You can use"
msgstr "Tüm bildirimler için gövde — Bildirim başlığı, gövdesi ve URL'sinde"
diff --git a/changedetectionio/translations/uk/LC_MESSAGES/messages.mo b/changedetectionio/translations/uk/LC_MESSAGES/messages.mo
index c9afed2ea..53a4d54aa 100644
Binary files a/changedetectionio/translations/uk/LC_MESSAGES/messages.mo and b/changedetectionio/translations/uk/LC_MESSAGES/messages.mo differ
diff --git a/changedetectionio/translations/uk/LC_MESSAGES/messages.po b/changedetectionio/translations/uk/LC_MESSAGES/messages.po
index f9f946ce6..37651049c 100644
--- a/changedetectionio/translations/uk/LC_MESSAGES/messages.po
+++ b/changedetectionio/translations/uk/LC_MESSAGES/messages.po
@@ -874,6 +874,10 @@ msgstr ""
msgid "Python version:"
msgstr "Версія Python:"
+#: changedetectionio/blueprint/settings/templates/settings.html
+msgid "Maximum number of page watches:"
+msgstr "Максимальна кількість завдань моніторингу:"
+
#: changedetectionio/blueprint/settings/templates/settings.html
msgid "Plugins active:"
msgstr "Активні плагіни:"
@@ -3998,6 +4002,11 @@ msgstr "Зміни тексту веб-сторінки/HTML, JSON та PDF"
msgid "Detects all text changes where possible"
msgstr "Виявляє всі текстові зміни, де це можливо"
+#: changedetectionio/store/__init__.py
+#, python-brace-format
+msgid "Watch limit reached ({current}/{limit} watches). Cannot add more watches."
+msgstr "Досягнуто ліміту завдань ({current}/{limit}). Неможливо додати більше."
+
#: changedetectionio/store/__init__.py
#, python-brace-format
msgid "Error fetching metadata for {}"
@@ -4007,11 +4016,6 @@ msgstr "Помилка отримання метаданих для {}"
msgid "Watch protocol is not permitted or invalid URL format"
msgstr "Протокол завдання не дозволено або невірний формат URL"
-#: changedetectionio/store/__init__.py
-#, python-brace-format
-msgid "Watch limit reached ({current}/{limit} watches). Cannot add more watches."
-msgstr "Досягнуто ліміту завдань ({current}/{limit}). Неможливо додати більше."
-
#: changedetectionio/templates/_common_fields.html
msgid "Body for all notifications — You can use"
msgstr "Тіло для всіх сповіщень — Ви можете використовувати"
diff --git a/changedetectionio/translations/zh/LC_MESSAGES/messages.mo b/changedetectionio/translations/zh/LC_MESSAGES/messages.mo
index 9f2e44b50..2db46c6e6 100644
Binary files a/changedetectionio/translations/zh/LC_MESSAGES/messages.mo and b/changedetectionio/translations/zh/LC_MESSAGES/messages.mo differ
diff --git a/changedetectionio/translations/zh/LC_MESSAGES/messages.po b/changedetectionio/translations/zh/LC_MESSAGES/messages.po
index 92f1aa2a5..e55e3c8c3 100644
--- a/changedetectionio/translations/zh/LC_MESSAGES/messages.po
+++ b/changedetectionio/translations/zh/LC_MESSAGES/messages.po
@@ -864,6 +864,10 @@ msgstr ""
msgid "Python version:"
msgstr "Python 版本:"
+#: changedetectionio/blueprint/settings/templates/settings.html
+msgid "Maximum number of page watches:"
+msgstr "最大监视器数量:"
+
#: changedetectionio/blueprint/settings/templates/settings.html
msgid "Plugins active:"
msgstr "已启用插件:"
@@ -3972,6 +3976,11 @@ msgstr "网页文本/HTML、JSON 和 PDF 变更"
msgid "Detects all text changes where possible"
msgstr "尽可能检测所有文本变更"
+#: changedetectionio/store/__init__.py
+#, python-brace-format
+msgid "Watch limit reached ({current}/{limit} watches). Cannot add more watches."
+msgstr "已达到监视器上限({current}/{limit})。无法添加更多。"
+
#: changedetectionio/store/__init__.py
#, python-brace-format
msgid "Error fetching metadata for {}"
@@ -3981,11 +3990,6 @@ msgstr "获取 {} 的元数据失败"
msgid "Watch protocol is not permitted or invalid URL format"
msgstr "监控协议不允许或 URL 格式无效"
-#: changedetectionio/store/__init__.py
-#, python-brace-format
-msgid "Watch limit reached ({current}/{limit} watches). Cannot add more watches."
-msgstr ""
-
#: changedetectionio/templates/_common_fields.html
msgid "Body for all notifications — You can use"
msgstr "所有通知的正文 — 您可以使用"
diff --git a/changedetectionio/translations/zh_Hant_TW/LC_MESSAGES/messages.mo b/changedetectionio/translations/zh_Hant_TW/LC_MESSAGES/messages.mo
index 8f4dc0f01..1860a57ba 100644
Binary files a/changedetectionio/translations/zh_Hant_TW/LC_MESSAGES/messages.mo and b/changedetectionio/translations/zh_Hant_TW/LC_MESSAGES/messages.mo differ
diff --git a/changedetectionio/translations/zh_Hant_TW/LC_MESSAGES/messages.po b/changedetectionio/translations/zh_Hant_TW/LC_MESSAGES/messages.po
index 2577b5484..e3695cdce 100644
--- a/changedetectionio/translations/zh_Hant_TW/LC_MESSAGES/messages.po
+++ b/changedetectionio/translations/zh_Hant_TW/LC_MESSAGES/messages.po
@@ -863,6 +863,10 @@ msgstr ""
msgid "Python version:"
msgstr "Python 版本:"
+#: changedetectionio/blueprint/settings/templates/settings.html
+msgid "Maximum number of page watches:"
+msgstr "最大監測任務數量:"
+
#: changedetectionio/blueprint/settings/templates/settings.html
msgid "Plugins active:"
msgstr "啟用的外掛:"
@@ -3972,6 +3976,11 @@ msgstr "網頁文字 / HTML、JSON 和 PDF 變更"
msgid "Detects all text changes where possible"
msgstr "盡可能檢測所有文字變更"
+#: changedetectionio/store/__init__.py
+#, python-brace-format
+msgid "Watch limit reached ({current}/{limit} watches). Cannot add more watches."
+msgstr "已達到監測任務上限({current}/{limit})。無法再新增。"
+
#: changedetectionio/store/__init__.py
#, python-brace-format
msgid "Error fetching metadata for {}"
@@ -3981,11 +3990,6 @@ msgstr "讀取 {} 的中繼資料時發生錯誤"
msgid "Watch protocol is not permitted or invalid URL format"
msgstr "監測協定不被允許或 URL 格式無效"
-#: changedetectionio/store/__init__.py
-#, python-brace-format
-msgid "Watch limit reached ({current}/{limit} watches). Cannot add more watches."
-msgstr ""
-
#: changedetectionio/templates/_common_fields.html
msgid "Body for all notifications — You can use"
msgstr "所有通知的內文 — 您可以使用"
diff --git a/docker-compose.yml b/docker-compose.yml
index 00ec49f81..17615aa4f 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -66,6 +66,10 @@ services:
# Absolute minimum seconds to recheck, overrides any watch minimum, change to 0 to disable
# - MINIMUM_SECONDS_RECHECK_TIME=3
#
+ # Cap the total number of watches this instance will hold - adding more (UI, API, import)
+ # is refused until one is deleted. Unset means unlimited.
+ # - PAGE_WATCH_LIMIT=100
+ #
# If you want to watch local files file:///path/to/file.txt (careful! security implications!)
# - ALLOW_FILE_URI=False
#
diff --git a/docs/api-spec.yaml b/docs/api-spec.yaml
index ed91e1b1e..182475a7d 100644
--- a/docs/api-spec.yaml
+++ b/docs/api-spec.yaml
@@ -28,7 +28,7 @@ info:
For example: `x-api-key: YOUR_API_KEY`
- version: 0.1.7
+ version: 0.1.8
contact:
name: ChangeDetection.io
url: https://github.com/dgtlmoon/changedetection.io
@@ -1046,6 +1046,15 @@ paths:
schema:
type: string
example: "OK"
+ '429':
+ description: |
+ Watch limit reached (server has `PAGE_WATCH_LIMIT` set; unlimited by default).
+ No watch was created - delete one to make room.
+ content:
+ text/plain:
+ schema:
+ type: string
+ example: "Watch limit reached (50/50 watches). Cannot add more watches."
'500':
description: Server error
content:
@@ -2140,6 +2149,16 @@ paths:
type: string
format: uuid
description: List of created watch UUIDs
+ '429':
+ description: |
+ Watch limit reached (server has `PAGE_WATCH_LIMIT` set; unlimited by default).
+ The batch is rejected whole - no watches are created - so the same request can be
+ retried unchanged once there is room.
+ content:
+ text/plain:
+ schema:
+ type: string
+ example: "Watch limit reached (48/50 watches), importing 5 URL(s) would exceed it. No watches were imported."
'500':
description: Server error
diff --git a/docs/api_v1/index.html b/docs/api_v1/index.html
index b5b9ba1b3..d55e2c82e 100644
--- a/docs/api_v1/index.html
+++ b/docs/api_v1/index.html
@@ -455,7 +455,7 @@ data-styled.g138[id="sc-enPhjR"]{content:"SikXG,"}/*!sc*/
55.627 l 55.6165,55.627 -231.245496,231.24803 c -127.185,127.1864
-231.5279,231.248 -231.873,231.248 -0.3451,0 -104.688,
-104.0616 -231.873,-231.248 z
- " fill="currentColor"> ChangeDetection.io API (0.1.7) Download OpenAPI specification:
ChangeDetection.io Web page monitoring and notifications APIChangeDetection.io API (0.1.8) Download OpenAPI specification:
ChangeDetection.io Web page monitoring and notifications APIREST API for managing Page watches, Group tags, and Notifications.
changedetection.io can be driven by its built in simple API, in the examples below you will also find curl command line and python examples to help you get started faster.
@@ -647,6 +647,10 @@ On a tag/group it is ternary and is that group's only AI control:
" class="sc-eVqvcJ sc-fszimp kIppRw drqpJr">
Whether llm_change_summary replaces the prompt inherited from the tag/global settings, or is appended to the end of it.
Responses 200 Web page change monitor (watch) created successfully
+
429 Watch limit reached (server has PAGE_WATCH_LIMIT set; unlimited by default).
+No watch was created - delete one to make room.
post /watch Skip duplicate URLs (default true)
Request Body schema: text/plain required
Responses 200 URLs imported successfully
+
429 Watch limit reached (server has PAGE_WATCH_LIMIT set; unlimited by default).
+The batch is rejected whole - no watches are created - so the same request can be
+retried unchanged once there is room.
post /import -X GET "http://localhost:5000/api/v1/full-spec"