From f4e178955caf2ce5edc329f7189a646bdec4929b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 15 Jan 2026 10:31:42 +0100 Subject: [PATCH 01/11] Bump pyppeteer-ng from 2.0.0rc10 to 2.0.0rc11 (#3742) --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 013150063..e329df85d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -91,7 +91,7 @@ jq~=1.3; python_version >= "3.8" and sys_platform == "linux" # playwright is installed at Dockerfile build time because it's not available on all platforms -pyppeteer-ng==2.0.0rc10 +pyppeteer-ng==2.0.0rc11 pyppeteerstealth>=0.0.4 # Include pytest, so if theres a support issue we can ask them to run these tests on their setup From 06ea29bfc7364092cf92a5229d2329fabb21e04e Mon Sep 17 00:00:00 2001 From: dgtlmoon Date: Thu, 15 Jan 2026 12:01:12 +0100 Subject: [PATCH 02/11] Translations - Fixing `zh_TW` to `zh_Hant_TW` , adding tests #3737 (#3744) --- changedetectionio/flask_app.py | 24 +++++++--- changedetectionio/languages.py | 4 +- changedetectionio/templates/base.html | 2 +- changedetectionio/tests/test_i18n.py | 45 ++++++++++++++++++ .../LC_MESSAGES/messages.mo | Bin .../LC_MESSAGES/messages.po | 0 6 files changed, 66 insertions(+), 9 deletions(-) rename changedetectionio/translations/{zh_TW => zh_Hant_TW}/LC_MESSAGES/messages.mo (100%) rename changedetectionio/translations/{zh_TW => zh_Hant_TW}/LC_MESSAGES/messages.po (100%) diff --git a/changedetectionio/flask_app.py b/changedetectionio/flask_app.py index a1545db26..d1e438ea5 100644 --- a/changedetectionio/flask_app.py +++ b/changedetectionio/flask_app.py @@ -9,6 +9,7 @@ import threading import time import timeago from blinker import signal +from pathlib import Path from changedetectionio.strtobool import strtobool from threading import Event @@ -84,6 +85,10 @@ app.config['NEW_VERSION_AVAILABLE'] = False if os.getenv('FLASK_SERVER_NAME'): app.config['SERVER_NAME'] = os.getenv('FLASK_SERVER_NAME') +# Babel/i18n configuration +app.config['BABEL_TRANSLATION_DIRECTORIES'] = str(Path(__file__).parent / 'translations') +app.config['BABEL_DEFAULT_LOCALE'] = 'en_GB' + #app.config["EXPLAIN_TEMPLATE_LOADING"] = True @@ -395,13 +400,9 @@ def changedetection_app(config=None, datastore_o=None): def get_locale(): # 1. Try to get locale from session (user explicitly selected) if 'locale' in session: - locale = session['locale'] - logger.trace(f"DEBUG: get_locale() returning from session: {locale}") - return locale + return session['locale'] # 2. Fall back to Accept-Language header - locale = request.accept_languages.best_match(language_codes) - logger.trace(f"DEBUG: get_locale() returning from Accept-Language: {locale}") - return locale + return request.accept_languages.best_match(language_codes) # Initialize Babel with locale selector babel = Babel(app, locale_selector=get_locale) @@ -518,9 +519,20 @@ def changedetection_app(config=None, datastore_o=None): @app.route('/set-language/') def set_language(locale): """Set the user's preferred language in the session""" + if not request.cookies: + logger.error("Cannot set language without session cookie") + flash("Cannot set language without session cookie", 'error') + return redirect(url_for('watchlist.index')) + # Validate the locale against available languages if locale in language_codes: session['locale'] = locale + + # CRITICAL: Flask-Babel caches the locale in the request context (ctx.babel_locale) + # We must refresh to clear this cache so the new locale takes effect immediately + # This is especially important for tests where multiple requests happen rapidly + from flask_babel import refresh + refresh() else: logger.error(f"Invalid locale {locale}, available: {language_codes}") diff --git a/changedetectionio/languages.py b/changedetectionio/languages.py index e6552d716..c169de9cf 100644 --- a/changedetectionio/languages.py +++ b/changedetectionio/languages.py @@ -29,7 +29,7 @@ def get_timeago_locale(flask_locale): """ locale_map = { 'zh': 'zh_CN', # Chinese Simplified - 'zh_Hant_TW': 'zh_TW', # Flask-Babel normalizes zh_TW to zh_Hant_TW + 'zh_TW': 'zh_Hant_TW', # Flask-Babel normalizes zh_TW to zh_Hant_TW 'pt': 'pt_PT', # Portuguese (Portugal) 'sv': 'sv_SE', # Swedish 'no': 'nb_NO', # Norwegian Bokmål @@ -54,7 +54,7 @@ LANGUAGE_DATA = { 'it': {'flag': 'fi fi-it fis', 'name': 'Italiano'}, 'ja': {'flag': 'fi fi-jp fis', 'name': '日本語'}, 'zh': {'flag': 'fi fi-cn fis', 'name': '中文 (简体)'}, - 'zh_TW': {'flag': 'fi fi-tw fis', 'name': '繁體中文'}, + 'zh_Hant_TW': {'flag': 'fi fi-tw fis', 'name': '繁體中文'}, 'ru': {'flag': 'fi fi-ru fis', 'name': 'Русский'}, 'pl': {'flag': 'fi fi-pl fis', 'name': 'Polski'}, 'nl': {'flag': 'fi fi-nl fis', 'name': 'Nederlands'}, diff --git a/changedetectionio/templates/base.html b/changedetectionio/templates/base.html index 35df0b70a..cc29d399d 100644 --- a/changedetectionio/templates/base.html +++ b/changedetectionio/templates/base.html @@ -1,5 +1,5 @@ - + diff --git a/changedetectionio/tests/test_i18n.py b/changedetectionio/tests/test_i18n.py index 76fa8f3e9..8f1b738ff 100644 --- a/changedetectionio/tests/test_i18n.py +++ b/changedetectionio/tests/test_i18n.py @@ -3,6 +3,39 @@ from flask import url_for from .util import live_server_setup +def test_zh_TW(client, live_server, measure_memory_usage, datastore_path): + + # Be sure we got a session cookie + res = client.get(url_for("watchlist.index"), follow_redirects=True) + + res = client.get( + url_for("set_language", locale="zh_Hant_TW"), # Traditional + follow_redirects=True + ) + # HTML follows BCP 47 language tag rules, not underscore-based locale formats. + assert b'zh + res = client.get( + url_for("set_language", locale="zh"), # Simplified chinese + follow_redirects=True + ) + res = client.get(url_for("watchlist.index"), follow_redirects=True) + assert "选择语言".encode() in res.data, "Simplified chinese worked and it means the flask-babel cache worked" + + + def test_language_switching(client, live_server, measure_memory_usage, datastore_path): """ @@ -13,6 +46,9 @@ def test_language_switching(client, live_server, measure_memory_usage, datastore 3. Switch back to English and verify English text appears """ + # Establish session cookie + client.get(url_for("watchlist.index"), follow_redirects=True) + # Step 1: Set the language to Italian using the /set-language endpoint res = client.get( url_for("set_language", locale="it"), @@ -61,6 +97,9 @@ def test_invalid_locale(client, live_server, measure_memory_usage, datastore_pat The app should ignore invalid locales and continue working. """ + # Establish session cookie + client.get(url_for("watchlist.index"), follow_redirects=True) + # First set to English res = client.get( url_for("set_language", locale="en"), @@ -93,6 +132,9 @@ def test_language_persistence_in_session(client, live_server, measure_memory_usa within the same session. """ + # Establish session cookie + client.get(url_for("watchlist.index"), follow_redirects=True) + # Set language to Italian res = client.get( url_for("set_language", locale="it"), @@ -119,6 +161,9 @@ def test_set_language_with_redirect(client, live_server, measure_memory_usage, d """ from flask import url_for + # Establish session cookie + client.get(url_for("watchlist.index"), follow_redirects=True) + # Set language with a redirect parameter (simulating language change from /settings) res = client.get( url_for("set_language", locale="de", redirect="/settings"), diff --git a/changedetectionio/translations/zh_TW/LC_MESSAGES/messages.mo b/changedetectionio/translations/zh_Hant_TW/LC_MESSAGES/messages.mo similarity index 100% rename from changedetectionio/translations/zh_TW/LC_MESSAGES/messages.mo rename to changedetectionio/translations/zh_Hant_TW/LC_MESSAGES/messages.mo diff --git a/changedetectionio/translations/zh_TW/LC_MESSAGES/messages.po b/changedetectionio/translations/zh_Hant_TW/LC_MESSAGES/messages.po similarity index 100% rename from changedetectionio/translations/zh_TW/LC_MESSAGES/messages.po rename to changedetectionio/translations/zh_Hant_TW/LC_MESSAGES/messages.po From 3e364e0eba44fe65402d2a8b1865c6784b45defe Mon Sep 17 00:00:00 2001 From: dgtlmoon Date: Thu, 15 Jan 2026 12:24:53 +0100 Subject: [PATCH 03/11] Translations - ZH_Hant_TW - Fixing `timeago` string handling #3737 --- changedetectionio/languages.py | 4 +++- changedetectionio/tests/test_i18n.py | 33 +++++++++++++++++++++++++++- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/changedetectionio/languages.py b/changedetectionio/languages.py index c169de9cf..42a9d4c0c 100644 --- a/changedetectionio/languages.py +++ b/changedetectionio/languages.py @@ -29,7 +29,9 @@ def get_timeago_locale(flask_locale): """ locale_map = { 'zh': 'zh_CN', # Chinese Simplified - 'zh_TW': 'zh_Hant_TW', # Flask-Babel normalizes zh_TW to zh_Hant_TW + # timeago library just hasn't been updated to use the more modern locale naming convention, before BCP 47 / RFC 5646. + 'zh_TW': 'zh_TW', # Chinese Traditional (timeago uses zh_TW) + 'zh_Hant_TW': 'zh_TW', # Flask-Babel normalizes zh_TW to zh_Hant_TW, map back to timeago's zh_TW 'pt': 'pt_PT', # Portuguese (Portugal) 'sv': 'sv_SE', # Swedish 'no': 'nb_NO', # Norwegian Bokmål diff --git a/changedetectionio/tests/test_i18n.py b/changedetectionio/tests/test_i18n.py index 8f1b738ff..8643427c7 100644 --- a/changedetectionio/tests/test_i18n.py +++ b/changedetectionio/tests/test_i18n.py @@ -1,9 +1,12 @@ #!/usr/bin/env python3 from flask import url_for -from .util import live_server_setup +from .util import live_server_setup, wait_for_all_checks + def test_zh_TW(client, live_server, measure_memory_usage, datastore_path): + import time + test_url = url_for('test_endpoint', _external=True) # Be sure we got a session cookie res = client.get(url_for("watchlist.index"), follow_redirects=True) @@ -35,6 +38,34 @@ def test_zh_TW(client, live_server, measure_memory_usage, datastore_path): assert "选择语言".encode() in res.data, "Simplified chinese worked and it means the flask-babel cache worked" +# timeago library just hasn't been updated to use the more modern locale naming convention, before BCP 47 / RFC 5646. +# The Python timeago library (https://github.com/hustcc/timeago) supports 48 locales but uses different naming conventions than Flask-Babel. +def test_zh_Hant_TW_timeago_integration(): + """Test that zh_Hant_TW mapping works and timeago renders Traditional Chinese correctly""" + import timeago + from datetime import datetime, timedelta + from changedetectionio.languages import get_timeago_locale + + # 1. Test the mapping + mapped_locale = get_timeago_locale('zh_Hant_TW') + assert mapped_locale == 'zh_TW', "zh_Hant_TW should map to timeago's zh_TW" + assert get_timeago_locale('zh_TW') == 'zh_TW', "zh_TW should also map to zh_TW" + + # 2. Test timeago library renders Traditional Chinese with the mapped locale + now = datetime.now() + + # Test various time periods with Traditional Chinese strings + result_15s = timeago.format(now - timedelta(seconds=15), now, mapped_locale) + assert '秒前' in result_15s, f"Expected '秒前' in '{result_15s}'" + + result_5m = timeago.format(now - timedelta(minutes=5), now, mapped_locale) + assert '分鐘前' in result_5m, f"Expected '分鐘前' in '{result_5m}'" + + result_2h = timeago.format(now - timedelta(hours=2), now, mapped_locale) + assert '小時前' in result_2h, f"Expected '小時前' in '{result_2h}'" + + result_3d = timeago.format(now - timedelta(days=3), now, mapped_locale) + assert '天前' in result_3d, f"Expected '天前' in '{result_3d}'" def test_language_switching(client, live_server, measure_memory_usage, datastore_path): From 68354cf53de42b695670b449143b5ace403b613c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 15 Jan 2026 13:03:16 +0100 Subject: [PATCH 04/11] Update jsonschema requirement from ~=4.25 to ~=4.26 (#3743) --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index e329df85d..c9777823c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -100,7 +100,7 @@ pytest-flask ~=1.3 pytest-mock ~=3.15 # Anything 4.0 and up but not 5.0 -jsonschema ~= 4.25 +jsonschema ~= 4.26 # OpenAPI validation support openapi-core[flask] >= 0.19.0 From 3b2b74e62d06bd656649d9b514ed4c43746423d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=BB=85=C3=BC?= <53787985+LaiYueTing@users.noreply.github.com> Date: Thu, 15 Jan 2026 20:12:25 +0800 Subject: [PATCH 05/11] i18n: Update zh_Hant_TW translations (#3745) --- .../zh_Hant_TW/LC_MESSAGES/messages.mo | Bin 23562 -> 41490 bytes .../zh_Hant_TW/LC_MESSAGES/messages.po | 1409 ++++++----------- 2 files changed, 469 insertions(+), 940 deletions(-) diff --git a/changedetectionio/translations/zh_Hant_TW/LC_MESSAGES/messages.mo b/changedetectionio/translations/zh_Hant_TW/LC_MESSAGES/messages.mo index 781a94ecce86f666fd522b2d844be03cc6a8e812..a4499f4303cea8b5bb30a935141531a7b28debc8 100644 GIT binary patch literal 41490 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 CS>0~{ literal 23562 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 WhBaq=7WUG\n" "Language: zh_Hant_TW\n" "Language-Team: zh_Hant_TW \n" @@ -27,59 +27,55 @@ msgstr "還沒有" #: changedetectionio/flask_app.py:534 msgid "Already logged in" -msgstr "" +msgstr "已經登入" #: changedetectionio/flask_app.py:536 msgid "You must be logged in, please log in." -msgstr "" +msgstr "您必須先登入,請登入。" #: changedetectionio/flask_app.py:551 -#, fuzzy msgid "Incorrect password" -msgstr "密碼" +msgstr "密碼錯誤" #: changedetectionio/forms.py:63 changedetectionio/forms.py:243 msgid "" "At least one time interval (weeks, days, hours, minutes, or seconds) must" " be specified." -msgstr "" +msgstr "必須指定至少一個時間間隔(週、天、小時、分鐘或秒)。" #: changedetectionio/forms.py:64 msgid "" "At least one time interval (weeks, days, hours, minutes, or seconds) must" " be specified when not using global settings." -msgstr "" +msgstr "當不使用全域設定時,必須指定至少一個時間間隔(週、天、小時、分鐘或秒)。" #: changedetectionio/forms.py:164 msgid "Invalid time format. Use HH:MM." -msgstr "時間格式無效。使用時:分。" +msgstr "時間格式無效。請使用 HH:MM。" #: changedetectionio/forms.py:180 msgid "Not a valid timezone name" msgstr "不是有效的時區名稱" #: changedetectionio/forms.py:183 -#, fuzzy msgid "not set" -msgstr "還沒有" +msgstr "未設定" #: changedetectionio/forms.py:184 -#, fuzzy msgid "Start At" -msgstr "統計數據" +msgstr "開始於" #: changedetectionio/forms.py:185 -#, fuzzy msgid "Run duration" -msgstr "暫無信息" +msgstr "執行時長" #: changedetectionio/forms.py:188 msgid "Use time scheduler" -msgstr "使用時間調度器" +msgstr "使用時間排程器" #: changedetectionio/forms.py:198 msgid "Optional timezone to run in" -msgstr "運行時的可選時區" +msgstr "執行時的選用時區" #: changedetectionio/forms.py:212 msgid "Monday" @@ -99,7 +95,7 @@ msgstr "週四" #: changedetectionio/forms.py:216 msgid "Friday" -msgstr "星期五" +msgstr "週五" #: changedetectionio/forms.py:217 msgid "Saturday" @@ -107,77 +103,74 @@ msgstr "週六" #: changedetectionio/forms.py:218 msgid "Sunday" -msgstr "星期日" +msgstr "週日" #: changedetectionio/forms.py:251 msgid "Weeks" -msgstr "週數" +msgstr "週" #: changedetectionio/forms.py:251 changedetectionio/forms.py:252 #: changedetectionio/forms.py:253 changedetectionio/forms.py:254 #: changedetectionio/forms.py:255 changedetectionio/forms.py:955 msgid "Should contain zero or more seconds" -msgstr "應包含零或更多秒" +msgstr "應包含 0 或更多秒" #: changedetectionio/forms.py:252 msgid "Days" msgstr "天" #: changedetectionio/forms.py:253 -#, fuzzy msgid "Hours" -msgstr "字" +msgstr "小時" #: changedetectionio/forms.py:254 -#, fuzzy msgid "Minutes" -msgstr "沉默的" +msgstr "分鐘" #: changedetectionio/forms.py:255 -#, fuzzy msgid "Seconds" msgstr "秒" #: changedetectionio/forms.py:460 msgid "Notification Body and Title is required when a Notification URL is used" -msgstr "使用通知 URL 時需要通知正文和標題" +msgstr "使用通知 URL 時,必須填寫通知內容與標題" #: changedetectionio/forms.py:489 #, python-format msgid "'%s' is not a valid AppRise URL." -msgstr "“%s”不是有效的 AppRise URL。" +msgstr "「%s」不是有效的 AppRise URL。" #: changedetectionio/forms.py:562 changedetectionio/forms.py:581 #, python-format msgid "RegEx '%s' is not a valid regular expression." -msgstr "RegEx“%s”不是有效的正則表達式。" +msgstr "RegEx 「%s」不是有效的正規表示式。" #: changedetectionio/forms.py:622 changedetectionio/forms.py:637 #, python-format msgid "'%s' is not a valid XPath expression. (%s)" -msgstr "“%s”不是有效的 XPath 表達式。 (%s)" +msgstr "「%s」不是有效的 XPath 表達式 (%s)。" #: changedetectionio/forms.py:657 #, python-format msgid "'%s' is not a valid JSONPath expression. (%s)" -msgstr "“%s”不是有效的 JSONPath 表達式。 (%s)" +msgstr "「%s」不是有效的 JSONPath 表達式 (%s)。" #: changedetectionio/forms.py:679 #, python-format msgid "'%s' is not a valid jq expression. (%s)" -msgstr "“%s”不是有效的 jq 表達式。 (%s)" +msgstr "「%s」不是有效的 jq 表達式 (%s)。" #: changedetectionio/forms.py:725 msgid "Empty value not allowed." -msgstr "不允許為空值。" +msgstr "不允許空值。" #: changedetectionio/forms.py:727 msgid "Invalid value." -msgstr "無效值。" +msgstr "數值無效。" #: changedetectionio/forms.py:732 msgid "Watch" -msgstr "監控" +msgstr "監測任務" #: changedetectionio/forms.py:733 changedetectionio/forms.py:766 msgid "Processor" @@ -185,101 +178,87 @@ msgstr "處理器" #: changedetectionio/forms.py:734 msgid "Edit > Watch" -msgstr "編輯 > 監控" +msgstr "編輯 > 監測任務" #: changedetectionio/forms.py:747 changedetectionio/forms.py:994 -#, fuzzy msgid "Fetch Method" -msgstr "設置獲取方法" +msgstr "抓取方式" #: changedetectionio/forms.py:748 -#, fuzzy msgid "Notification Body" -msgstr "通知" +msgstr "通知內容" #: changedetectionio/forms.py:749 -#, fuzzy msgid "Notification format" -msgstr "通知" +msgstr "通知格式" #: changedetectionio/forms.py:750 -#, fuzzy msgid "Notification Title" -msgstr "通知" +msgstr "通知標題" #: changedetectionio/forms.py:751 -#, fuzzy msgid "Notification URL List" -msgstr "通知" +msgstr "通知 URL 列表" #: changedetectionio/forms.py:752 msgid "Processor - What do you want to achieve?" -msgstr "處理器 - 您想要實現什麼?" +msgstr "處理器 - 您想要達成什麼目標?" #: changedetectionio/forms.py:753 msgid "Default timezone for watch check scheduler" -msgstr "手錶檢查調度程序的默認時區" +msgstr "監測排程的預設時區" #: changedetectionio/forms.py:754 -#, fuzzy msgid "Wait seconds before extracting text" -msgstr "提取文本前幾秒。" +msgstr "提取文字前的等待秒數" #: changedetectionio/forms.py:754 msgid "Should contain one or more seconds" -msgstr "應包含一秒或多秒" +msgstr "應包含 1 秒或更多秒" #: changedetectionio/forms.py:767 -#, fuzzy msgid "URLs" -msgstr "網址" +msgstr "URL 列表" #: changedetectionio/forms.py:768 msgid "Upload .xlsx file" -msgstr "上傳 .xlsx 文件" +msgstr "上傳 .xlsx 檔案" #: changedetectionio/forms.py:768 msgid "Must be .xlsx file!" -msgstr "必須是 .xlsx 文件!" +msgstr "必須是 .xlsx 檔案!" #: changedetectionio/forms.py:769 -#, fuzzy msgid "File mapping" -msgstr "文件映射類型。" +msgstr "檔案對應" #: changedetectionio/forms.py:773 -#, fuzzy msgid "Operation" -msgstr "用戶界面選項" +msgstr "操作" #: changedetectionio/forms.py:776 -#, fuzzy msgid "Selector" -msgstr "選擇方式:" +msgstr "選擇器" #: changedetectionio/forms.py:777 -#, fuzzy msgid "value" -msgstr "暫停" +msgstr "值" #: changedetectionio/forms.py:796 msgid "Use global settings for time between check and scheduler." -msgstr "使用全局設置檢查和調度程序之間的時間。" +msgstr "檢查與排程時間使用全域設定。" #: changedetectionio/forms.py:798 -#, fuzzy msgid "CSS/JSONPath/JQ/XPath Filters" -msgstr "CSS/xPath 過濾器" +msgstr "CSS / JSONPath / JQ / XPath 過濾器" #: changedetectionio/forms.py:800 changedetectionio/forms.py:996 -#, fuzzy msgid "Remove elements" -msgstr "按元素選擇" +msgstr "移除元素" #: changedetectionio/forms.py:802 -#, fuzzy msgid "Extract text" -msgstr "提取數據" +msgstr "提取文字" #: changedetectionio/blueprint/imports/templates/import.html:106 #: changedetectionio/forms.py:804 @@ -287,81 +266,74 @@ msgid "Title" msgstr "標題" #: changedetectionio/forms.py:806 -#, fuzzy msgid "Ignore lines containing" -msgstr "忽略任何匹配的行" +msgstr "忽略包含此內容的行" #: changedetectionio/forms.py:808 -#, fuzzy msgid "Request body" -msgstr "要求" +msgstr "請求內容" #: changedetectionio/forms.py:809 -#, fuzzy msgid "Request method" -msgstr "要求" +msgstr "請求方式" #: changedetectionio/forms.py:810 msgid "Ignore status codes (process non-2xx status codes as normal)" -msgstr "忽略狀態代碼(正常處理非 2xx 狀態代碼)" +msgstr "忽略狀態碼(將非 2xx 狀態碼視為正常處理)" #: changedetectionio/forms.py:811 -#, fuzzy msgid "Only trigger when unique lines appear in all history" -msgstr "僅當出現唯一線條時觸發" +msgstr "僅當歷史記錄中出現獨特行時觸發" #: changedetectionio/blueprint/ui/templates/edit.html:336 #: changedetectionio/forms.py:812 msgid "Remove duplicate lines of text" -msgstr "刪除重複的文本行" +msgstr "移除重複的文字行" #: changedetectionio/forms.py:813 msgid "Sort text alphabetically" -msgstr "按字母順序對文本進行排序" +msgstr "按字母順序排序文字" #: changedetectionio/forms.py:814 changedetectionio/forms.py:1023 msgid "Strip ignored lines" -msgstr "去掉忽略的行" +msgstr "移除被忽略的行" #: changedetectionio/forms.py:815 -#, fuzzy msgid "Trim whitespace before and after text" -msgstr "刪除每行文本前後的所有空格" +msgstr "移除文字前後的空白" #: changedetectionio/forms.py:817 -#, fuzzy msgid "Added lines" -msgstr "線路" +msgstr "新增的行" #: changedetectionio/forms.py:818 msgid "Replaced/changed lines" -msgstr "更換/更改線路" +msgstr "替換 / 變更的行" #: changedetectionio/forms.py:819 -#, fuzzy msgid "Removed lines" -msgstr "已刪除" +msgstr "移除的行" #: changedetectionio/forms.py:821 msgid "Keyword triggers - Trigger/wait for text" -msgstr "關鍵字觸發器 - 觸發/等待文本" +msgstr "關鍵字觸發 - 觸發 / 等待文字" #: changedetectionio/forms.py:824 msgid "Block change-detection while text matches" -msgstr "文本匹配時阻止更改檢測" +msgstr "當文字符合時,阻擋變更檢測" #: changedetectionio/forms.py:825 msgid "Execute JavaScript before change detection" -msgstr "在更改檢測之前執行 JavaScript" +msgstr "在變更檢測前執行 JavaScript" #: changedetectionio/blueprint/tags/templates/groups-overview.html:17 #: changedetectionio/forms.py:827 changedetectionio/forms.py:1051 msgid "Save" -msgstr "節省" +msgstr "儲存" #: changedetectionio/forms.py:829 msgid "Proxy" -msgstr "代理" +msgstr "代理伺服器" #: changedetectionio/forms.py:831 msgid "Send a notification when the filter can no longer be found on the page" @@ -375,54 +347,52 @@ msgid "Notifications" msgstr "通知" #: changedetectionio/forms.py:832 -#, fuzzy msgid "Muted" -msgstr "沉默的" +msgstr "已靜音" #: changedetectionio/forms.py:832 -#, fuzzy msgid "On" -msgstr "沒有任何" +msgstr "開啟" #: changedetectionio/forms.py:833 msgid "Attach screenshot to notification (where possible)" -msgstr "將屏幕截圖附加到通知(如果可能)" +msgstr "將截圖附加到通知中(如果支援)" #: changedetectionio/forms.py:835 msgid "Match" -msgstr "# 手錶" +msgstr "符合" #: changedetectionio/forms.py:835 msgid "Match all of the following" -msgstr "匹配以下所有內容" +msgstr "符合以下所有條件" #: changedetectionio/forms.py:835 msgid "Match any of the following" -msgstr "匹配以下任意一項" +msgstr "符合以下任一條件" #: changedetectionio/forms.py:837 msgid "Use page in list" -msgstr "使用列表中的頁面<標題>" +msgstr "在列表中使用頁面 <title>" #: changedetectionio/forms.py:854 msgid "Body must be empty when Request Method is set to GET" -msgstr "當請求方法設置為 GET 時,正文必須為空" +msgstr "當請求方法設為 GET 時,內容必須為空" #: changedetectionio/forms.py:863 changedetectionio/forms.py:877 #: changedetectionio/forms.py:892 #, python-format msgid "Invalid template syntax configuration: %(error)s" -msgstr "模板語法配置無效:%(error)s" +msgstr "範本語法設定無效:%(error)s" #: changedetectionio/forms.py:867 changedetectionio/forms.py:881 #, python-format msgid "Invalid template syntax: %(error)s" -msgstr "無效的模板語法:%(error)s" +msgstr "無效的範本語法:%(error)s" #: changedetectionio/forms.py:896 #, python-format msgid "Invalid template syntax in \"%(header)s\" header: %(error)s" -msgstr "" +msgstr "「%(header)s」標頭中的範本語法無效:%(error)s" #: changedetectionio/forms.py:920 changedetectionio/forms.py:932 msgid "Name" @@ -430,15 +400,15 @@ msgstr "名稱" #: changedetectionio/forms.py:921 msgid "Proxy URL" -msgstr "代理網址" +msgstr "代理伺服器 URL" #: changedetectionio/forms.py:926 msgid "Proxy URLs must start with http://, https:// or socks5://" -msgstr "代理 URL 必須以 http://、https:// 或ocks5:// 開頭" +msgstr "代理伺服器 URL 必須以 http://、https:// 或 socks5:// 開頭" #: changedetectionio/forms.py:933 msgid "Browser connection URL" -msgstr "瀏覽器連接網址" +msgstr "瀏覽器連線 URL" #: changedetectionio/forms.py:938 msgid "Browser URLs must start with wss:// or ws://" @@ -446,23 +416,23 @@ msgstr "瀏覽器 URL 必須以 wss:// 或 ws:// 開頭" #: changedetectionio/forms.py:944 msgid "Plaintext requests" -msgstr "明文請求" +msgstr "純文字請求" #: changedetectionio/forms.py:946 msgid "Chrome requests" -msgstr "Chrome請求" +msgstr "Chrome 請求" #: changedetectionio/forms.py:952 msgid "Default proxy" -msgstr "默認代理" +msgstr "預設代理伺服器" #: changedetectionio/forms.py:953 msgid "Random jitter seconds ± check" -msgstr "隨機抖動秒±檢查" +msgstr "隨機抖動秒數 ± 檢查" #: changedetectionio/forms.py:957 msgid "Number of fetch workers" -msgstr "取貨工人數量" +msgstr "抓取工作程序 (Worker) 數量" #: changedetectionio/forms.py:960 msgid "Should be between 1 and 50" @@ -470,7 +440,7 @@ msgstr "應介於 1 到 50 之間" #: changedetectionio/forms.py:962 msgid "Requests timeout in seconds" -msgstr "請求超時(以秒為單位)" +msgstr "請求逾時(秒)" #: changedetectionio/forms.py:965 msgid "Should be between 1 and 999" @@ -478,51 +448,47 @@ msgstr "應介於 1 到 999 之間" #: changedetectionio/forms.py:970 msgid "Default User-Agent overrides" -msgstr "默認用戶代理覆蓋" +msgstr "預設 User-Agent 覆寫" #: changedetectionio/forms.py:976 msgid "Both a name, and a Proxy URL is required." -msgstr "名稱和代理 URL 都是必需的。" +msgstr "名稱與代理伺服器 URL 皆為必填。" #: changedetectionio/forms.py:980 msgid "Open 'History' page in a new tab" -msgstr "在新選項卡中打開“歷史記錄”頁面" +msgstr "在新分頁開啟「歷史記錄」頁面" #: changedetectionio/forms.py:981 -#, fuzzy msgid "Realtime UI Updates Enabled" -msgstr "離線實時更新" +msgstr "已啟用即時 UI 更新" #: changedetectionio/forms.py:982 -#, fuzzy msgid "Favicons Enabled" -msgstr "考慮啟用" +msgstr "啟用網站圖示 (Favicons)" #: changedetectionio/forms.py:983 msgid "Use page <title> in watch overview list" -msgstr "在觀看概覽列表中使用頁面<標題>" +msgstr "在監測概覽列表中使用頁面 <title>" #: changedetectionio/forms.py:988 msgid "API access token security check enabled" -msgstr "已啟用 API 訪問令牌安全檢查" +msgstr "已啟用 API 存取權杖安全檢查" #: changedetectionio/forms.py:989 msgid "Notification base URL override" -msgstr "通知基礎URL" +msgstr "通知基礎 URL 覆寫" #: changedetectionio/forms.py:993 msgid "Treat empty pages as a change?" -msgstr "將空頁視為更改?" +msgstr "將空白頁面視為變更?" #: changedetectionio/forms.py:995 -#, fuzzy msgid "Ignore Text" -msgstr "錯誤文本" +msgstr "忽略文字" #: changedetectionio/forms.py:997 -#, fuzzy msgid "Ignore whitespace" -msgstr "忽略空格" +msgstr "忽略空白" #: changedetectionio/forms.py:1004 #: changedetectionio/processors/image_ssim_diff/forms.py:50 @@ -531,11 +497,11 @@ msgstr "必須介於 0 到 100 之間" #: changedetectionio/forms.py:1011 msgid "Pager size" -msgstr "尋呼機尺寸" +msgstr "分頁大小" #: changedetectionio/forms.py:1014 msgid "Should be atleast zero (disabled)" -msgstr "應至少為零(禁用)" +msgstr "應至少為 0(停用)" #: changedetectionio/forms.py:1016 msgid "RSS Content format" @@ -543,78 +509,76 @@ msgstr "RSS 內容格式" #: changedetectionio/forms.py:1017 msgid "RSS <description> body built from" -msgstr "RSS <描述> 正文構建於" +msgstr "RSS <description> 內容建立自" #: changedetectionio/forms.py:1018 msgid "RSS \"System default\" template override" -msgstr "" +msgstr "RSS「系統預設」範本覆寫" #: changedetectionio/forms.py:1020 -#, fuzzy msgid "Remove password" -msgstr "密碼" +msgstr "移除密碼" #: changedetectionio/forms.py:1021 msgid "Render anchor tag content" -msgstr "渲染錨標記內容" +msgstr "渲染錨點標籤內容" #: changedetectionio/forms.py:1022 msgid "Allow anonymous access to watch history page when password is enabled" -msgstr "啟用密碼後允許匿名訪問觀看歷史記錄頁面" +msgstr "啟用密碼時允許匿名存取監測歷史頁面" #: changedetectionio/forms.py:1024 msgid "Hide muted watches from RSS feed" -msgstr "從 RSS 源中隱藏靜音的手錶" +msgstr "從 RSS Feed 中隱藏已靜音的監測任務" #: changedetectionio/forms.py:1027 msgid "Enable RSS reader mode " -msgstr "啟用 RSS 閱讀器模式" +msgstr "啟用 RSS 閱讀器模式 " #: changedetectionio/forms.py:1028 msgid "Number of changes to show in watch RSS feed" -msgstr "觀看 RSS 源中顯示的更改數量" +msgstr "在 RSS Feed 中顯示的變更數量" #: changedetectionio/forms.py:1030 changedetectionio/forms.py:1035 msgid "Should contain zero or more attempts" -msgstr "應包含零次或多次嘗試" +msgstr "應包含 0 次或更多嘗試" #: changedetectionio/forms.py:1032 msgid "Number of times the filter can be missing before sending a notification" -msgstr "發送通知之前過濾器可能丟失的次數" +msgstr "發送通知前允許過濾器遺失的次數" #: changedetectionio/forms.py:1055 msgid "RegEx to extract" -msgstr "要提取的正則表達式" +msgstr "要提取的 RegEx" #: changedetectionio/forms.py:1056 -#, fuzzy msgid "Extract as CSV" -msgstr "提取數據" +msgstr "提取為 CSV" #: changedetectionio/store.py:386 #, python-brace-format msgid "Error fetching metadata for {}" -msgstr "" +msgstr "讀取 {} 的中繼資料時發生錯誤" #: changedetectionio/store.py:390 msgid "Watch protocol is not permitted or invalid URL format" -msgstr "" +msgstr "監測協定不被允許或 URL 格式無效" #: changedetectionio/blueprint/backups/__init__.py:86 msgid "A backup is already running, check back in a few minutes" -msgstr "" +msgstr "備份正在進行中,請稍後再回來查看" #: changedetectionio/blueprint/backups/__init__.py:90 msgid "Maximum number of backups reached, please remove some" -msgstr "" +msgstr "已達備份數量上限,請移除部分備份" #: changedetectionio/blueprint/backups/__init__.py:98 msgid "Backup building in background, check back in a few minutes." -msgstr "" +msgstr "正在背景建立備份,請稍後再回來查看。" #: changedetectionio/blueprint/backups/__init__.py:161 msgid "Backups were deleted." -msgstr "" +msgstr "備份已刪除。" #: changedetectionio/blueprint/backups/templates/overview.html:6 #: changedetectionio/templates/base.html:282 @@ -624,13 +588,13 @@ msgstr "備份" #: changedetectionio/blueprint/backups/templates/overview.html:9 msgid "A backup is running!" -msgstr "備份正在運行!" +msgstr "備份正在執行中!" #: changedetectionio/blueprint/backups/templates/overview.html:13 msgid "" "Here you can download and request a new backup, when a backup is " "completed you will see it listed below." -msgstr "" +msgstr "您可以在此下載並請求建立新備份,備份完成後將顯示於下方。" #: changedetectionio/blueprint/backups/templates/overview.html:19 msgid "Mb" @@ -638,50 +602,50 @@ msgstr "MB" #: changedetectionio/blueprint/backups/templates/overview.html:24 msgid "No backups found." -msgstr "未找到備份。" +msgstr "找不到備份。" #: changedetectionio/blueprint/backups/templates/overview.html:28 msgid "Create backup" -msgstr "創建備份" +msgstr "建立備份" #: changedetectionio/blueprint/backups/templates/overview.html:30 msgid "Remove backups" -msgstr "刪除備份" +msgstr "移除備份" #: changedetectionio/blueprint/imports/importer.py:45 msgid "" "Importing 5,000 of the first URLs from your list, the rest can be " "imported again." -msgstr "" +msgstr "正在匯入清單中的前 5,000 個 URL,其餘的可以再次匯入。" #: changedetectionio/blueprint/imports/importer.py:78 #, python-brace-format msgid "{} Imported from list in {:.2f}s, {} Skipped." -msgstr "" +msgstr "{} 已從清單匯入,耗時 {:.2f} 秒,跳過 {} 筆。" #: changedetectionio/blueprint/imports/importer.py:98 msgid "Unable to read JSON file, was it broken?" -msgstr "" +msgstr "無法讀取 JSON 檔案,檔案是否已損毀?" #: changedetectionio/blueprint/imports/importer.py:102 msgid "JSON structure looks invalid, was it broken?" -msgstr "" +msgstr "JSON 結構看起來無效,檔案是否已損毀?" #: changedetectionio/blueprint/imports/importer.py:139 #, python-brace-format msgid "{} Imported from Distill.io in {:.2f}s, {} Skipped." -msgstr "" +msgstr "{} 已從 Distill.io 匯入,耗時 {:.2f} 秒,跳過 {} 筆。" #: changedetectionio/blueprint/imports/importer.py:160 #: changedetectionio/blueprint/imports/importer.py:239 msgid "Unable to read export XLSX file, something wrong with the file?" -msgstr "" +msgstr "無法讀取匯出的 XLSX 檔案,檔案是否有問題?" #: changedetectionio/blueprint/imports/importer.py:200 #: changedetectionio/blueprint/imports/importer.py:268 #, python-brace-format msgid "Error processing row number {}, URL value was incorrect, row was skipped." -msgstr "" +msgstr "處理第 {} 行時發生錯誤,URL 數值不正確,已跳過該行。" #: changedetectionio/blueprint/imports/importer.py:214 #: changedetectionio/blueprint/imports/importer.py:297 @@ -689,21 +653,21 @@ msgstr "" msgid "" "Error processing row number {}, check all cell data types are correct, " "row was skipped." -msgstr "" +msgstr "處理第 {} 行時發生錯誤,請檢查所有儲存格資料類型是否正確,已跳過該行。" #: changedetectionio/blueprint/imports/importer.py:218 #, python-brace-format msgid "{} imported from Wachete .xlsx in {:.2f}s" -msgstr "" +msgstr "{} 已從 Wachete .xlsx 匯入,耗時 {:.2f} 秒" #: changedetectionio/blueprint/imports/importer.py:301 #, python-brace-format msgid "{} imported from custom .xlsx in {:.2f}s" -msgstr "" +msgstr "{} 已從自訂 .xlsx 匯入,耗時 {:.2f} 秒" #: changedetectionio/blueprint/imports/templates/import.html:9 msgid "URL List" -msgstr "網址列表" +msgstr "URL 列表" #: changedetectionio/blueprint/imports/templates/import.html:10 msgid "Distill.io" @@ -711,27 +675,27 @@ msgstr "Distill.io" #: changedetectionio/blueprint/imports/templates/import.html:11 msgid ".XLSX & Wachete" -msgstr ".XLSX 和瓦切特" +msgstr ".XLSX 和 Wachete" #: changedetectionio/blueprint/imports/templates/import.html:20 msgid "" "Enter one URL per line, and optionally add tags for each URL after a " "space, delineated by comma (,):" -msgstr "" +msgstr "每行輸入一個 URL,可選用空格分隔後為每個 URL 新增標籤,標籤間用逗號 (,) 分隔:" #: changedetectionio/blueprint/imports/templates/import.html:22 msgid "Example:" -msgstr "例子:" +msgstr "範例:" #: changedetectionio/blueprint/imports/templates/import.html:23 msgid "URLs which do not pass validation will stay in the textarea." -msgstr "未通過驗證的 URL 將保留在文本區域中。" +msgstr "未通過驗證的 URL 將保留在文字區塊中。" #: changedetectionio/blueprint/imports/templates/import.html:44 msgid "" "Copy and Paste your Distill.io watch 'export' file, this should be a JSON" " file." -msgstr "" +msgstr "複製並貼上您的 Distill.io 監測任務「匯出」檔案,這應該是一個 JSON 檔案。" #: changedetectionio/blueprint/imports/templates/import.html:45 msgid "This is" @@ -739,43 +703,43 @@ msgstr "這是" #: changedetectionio/blueprint/imports/templates/import.html:45 msgid "experimental" -msgstr "實驗性的" +msgstr "實驗性功能" #: changedetectionio/blueprint/imports/templates/import.html:45 msgid "supported fields are" -msgstr "支持的字段有" +msgstr "支援的欄位有" #: changedetectionio/blueprint/imports/templates/import.html:45 msgid "the rest (including" -msgstr "其餘的(包括" +msgstr "其餘(包括" #: changedetectionio/blueprint/imports/templates/import.html:45 msgid "are ignored." -msgstr "被忽略。" +msgstr "將被忽略。" #: changedetectionio/blueprint/imports/templates/import.html:48 msgid "How to export?" -msgstr "如何導出?" +msgstr "如何匯出?" #: changedetectionio/blueprint/imports/templates/import.html:49 msgid "Be sure to set your default fetcher to Chrome if required." -msgstr "如果需要,請務必將默認提取器設置為 Chrome。" +msgstr "如果需要,請務必將您的預設抓取器設為 Chrome。" #: changedetectionio/blueprint/imports/templates/import.html:91 msgid "Table of custom column and data types mapping for the" -msgstr "自定義列和數據類型映射表" +msgstr "自訂欄位與資料類型對應表,適用於" #: changedetectionio/blueprint/imports/templates/import.html:91 msgid "Custom mapping" -msgstr "自定義映射" +msgstr "自訂對應" #: changedetectionio/blueprint/imports/templates/import.html:91 msgid "File mapping type." -msgstr "文件映射類型。" +msgstr "檔案對應類型。" #: changedetectionio/blueprint/imports/templates/import.html:95 msgid "Column #" -msgstr "柱子 #" +msgstr "欄位 #" #: changedetectionio/blueprint/imports/templates/import.html:101 msgid "Type" @@ -783,74 +747,73 @@ msgstr "類型" #: changedetectionio/blueprint/imports/templates/import.html:104 msgid "none" -msgstr "沒有任何" +msgstr "無" #: changedetectionio/blueprint/imports/templates/import.html:105 msgid "URL" -msgstr "網址" +msgstr "URL" #: changedetectionio/blueprint/imports/templates/import.html:107 msgid "CSS/xPath filter" -msgstr "CSS/xPath 過濾器" +msgstr "CSS / xPath 過濾器" #: changedetectionio/blueprint/imports/templates/import.html:108 msgid "Group / Tag name(s)" -msgstr "組/標籤名稱" +msgstr "群組 / 標籤名稱" #: changedetectionio/blueprint/imports/templates/import.html:109 msgid "Recheck time (minutes)" -msgstr "複檢時間(分鐘)" +msgstr "複查時間(分鐘)" #: changedetectionio/blueprint/imports/templates/import.html:116 msgid "Import" -msgstr "進口" +msgstr "匯入" #: changedetectionio/blueprint/settings/__init__.py:64 msgid "Password protection removed." -msgstr "" +msgstr "密碼保護已移除。" #: changedetectionio/blueprint/settings/__init__.py:98 #, python-brace-format msgid "Worker count adjusted: {}" -msgstr "" +msgstr "工作程序數量已調整:{}" #: changedetectionio/blueprint/settings/__init__.py:100 msgid "Dynamic worker adjustment not supported for sync workers" -msgstr "" +msgstr "同步工作程序不支援動態調整" #: changedetectionio/blueprint/settings/__init__.py:102 #, python-brace-format msgid "Error adjusting workers: {}" -msgstr "" +msgstr "調整工作程序時發生錯誤:{}" #: changedetectionio/blueprint/settings/__init__.py:107 msgid "Password protection enabled." -msgstr "" +msgstr "已啟用密碼保護。" #: changedetectionio/blueprint/settings/__init__.py:126 -#, fuzzy msgid "Settings updated." -msgstr "設定" +msgstr "設定已更新。" #: changedetectionio/blueprint/settings/__init__.py:129 #: changedetectionio/blueprint/ui/edit.py:283 #: changedetectionio/processors/extract.py:105 msgid "An error occurred, please see below." -msgstr "" +msgstr "發生錯誤,請參見下方。" #: changedetectionio/blueprint/settings/__init__.py:179 msgid "API Key was regenerated." -msgstr "" +msgstr "API 金鑰已重新產生。" #: changedetectionio/blueprint/settings/templates/notification-log.html:7 msgid "Notification debug log" -msgstr "通知調試日誌" +msgstr "通知除錯記錄" #: changedetectionio/blueprint/settings/templates/settings.html:21 #: changedetectionio/blueprint/tags/templates/edit-tag.html:27 #: changedetectionio/blueprint/ui/templates/edit.html:47 msgid "General" -msgstr "一般的" +msgstr "一般" #: changedetectionio/blueprint/settings/templates/settings.html:23 msgid "Fetching" @@ -858,15 +821,15 @@ msgstr "抓取" #: changedetectionio/blueprint/settings/templates/settings.html:24 msgid "Global Filters" -msgstr "全局過濾器" +msgstr "全域過濾器" #: changedetectionio/blueprint/settings/templates/settings.html:25 msgid "UI Options" -msgstr "用戶界面選項" +msgstr "介面選項" #: changedetectionio/blueprint/settings/templates/settings.html:26 msgid "API" -msgstr "應用程序編程接口" +msgstr "API" #: changedetectionio/blueprint/settings/templates/settings.html:27 msgid "RSS" @@ -874,11 +837,11 @@ msgstr "RSS" #: changedetectionio/blueprint/settings/templates/settings.html:28 msgid "Time & Date" -msgstr "時間和日期" +msgstr "時間與日期" #: changedetectionio/blueprint/settings/templates/settings.html:29 msgid "CAPTCHA & Proxies" -msgstr "驗證碼和代理" +msgstr "驗證碼與代理伺服器" #: changedetectionio/blueprint/settings/templates/settings.html:35 msgid "Info" @@ -886,7 +849,7 @@ msgstr "資訊" #: changedetectionio/blueprint/settings/templates/settings.html:46 msgid "Default recheck time for all watches, current system minimum is" -msgstr "所有手錶默認複檢時間,當前系統最小值為" +msgstr "所有監測任務的預設複查時間,目前系統最小值為" #: changedetectionio/blueprint/settings/templates/settings.html:46 msgid "seconds" @@ -894,23 +857,23 @@ msgstr "秒" #: changedetectionio/blueprint/settings/templates/settings.html:46 msgid "more info" -msgstr "更多信息" +msgstr "更多資訊" #: changedetectionio/blueprint/settings/templates/settings.html:390 msgid "Python version:" -msgstr "Python版本:" +msgstr "Python 版本:" #: changedetectionio/blueprint/settings/templates/settings.html:391 msgid "Plugins active:" -msgstr "插件活躍:" +msgstr "啟用的外掛:" #: changedetectionio/blueprint/settings/templates/settings.html:399 msgid "No plugins active" -msgstr "沒有激活的插件" +msgstr "無啟用的外掛" #: changedetectionio/blueprint/settings/templates/settings.html:405 msgid "Back" -msgstr "後退" +msgstr "返回" #: changedetectionio/blueprint/settings/templates/settings.html:406 msgid "Clear Snapshot History" @@ -919,129 +882,127 @@ msgstr "清除快照歷史記錄" #: changedetectionio/blueprint/tags/__init__.py:46 #, python-brace-format msgid "The tag \"{}\" already exists" -msgstr "" +msgstr "標籤「{}」已存在" #: changedetectionio/blueprint/tags/__init__.py:50 -#, fuzzy msgid "Tag added" -msgstr "額外" +msgstr "標籤已新增" #: changedetectionio/blueprint/tags/__init__.py:75 #, python-brace-format msgid "Tag deleted and removed from {} watches" -msgstr "" +msgstr "標籤已刪除,並從 {} 個監測任務中移除" #: changedetectionio/blueprint/tags/__init__.py:87 #, python-brace-format msgid "Tag unlinked removed from {} watches" -msgstr "" +msgstr "標籤已取消連結,並從 {} 個監測任務中移除" #: changedetectionio/blueprint/tags/__init__.py:97 msgid "All tags deleted" -msgstr "" +msgstr "所有標籤已刪除" #: changedetectionio/blueprint/tags/__init__.py:109 msgid "Tag not found" -msgstr "" +msgstr "找不到標籤" #: changedetectionio/blueprint/tags/__init__.py:184 -#, fuzzy msgid "Updated" -msgstr "沉默的" +msgstr "已更新" #: changedetectionio/blueprint/tags/templates/edit-tag.html:28 #: changedetectionio/blueprint/ui/templates/edit.html:56 #: changedetectionio/blueprint/ui/templates/edit.html:386 msgid "Filters & Triggers" -msgstr "過濾器和触發器" +msgstr "過濾器與觸發器" #: changedetectionio/blueprint/tags/templates/edit-tag.html:50 msgid "These settings are" -msgstr "這些設置是" +msgstr "這些設定會" #: changedetectionio/blueprint/tags/templates/edit-tag.html:50 msgid "added" -msgstr "額外" +msgstr "新增" #: changedetectionio/blueprint/tags/templates/edit-tag.html:50 msgid "to any existing watch configurations." -msgstr "任何現有的手錶配置。" +msgstr "至任何現有的監測設定中。" #: changedetectionio/blueprint/tags/templates/edit-tag.html:53 #: changedetectionio/blueprint/ui/templates/edit.html:321 msgid "Text filtering" -msgstr "文本過濾" +msgstr "文字過濾" #: changedetectionio/blueprint/tags/templates/edit-tag.html:73 #: changedetectionio/blueprint/ui/templates/edit.html:269 msgid "Use with caution!" -msgstr "謹慎使用!" +msgstr "請謹慎使用!" #: changedetectionio/blueprint/tags/templates/edit-tag.html:73 #: changedetectionio/blueprint/ui/templates/edit.html:269 msgid "This will easily fill up your email storage quota or flood other storages." -msgstr "這將很容易填滿您的電子郵件存儲配額或淹沒其他存儲。" +msgstr "這很容易填滿您的電子郵件儲存配額或淹沒其他儲存空間。" #: changedetectionio/blueprint/tags/templates/edit-tag.html:80 #: changedetectionio/blueprint/ui/templates/edit.html:276 msgid "Look out!" -msgstr "當心!" +msgstr "注意!" #: changedetectionio/blueprint/tags/templates/edit-tag.html:80 #: changedetectionio/blueprint/ui/templates/edit.html:276 msgid "Lookout!" -msgstr "瞭望!" +msgstr "注意!" #: changedetectionio/blueprint/tags/templates/edit-tag.html:81 #: changedetectionio/blueprint/ui/templates/edit.html:277 msgid "There are" -msgstr "有" +msgstr "目前有" #: changedetectionio/blueprint/tags/templates/edit-tag.html:81 #: changedetectionio/blueprint/ui/templates/edit.html:277 msgid "system-wide notification URLs enabled" -msgstr "啟用系統範圍的通知 URL" +msgstr "已啟用的全系統通知 URL" #: changedetectionio/blueprint/tags/templates/edit-tag.html:81 #: changedetectionio/blueprint/ui/templates/edit.html:277 msgid "this form will override notification settings for this watch only" -msgstr "此表單將僅覆蓋此手錶的通知設置" +msgstr "此表單將僅覆寫此監測任務的通知設定" #: changedetectionio/blueprint/tags/templates/edit-tag.html:81 #: changedetectionio/blueprint/ui/templates/edit.html:277 msgid "an empty Notification URL list here will still send notifications." -msgstr "此處的通知 URL 列表為空仍會發送通知。" +msgstr "此處留空的通知 URL 列表仍會發送通知。" #: changedetectionio/blueprint/tags/templates/edit-tag.html:84 #: changedetectionio/blueprint/ui/templates/edit.html:280 msgid "Use system defaults" -msgstr "使用系統默認值" +msgstr "使用系統預設值" #: changedetectionio/blueprint/tags/templates/groups-overview.html:11 msgid "Add a new organisational tag" -msgstr "添加新的組織標籤" +msgstr "新增組織標籤" #: changedetectionio/blueprint/tags/templates/groups-overview.html:14 msgid "Watch group / tag" -msgstr "觀看組/標籤" +msgstr "監測群組 / 標籤" #: changedetectionio/blueprint/tags/templates/groups-overview.html:21 msgid "" "Groups allows you to manage filters and notifications for multiple " "watches under a single organisational tag." -msgstr "" +msgstr "群組功能讓您能在單一組織標籤下,管理多個監測任務的過濾器與通知設定。" #: changedetectionio/blueprint/tags/templates/groups-overview.html:31 msgid "# Watches" -msgstr "# 監控項" +msgstr "# 監測任務" #: changedetectionio/blueprint/tags/templates/groups-overview.html:32 msgid "Tag / Label name" -msgstr "標籤/標籤名稱" +msgstr "標籤 / 名稱" #: changedetectionio/blueprint/tags/templates/groups-overview.html:42 msgid "No website organisational tags/groups configured" -msgstr "未配置網站組織標籤/組" +msgstr "未設定網站組織標籤 / 群組" #: changedetectionio/blueprint/tags/templates/groups-overview.html:53 #: changedetectionio/blueprint/watchlist/templates/watch-overview.html:249 @@ -1057,7 +1018,7 @@ msgstr "刪除群組?" msgid "" "<p>Are you sure you want to delete group " "<strong>%(title)s</strong>?</p><p>This action cannot be undone.</p>" -msgstr "" +msgstr "<p>您確定要刪除群組 <strong>%(title)s</strong> 嗎?</p><p>此動作無法復原。</p>" #: changedetectionio/blueprint/tags/templates/groups-overview.html:60 #: changedetectionio/blueprint/tags/templates/groups-overview.html:61 @@ -1072,7 +1033,7 @@ msgstr "刪除並移除標籤" #: changedetectionio/blueprint/tags/templates/groups-overview.html:66 msgid "Unlink Group?" -msgstr "取消群組鏈接?" +msgstr "解除群組連結?" #: changedetectionio/blueprint/tags/templates/groups-overview.html:67 #, python-format @@ -1080,130 +1041,126 @@ msgid "" "<p>Are you sure you want to unlink all watches from group " "<strong>%(title)s</strong>?</p><p>The tag will be kept but watches will " "be removed from it.</p>" -msgstr "" +msgstr "<p>您確定要將所有監測任務從群組 <strong>%(title)s</strong> 解除連結嗎?</p><p>標籤將被保留,但監測任務將從中移除。</p>" #: changedetectionio/blueprint/tags/templates/groups-overview.html:68 #: changedetectionio/blueprint/tags/templates/groups-overview.html:69 msgid "Unlink" -msgstr "取消鏈接" +msgstr "解除連結" #: changedetectionio/blueprint/tags/templates/groups-overview.html:69 msgid "Keep the tag but unlink any watches" -msgstr "保留標籤但取消所有手錶的鏈接" +msgstr "保留標籤但解除任何監測任務的連結" #: changedetectionio/blueprint/tags/templates/groups-overview.html:70 #: changedetectionio/blueprint/ui/templates/edit.html:500 msgid "RSS Feed for this watch" -msgstr "此手錶的 RSS 源" +msgstr "此監測任務的 RSS Feed" #: changedetectionio/blueprint/ui/__init__.py:20 #, python-brace-format msgid "{} watches deleted" -msgstr "" +msgstr "{} 個監測任務已刪除" #: changedetectionio/blueprint/ui/__init__.py:27 -#, fuzzy, python-brace-format +#, python-brace-format msgid "{} watches paused" -msgstr "# 手錶" +msgstr "{} 個監測任務已暫停" #: changedetectionio/blueprint/ui/__init__.py:34 #, python-brace-format msgid "{} watches unpaused" -msgstr "" +msgstr "{} 個監測任務已取消暫停" #: changedetectionio/blueprint/ui/__init__.py:41 #, python-brace-format msgid "{} watches updated" -msgstr "" +msgstr "{} 個監測任務已更新" #: changedetectionio/blueprint/ui/__init__.py:48 -#, fuzzy, python-brace-format +#, python-brace-format msgid "{} watches muted" -msgstr "# 手錶" +msgstr "{} 個監測任務已靜音" #: changedetectionio/blueprint/ui/__init__.py:55 #, python-brace-format msgid "{} watches un-muted" -msgstr "" +msgstr "{} 個監測任務已取消靜音" #: changedetectionio/blueprint/ui/__init__.py:63 #, python-brace-format msgid "{} watches queued for rechecking" -msgstr "" +msgstr "{} 個監測任務已排入複查佇列" #: changedetectionio/blueprint/ui/__init__.py:70 #, python-brace-format msgid "{} watches errors cleared" -msgstr "" +msgstr "{} 個監測任務錯誤已清除" #: changedetectionio/blueprint/ui/__init__.py:77 #, python-brace-format msgid "{} watches cleared/reset." -msgstr "" +msgstr "{} 個監測任務已清除 / 重置。" #: changedetectionio/blueprint/ui/__init__.py:90 -#, fuzzy, python-brace-format +#, python-brace-format msgid "{} watches set to use default notification settings" -msgstr "使用默認通知" +msgstr "{} 個監測任務已設為使用預設通知設定" #: changedetectionio/blueprint/ui/__init__.py:105 #, python-brace-format msgid "{} watches were tagged" -msgstr "" +msgstr "{} 個監測任務已加上標籤" #: changedetectionio/blueprint/ui/__init__.py:142 -#, fuzzy msgid "Watch not found" -msgstr "關注這個網址!" +msgstr "找不到監測任務" #: changedetectionio/blueprint/ui/__init__.py:144 -#, fuzzy, python-brace-format +#, python-brace-format msgid "Cleared snapshot history for watch {}" -msgstr "清除快照歷史記錄" +msgstr "已清除監測任務 {} 的快照歷史記錄" #: changedetectionio/blueprint/ui/__init__.py:156 -#, fuzzy msgid "Cleared snapshot history for all watches" -msgstr "清除快照歷史記錄" +msgstr "已清除所有監測任務的快照歷史記錄" #: changedetectionio/blueprint/ui/__init__.py:158 -#, fuzzy msgid "Incorrect confirmation text." -msgstr "確認文字" +msgstr "確認文字不正確。" #: changedetectionio/blueprint/ui/__init__.py:192 #, python-brace-format msgid "The watch by UUID {} does not exist." -msgstr "" +msgstr "UUID 為 {} 的監測任務不存在。" #: changedetectionio/blueprint/ui/__init__.py:199 -#, fuzzy msgid "Deleted." -msgstr "刪除" +msgstr "已刪除。" #: changedetectionio/blueprint/ui/__init__.py:216 msgid "Cloned, you are editing the new watch." -msgstr "" +msgstr "已複製,您正在編輯新的監測任務。" #: changedetectionio/blueprint/ui/__init__.py:255 msgid "Queued 1 watch for rechecking." -msgstr "" +msgstr "已將 1 個監測任務排入複查佇列。" #: changedetectionio/blueprint/ui/__init__.py:257 #, python-brace-format msgid "Queued {} watches for rechecking." -msgstr "" +msgstr "已將 {} 個監測任務排入複查佇列。" #: changedetectionio/blueprint/ui/__init__.py:259 msgid "No watches available to recheck." -msgstr "" +msgstr "沒有可複查的監測任務。" #: changedetectionio/blueprint/ui/__init__.py:330 #, python-brace-format msgid "" "Could not share, something went wrong while communicating with the share " "server - {}" -msgstr "" +msgstr "無法分享,與分享伺服器通訊時發生錯誤 - {}" #: changedetectionio/blueprint/ui/diff.py:93 #: changedetectionio/blueprint/ui/diff.py:154 @@ -1212,68 +1169,67 @@ msgstr "" #: changedetectionio/blueprint/ui/preview.py:36 #: changedetectionio/blueprint/ui/preview.py:160 msgid "No history found for the specified link, bad link?" -msgstr "" +msgstr "找不到指定連結的歷史記錄,連結無效?" #: changedetectionio/blueprint/ui/diff.py:98 msgid "" "Not enough history (2 snapshots required) to show difference page for " "this watch." -msgstr "" +msgstr "歷史記錄不足(需要 2 個快照)以顯示此監測任務的差異頁面。" #: changedetectionio/blueprint/ui/edit.py:35 msgid "No watches to edit" -msgstr "" +msgstr "沒有可編輯的監測任務" #: changedetectionio/blueprint/ui/edit.py:42 #, python-brace-format msgid "No watch with the UUID {} found." -msgstr "" +msgstr "找不到 UUID 為 {} 的監測任務。" #: changedetectionio/blueprint/ui/edit.py:50 #, python-brace-format msgid "Switched to mode - {}." -msgstr "" +msgstr "已切換至模式 - {}。" #: changedetectionio/blueprint/ui/edit.py:69 #, python-brace-format msgid "Cannot load the edit form for processor/plugin '{}', plugin missing?" -msgstr "" +msgstr "無法載入處理器 / 外掛 '{}' 的編輯表單,外掛是否遺失?" #: changedetectionio/blueprint/ui/edit.py:239 msgid "Updated watch - unpaused!" -msgstr "" +msgstr "已更新監測任務 - 已取消暫停!" #: changedetectionio/blueprint/ui/edit.py:239 -#, fuzzy msgid "Updated watch." -msgstr "刪除手錶?" +msgstr "已更新監測任務。" #: changedetectionio/blueprint/ui/preview.py:78 msgid "Preview unavailable - No fetch/check completed or triggers not reached" -msgstr "" +msgstr "預覽無法使用 - 未完成抓取 / 檢查或未觸發" #: changedetectionio/blueprint/ui/views.py:24 #, python-brace-format msgid "Warning, URL {} already exists" -msgstr "" +msgstr "警告,URL {} 已存在" #: changedetectionio/blueprint/ui/views.py:32 msgid "Watch added in Paused state, saving will unpause." -msgstr "" +msgstr "監測任務已在暫停狀態下新增,儲存後將取消暫停。" #: changedetectionio/blueprint/ui/views.py:37 msgid "Watch added." -msgstr "" +msgstr "監測任務已新增。" #: changedetectionio/blueprint/ui/templates/clear_all_history.html:12 msgid "" "This will remove version history (snapshots) for ALL watches, but keep " "your list of URLs!" -msgstr "" +msgstr "這將移除「所有」監測任務的版本歷史記錄(快照),但保留您的 URL 列表!" #: changedetectionio/blueprint/ui/templates/clear_all_history.html:13 msgid "You may like to use the" -msgstr "您可能喜歡使用" +msgstr "您可能想先使用" #: changedetectionio/blueprint/ui/templates/clear_all_history.html:13 msgid "BACKUP" @@ -1281,7 +1237,7 @@ msgstr "備份" #: changedetectionio/blueprint/ui/templates/clear_all_history.html:13 msgid "link first." -msgstr "先鏈接。" +msgstr "連結。" #: changedetectionio/blueprint/ui/templates/clear_all_history.html:17 msgid "Confirmation text" @@ -1289,19 +1245,19 @@ msgstr "確認文字" #: changedetectionio/blueprint/ui/templates/clear_all_history.html:27 msgid "Type in the word" -msgstr "輸入單詞" +msgstr "輸入單字" #: changedetectionio/blueprint/ui/templates/clear_all_history.html:27 msgid "clear" -msgstr "清除" +msgstr "clear" #: changedetectionio/blueprint/ui/templates/clear_all_history.html:27 msgid "to confirm that you understand." -msgstr "以確認您已理解。" +msgstr "以確認您已了解。" #: changedetectionio/blueprint/ui/templates/clear_all_history.html:33 msgid "Clear History!" -msgstr "清除歷史!" +msgstr "清除歷史記錄!" #: changedetectionio/blueprint/ui/templates/clear_all_history.html:39 #: changedetectionio/templates/base.html:379 @@ -1311,7 +1267,7 @@ msgstr "取消" #: changedetectionio/blueprint/ui/templates/diff-offscreen-options.html:3 msgid "Share diff as image" -msgstr "將差異共享為圖像" +msgstr "將差異分享為圖片" #: changedetectionio/blueprint/ui/templates/diff-offscreen-options.html:3 msgid "Share as Image" @@ -1319,11 +1275,11 @@ msgstr "分享為圖片" #: changedetectionio/blueprint/ui/templates/diff-offscreen-options.html:6 msgid "Ignore any lines matching" -msgstr "忽略任何匹配的行" +msgstr "忽略任何符合的行" #: changedetectionio/blueprint/ui/templates/diff-offscreen-options.html:9 msgid "Ignore any lines matching excluding digits" -msgstr "忽略任何匹配排除數字的行" +msgstr "忽略任何符合(排除數字)的行" #: changedetectionio/blueprint/ui/templates/diff.html:28 msgid "From" @@ -1339,29 +1295,29 @@ msgstr "字" #: changedetectionio/blueprint/ui/templates/diff.html:57 msgid "Lines" -msgstr "線路" +msgstr "行" #: changedetectionio/blueprint/ui/templates/diff.html:61 msgid "Ignore Whitespace" -msgstr "忽略空格" +msgstr "忽略空白" #: changedetectionio/blueprint/ui/templates/diff.html:65 msgid "Same/non-changed" -msgstr "相同/未改變" +msgstr "相同 / 未變更" #: changedetectionio/blueprint/ui/templates/diff.html:69 msgid "Removed" -msgstr "已刪除" +msgstr "已移除" #: changedetectionio/blueprint/ui/templates/diff.html:73 #: changedetectionio/blueprint/ui/templates/edit.html:327 msgid "Added" -msgstr "額外" +msgstr "已新增" #: changedetectionio/blueprint/ui/templates/diff.html:77 #: changedetectionio/blueprint/ui/templates/edit.html:327 msgid "Replaced" -msgstr "已更換" +msgstr "已替換" #: changedetectionio/blueprint/ui/templates/diff.html:82 #: changedetectionio/blueprint/ui/templates/preview.html:36 @@ -1371,7 +1327,7 @@ msgstr "鍵盤:" #: changedetectionio/blueprint/ui/templates/diff.html:83 #: changedetectionio/blueprint/ui/templates/preview.html:37 msgid "Previous" -msgstr "以前的" +msgstr "上一個" #: changedetectionio/blueprint/ui/templates/diff.html:84 #: changedetectionio/blueprint/ui/templates/preview.html:38 @@ -1380,16 +1336,16 @@ msgstr "下一個" #: changedetectionio/blueprint/ui/templates/diff.html:91 msgid "Jump to next difference" -msgstr "跳轉到下一個差異" +msgstr "跳至下一個差異" #: changedetectionio/blueprint/ui/templates/diff.html:91 msgid "Jump" -msgstr "跳" +msgstr "跳轉" #: changedetectionio/blueprint/ui/templates/diff.html:97 #: changedetectionio/blueprint/ui/templates/preview.html:45 msgid "Error Text" -msgstr "錯誤文本" +msgstr "錯誤文字" #: changedetectionio/blueprint/ui/templates/diff.html:98 #: changedetectionio/blueprint/ui/templates/preview.html:47 @@ -1404,25 +1360,25 @@ msgstr "文字" #: changedetectionio/blueprint/ui/templates/diff.html:100 #: changedetectionio/blueprint/ui/templates/preview.html:51 msgid "Current screenshot" -msgstr "當前截圖" +msgstr "目前截圖" #: changedetectionio/blueprint/ui/templates/diff.html:101 msgid "Extract Data" -msgstr "提取數據" +msgstr "提取資料" #: changedetectionio/blueprint/ui/templates/diff.html:107 msgid "seconds ago." -msgstr "幾秒鐘前。" +msgstr "秒前。" #: changedetectionio/blueprint/ui/templates/diff.html:114 #: changedetectionio/blueprint/ui/templates/preview.html:59 #: changedetectionio/blueprint/ui/templates/preview.html:66 msgid "seconds ago" -msgstr "幾秒鐘前" +msgstr "秒前" #: changedetectionio/blueprint/ui/templates/diff.html:115 msgid "Current error-ing screenshot from most recent request" -msgstr "最近請求的當前錯誤屏幕截圖" +msgstr "最近請求的目前錯誤截圖" #: changedetectionio/blueprint/ui/templates/diff.html:127 msgid "Pro-tip: You can enable" @@ -1430,15 +1386,15 @@ msgstr "專業提示:您可以啟用" #: changedetectionio/blueprint/ui/templates/diff.html:127 msgid "\"share access when password is enabled\"" -msgstr "" +msgstr "「啟用密碼時分享存取權限」" #: changedetectionio/blueprint/ui/templates/diff.html:127 msgid "from settings." -msgstr "從設置。" +msgstr "於設定中。" #: changedetectionio/blueprint/ui/templates/diff.html:133 msgid "Goto single snapshot" -msgstr "轉到單個快照" +msgstr "前往單一快照" #: changedetectionio/blueprint/ui/templates/diff.html:138 #: changedetectionio/blueprint/ui/templates/edit.html:125 @@ -1447,32 +1403,32 @@ msgstr "提示:" #: changedetectionio/blueprint/ui/templates/diff.html:138 msgid "Highlight text to share or add to ignore lists." -msgstr "突出顯示要共享或添加到忽略列表的文本。" +msgstr "反白文字以分享或新增至忽略列表。" #: changedetectionio/blueprint/ui/templates/diff.html:144 #: changedetectionio/blueprint/ui/templates/preview.html:80 msgid "" "For now, Differences are performed on text, not graphically, only the " "latest screenshot is available." -msgstr "" +msgstr "目前,差異比對是針對文字執行,而非圖形,僅提供最新的截圖。" #: changedetectionio/blueprint/ui/templates/diff.html:149 #: changedetectionio/blueprint/ui/templates/preview.html:86 msgid "Current screenshot from most recent request" -msgstr "最近請求的當前屏幕截圖" +msgstr "最近請求的目前截圖" #: changedetectionio/blueprint/ui/templates/diff.html:151 #: changedetectionio/blueprint/ui/templates/preview.html:88 msgid "No screenshot available just yet! Try rechecking the page." -msgstr "目前還沒有可用的屏幕截圖!嘗試重新檢查頁面。" +msgstr "目前還沒有可用的截圖!請嘗試複查頁面。" #: changedetectionio/blueprint/ui/templates/diff.html:154 msgid "Screenshot requires Playwright/WebDriver enabled" -msgstr "屏幕截圖需要啟用 Playwright/WebDriver" +msgstr "截圖需要啟用 Playwright / WebDriver" #: changedetectionio/blueprint/ui/templates/edit.html:48 msgid "Request" -msgstr "要求" +msgstr "請求" #: changedetectionio/blueprint/ui/templates/edit.html:52 msgid "Browser Steps" @@ -1480,11 +1436,11 @@ msgstr "瀏覽器步驟" #: changedetectionio/blueprint/ui/templates/edit.html:55 msgid "Visual Filter Selector" -msgstr "視覺過濾器選擇器" +msgstr "視覺過濾選擇器" #: changedetectionio/blueprint/ui/templates/edit.html:57 msgid "Conditions" -msgstr "狀況" +msgstr "條件" #: changedetectionio/blueprint/ui/templates/edit.html:60 msgid "Stats" @@ -1493,43 +1449,43 @@ msgstr "統計數據" #: changedetectionio/blueprint/ui/templates/edit.html:73 #: changedetectionio/blueprint/ui/templates/edit.html:313 msgid "Some sites use JavaScript to create the content, for this you should" -msgstr "有些網站使用 JavaScript 來創建內容,為此您應該" +msgstr "有些網站使用 JavaScript 來建立內容,為此您應該" #: changedetectionio/blueprint/ui/templates/edit.html:73 #: changedetectionio/blueprint/ui/templates/edit.html:313 msgid "use the Chrome/WebDriver Fetcher" -msgstr "使用 Chrome/WebDriver Fetcher" +msgstr "使用 Chrome / WebDriver 抓取器" #: changedetectionio/blueprint/ui/templates/edit.html:74 msgid "Variables are supported in the URL" -msgstr "URL 中支持變量" +msgstr "URL 中支援變數" #: changedetectionio/blueprint/ui/templates/edit.html:74 #: changedetectionio/blueprint/ui/templates/edit.html:180 #: changedetectionio/blueprint/ui/templates/edit.html:189 msgid "help and examples here" -msgstr "幫助和示例在這裡" +msgstr "幫助與範例請見此處" #: changedetectionio/blueprint/ui/templates/edit.html:78 msgid "Organisational tag/group name used in the main listing page" -msgstr "主列表頁面中使用的組織標籤/組名稱" +msgstr "主列表頁面中使用的組織標籤 / 群組名稱" #: changedetectionio/blueprint/ui/templates/edit.html:85 msgid "" "Automatically uses the page title if found, you can also use your own " "title/description here" -msgstr "" +msgstr "如果找到頁面標題將自動使用,您也可以在此使用您自己的標題 / 描述" #: changedetectionio/blueprint/ui/templates/edit.html:95 msgid "The interval/amount of time between each check." -msgstr "每次檢查之間的間隔/時間量。" +msgstr "每次檢查之間的間隔 / 時間量。" #: changedetectionio/blueprint/ui/templates/edit.html:110 msgid "" "Sends a notification when the filter can no longer be seen on the page, " "good for knowing when the page changed and your filter will not work " "anymore." -msgstr "" +msgstr "當頁面上找不到過濾器時發送通知,這有助於了解頁面何時變更導致您的過濾器失效。" #: changedetectionio/blueprint/ui/templates/edit.html:123 msgid "Use the" @@ -1537,45 +1493,45 @@ msgstr "使用" #: changedetectionio/blueprint/ui/templates/edit.html:123 msgid "Basic" -msgstr "基本的" +msgstr "基本" #: changedetectionio/blueprint/ui/templates/edit.html:123 msgid "" "method (default) where your watched site doesn't need Javascript to " "render." -msgstr "" +msgstr "方法(預設),適用於您監測的網站不需要 Javascript 渲染的情況。" #: changedetectionio/blueprint/ui/templates/edit.html:124 msgid "The" -msgstr "這" +msgstr "這個" #: changedetectionio/blueprint/ui/templates/edit.html:124 msgid "Chrome/Javascript" -msgstr "Chrome/Javascript" +msgstr "Chrome / Javascript" #: changedetectionio/blueprint/ui/templates/edit.html:124 msgid "" "method requires a network connection to a running WebDriver+Chrome " "server, set by the ENV var 'WEBDRIVER_URL'." -msgstr "" +msgstr "方法需要連線到執行中的 WebDriver + Chrome 伺服器,由環境變數 'WEBDRIVER_URL' 設定。" #: changedetectionio/blueprint/ui/templates/edit.html:125 msgid "Connect using Bright Data and Oxylabs Proxies, find out more here." -msgstr "使用 Bright Data 和 Oxylabs Proxies 進行連接,在此處了解更多信息。" +msgstr "使用 Bright Data 和 Oxylabs 代理連接,在此處了解更多資訊。" #: changedetectionio/blueprint/ui/templates/edit.html:130 msgid "Check/Scan all" -msgstr "檢查/掃描全部" +msgstr "檢查 / 掃描全部" #: changedetectionio/blueprint/ui/templates/edit.html:133 msgid "Choose a proxy for this watch" -msgstr "為該手錶選擇代理" +msgstr "為此監測任務選擇代理伺服器" #: changedetectionio/blueprint/ui/templates/edit.html:143 msgid "" "If you're having trouble waiting for the page to be fully rendered (text " "missing etc), try increasing the 'wait' time here." -msgstr "" +msgstr "如果您在等待頁面完全渲染時遇到問題(文字遺失等),請嘗試在此增加「等待」時間。" #: changedetectionio/blueprint/ui/templates/edit.html:145 msgid "This will wait" @@ -1583,113 +1539,113 @@ msgstr "這會等待" #: changedetectionio/blueprint/ui/templates/edit.html:145 msgid "seconds before extracting the text." -msgstr "提取文本前幾秒。" +msgstr "秒後才提取文字。" #: changedetectionio/blueprint/ui/templates/edit.html:147 msgid "Using the current global default settings" -msgstr "使用當前全局默認設置" +msgstr "使用目前全域預設設定" #: changedetectionio/blueprint/ui/templates/edit.html:152 #: changedetectionio/blueprint/ui/templates/edit.html:165 msgid "Show advanced options" -msgstr "顯示高級選項" +msgstr "顯示進階選項" #: changedetectionio/blueprint/ui/templates/edit.html:157 msgid "" "Run this code before performing change detection, handy for filling in " "fields and other actions" -msgstr "" +msgstr "在執行變更檢測之前執行此程式碼,方便填寫欄位和其他動作" #: changedetectionio/blueprint/ui/templates/edit.html:158 msgid "More help and examples here" -msgstr "更多幫助和示例請參見此處" +msgstr "更多幫助和範例請見此處" #: changedetectionio/blueprint/ui/templates/edit.html:180 msgid "Variables are supported in the request body" -msgstr "請求正文中支持變量" +msgstr "請求內容中支援變數" #: changedetectionio/blueprint/ui/templates/edit.html:189 msgid "Variables are supported in the request header values" -msgstr "請求標頭值支持變量" +msgstr "請求標頭值支援變數" #: changedetectionio/blueprint/ui/templates/edit.html:192 msgid "Alert! Extra headers file found and will be added to this watch!" -msgstr "警報!找到額外的頭文件並將其添加到此手錶中!" +msgstr "警報!找到額外的標頭檔案,將新增至此監測任務!" #: changedetectionio/blueprint/ui/templates/edit.html:194 msgid "Headers can be also read from a file in your data-directory" -msgstr "還可以從數據目錄中的文件中讀取標頭" +msgstr "標頭也可以從您的資料目錄中的檔案讀取" #: changedetectionio/blueprint/ui/templates/edit.html:194 msgid "Read more here" -msgstr "在這裡閱讀更多內容" +msgstr "在此閱讀更多內容" #: changedetectionio/blueprint/ui/templates/edit.html:197 msgid "Not supported by Selenium browser" -msgstr "Selenium 瀏覽器不支持" +msgstr "Selenium 瀏覽器不支援" #: changedetectionio/blueprint/ui/templates/edit.html:221 msgid "Turn on text finder" -msgstr "打開文本查找器" +msgstr "開啟文字尋找器" #: changedetectionio/blueprint/ui/templates/edit.html:224 msgid "Please wait, first browser step can take a little time to load.." -msgstr "請稍候,第一個瀏覽器步驟可能需要一些時間來加載。" +msgstr "請稍候,第一個瀏覽器步驟可能需要一點時間載入.." #: changedetectionio/blueprint/ui/templates/edit.html:231 msgid "Click here to Start" -msgstr "單擊此處開始" +msgstr "點擊此處開始" #: changedetectionio/blueprint/ui/templates/edit.html:233 msgid "Please allow 10-15 seconds for the browser to connect." -msgstr "請等待 10-15 秒讓瀏覽器連接。" +msgstr "請等待 10-15 秒讓瀏覽器連線。" #: changedetectionio/blueprint/ui/templates/edit.html:242 msgid "Press \"Play\" to start." -msgstr "" +msgstr "按 \"Play\" 開始。" #: changedetectionio/blueprint/ui/templates/edit.html:249 #: changedetectionio/blueprint/ui/templates/edit.html:419 msgid "Visual Selector data is not ready, watch needs to be checked atleast once." -msgstr "視覺選擇器數據尚未準備好,至少需要檢查一次手錶。" +msgstr "視覺選擇器資料尚未準備好,監測任務至少需要檢查一次。" #: changedetectionio/blueprint/ui/templates/edit.html:253 msgid "" "Sorry, this functionality only works with fetchers that support " "interactive Javascript (so far only Playwright based fetchers)" -msgstr "" +msgstr "抱歉,此功能僅適用於支援互動式 Javascript 的抓取器(目前僅限基於 Playwright 的抓取器)" #: changedetectionio/blueprint/ui/templates/edit.html:254 #: changedetectionio/blueprint/ui/templates/edit.html:424 msgid "You need to" -msgstr "你需要" +msgstr "您需要" #: changedetectionio/blueprint/ui/templates/edit.html:254 #: changedetectionio/blueprint/ui/templates/edit.html:424 msgid "Set the fetch method" -msgstr "設置獲取方法" +msgstr "設定抓取方式" #: changedetectionio/blueprint/ui/templates/edit.html:254 msgid "to one that supports interactive Javascript." -msgstr "到支持交互式 Javascript 的一個。" +msgstr "為支援互動式 Javascript 的方式。" #: changedetectionio/blueprint/ui/templates/edit.html:297 msgid "" "Use the verify (✓) button to test if a condition passes against the " "current snapshot." -msgstr "" +msgstr "使用驗證 (✓) 按鈕測試條件是否符合目前的快照。" #: changedetectionio/blueprint/ui/templates/edit.html:298 msgid "Read a quick tutorial about" -msgstr "閱讀有關以下內容的快速教程" +msgstr "閱讀有關" #: changedetectionio/blueprint/ui/templates/edit.html:298 msgid "using conditional web page changes here" -msgstr "此處使用條件網頁更改" +msgstr "使用條件式網頁變更的快速教學" #: changedetectionio/blueprint/ui/templates/edit.html:303 msgid "Activate preview" -msgstr "激活預覽" +msgstr "啟用預覽" #: changedetectionio/blueprint/ui/templates/edit.html:307 msgid "Pro-tips:" @@ -1697,30 +1653,30 @@ msgstr "專業提示:" #: changedetectionio/blueprint/ui/templates/edit.html:310 msgid "Use the preview page to see your filters and triggers highlighted." -msgstr "使用預覽頁面查看突出顯示的過濾器和触發器。" +msgstr "使用預覽頁面查看反白的過濾器和觸發器。" #: changedetectionio/blueprint/ui/templates/edit.html:322 msgid "Limit trigger/ignore/block/extract to;" -msgstr "將觸發/忽略/阻止/提取限制為;" +msgstr "將觸發 / 忽略 / 阻擋 / 提取限制為;" #: changedetectionio/blueprint/ui/templates/edit.html:326 msgid "" "Note: Depending on the length and similarity of the text on each line, " "the algorithm may consider an" -msgstr "" +msgstr "注意:根據每行文字的長度和相似度,演算法可能會將" #: changedetectionio/blueprint/ui/templates/edit.html:326 #: changedetectionio/blueprint/ui/templates/edit.html:328 msgid "addition" -msgstr "添加" +msgstr "新增" #: changedetectionio/blueprint/ui/templates/edit.html:326 msgid "instead of" -msgstr "而不是" +msgstr "誤判為" #: changedetectionio/blueprint/ui/templates/edit.html:326 msgid "replacement" -msgstr "替代品" +msgstr "替換" #: changedetectionio/blueprint/ui/templates/edit.html:326 msgid "for example." @@ -1728,7 +1684,7 @@ msgstr "例如。" #: changedetectionio/blueprint/ui/templates/edit.html:327 msgid "So it's always better to select" -msgstr "所以選擇總是更好" +msgstr "所以最好選擇" #: changedetectionio/blueprint/ui/templates/edit.html:327 msgid "when you're interested in new content." @@ -1744,42 +1700,42 @@ msgstr "考慮啟用" #: changedetectionio/blueprint/ui/templates/edit.html:328 msgid "Only trigger when unique lines appear" -msgstr "僅當出現唯一線條時觸發" +msgstr "僅當出現獨特行時觸發" #: changedetectionio/blueprint/ui/templates/edit.html:332 msgid "" "Good for websites that just move the content around, and you want to know" " when NEW content is added, compares new lines against all history for " "this watch." -msgstr "" +msgstr "適用於內容僅會移動的網站,且您想知道何時新增了「新」內容,此功能會將新行與此監測任務的所有歷史記錄進行比較。" #: changedetectionio/blueprint/ui/templates/edit.html:340 msgid "" "Helps reduce changes detected caused by sites shuffling lines around, " "combine with" -msgstr "" +msgstr "有助於減少因網站重新排列行而檢測到的變更,結合" #: changedetectionio/blueprint/ui/templates/edit.html:340 msgid "check unique lines" -msgstr "檢查獨特的線路" +msgstr "檢查獨特行" #: changedetectionio/blueprint/ui/templates/edit.html:340 msgid "below." -msgstr "以下。" +msgstr "於下方。" #: changedetectionio/blueprint/ui/templates/edit.html:344 msgid "Remove any whitespace before and after each line of text" -msgstr "刪除每行文本前後的所有空格" +msgstr "移除每行文字前後的所有空白" #: changedetectionio/blueprint/ui/templates/edit.html:358 #: changedetectionio/blueprint/ui/templates/edit.html:361 #: changedetectionio/blueprint/ui/templates/edit.html:417 msgid "Loading..." -msgstr "載入中..." +msgstr "載入中 ..." #: changedetectionio/blueprint/ui/templates/edit.html:386 msgid "The Visual Selector tool lets you select the" -msgstr "視覺選擇器工具可讓您選擇" +msgstr "視覺選擇器工具讓您可以選擇" #: changedetectionio/blueprint/ui/templates/edit.html:386 msgid "text" @@ -1789,15 +1745,15 @@ msgstr "文字" msgid "" "elements that will be used for the change detection. It automatically " "fills-in the filters in the \"CSS/JSONPath/JQ/XPath Filters\" box of the" -msgstr "" +msgstr "將用於變更檢測的元素。它會自動填入" #: changedetectionio/blueprint/ui/templates/edit.html:386 msgid "tab. Use" -msgstr "選項卡。使用" +msgstr "分頁的「CSS / JSONPath / JQ / XPath 過濾器」欄位。使用" #: changedetectionio/blueprint/ui/templates/edit.html:386 msgid "Shift+Click" -msgstr "Shift+單擊" +msgstr "Shift + 點擊" #: changedetectionio/blueprint/ui/templates/edit.html:386 msgid "to select multiple items." @@ -1805,7 +1761,7 @@ msgstr "選擇多個項目。" #: changedetectionio/blueprint/ui/templates/edit.html:391 msgid "Selection Mode:" -msgstr "選擇方式:" +msgstr "選擇模式:" #: changedetectionio/blueprint/ui/templates/edit.html:394 msgid "Select by element" @@ -1813,7 +1769,7 @@ msgstr "按元素選擇" #: changedetectionio/blueprint/ui/templates/edit.html:398 msgid "Draw area" -msgstr "繪圖區" +msgstr "繪製區域" #: changedetectionio/blueprint/ui/templates/edit.html:406 msgid "Clear selection" @@ -1821,29 +1777,29 @@ msgstr "清除選擇" #: changedetectionio/blueprint/ui/templates/edit.html:408 msgid "One moment, fetching screenshot and element information.." -msgstr "一會兒,正在獲取屏幕截圖和元素信息.." +msgstr "請稍候,正在抓取截圖和元素資訊.." #: changedetectionio/blueprint/ui/templates/edit.html:417 msgid "Currently:" -msgstr "現在:" +msgstr "目前:" #: changedetectionio/blueprint/ui/templates/edit.html:423 msgid "" "Sorry, this functionality only works with fetchers that support " "Javascript and screenshots (such as playwright etc)." -msgstr "" +msgstr "抱歉,此功能僅適用於支援 Javascript 和截圖的抓取器(如 playwright 等)。" #: changedetectionio/blueprint/ui/templates/edit.html:424 msgid "to one that supports Javascript and screenshots." -msgstr "到支持 Javascript 和屏幕截圖的一個。" +msgstr "為支援 Javascript 和截圖的方式。" #: changedetectionio/blueprint/ui/templates/edit.html:441 msgid "Check count" -msgstr "檢查計數" +msgstr "檢查次數" #: changedetectionio/blueprint/ui/templates/edit.html:445 msgid "Consecutive filter failures" -msgstr "連續過濾器故障" +msgstr "連續過濾失敗" #: changedetectionio/blueprint/ui/templates/edit.html:449 msgid "History length" @@ -1851,31 +1807,31 @@ msgstr "歷史長度" #: changedetectionio/blueprint/ui/templates/edit.html:453 msgid "Last fetch duration" -msgstr "上次獲取持續時間" +msgstr "上次抓取耗時" #: changedetectionio/blueprint/ui/templates/edit.html:457 msgid "Notification alert count" -msgstr "通知警報計數" +msgstr "通知警報次數" #: changedetectionio/blueprint/ui/templates/edit.html:461 msgid "Server type reply" -msgstr "服務器類型回复" +msgstr "伺服器類型回應" #: changedetectionio/blueprint/ui/templates/edit.html:475 msgid "Download latest HTML snapshot" -msgstr "下載最新的 HTML 快照" +msgstr "下載最新 HTML 快照" #: changedetectionio/blueprint/ui/templates/edit.html:488 msgid "Delete Watch?" -msgstr "刪除手錶?" +msgstr "刪除監測任務?" #: changedetectionio/blueprint/ui/templates/edit.html:489 msgid "Are you sure you want to delete the watch for:" -msgstr "您確定要刪除以下對象的手錶嗎:" +msgstr "您確定要刪除以下對象的監測任務:" #: changedetectionio/blueprint/ui/templates/edit.html:489 msgid "This action cannot be undone." -msgstr "此操作無法撤消。" +msgstr "此動作無法復原。" #: changedetectionio/blueprint/ui/templates/edit.html:495 msgid "Clear History?" @@ -1883,13 +1839,13 @@ msgstr "清除歷史記錄?" #: changedetectionio/blueprint/ui/templates/edit.html:496 msgid "Are you sure you want to clear all history for:" -msgstr "您確定要清除以下內容的所有歷史記錄:" +msgstr "您確定要清除以下項目的所有歷史記錄:" #: changedetectionio/blueprint/ui/templates/edit.html:496 msgid "" "This will remove all snapshots and previous versions. This action cannot " "be undone." -msgstr "" +msgstr "這將移除所有快照和先前版本。此動作無法復原。" #: changedetectionio/blueprint/ui/templates/edit.html:497 msgid "Clear History" @@ -1897,49 +1853,49 @@ msgstr "清除歷史記錄" #: changedetectionio/blueprint/ui/templates/edit.html:499 msgid "Clone & Edit" -msgstr "克隆和編輯" +msgstr "複製並編輯" #: changedetectionio/blueprint/ui/templates/preview.html:22 msgid "Select timestamp" -msgstr "選擇時間戳" +msgstr "選擇時間戳記" #: changedetectionio/blueprint/ui/templates/preview.html:31 msgid "Go" -msgstr "去" +msgstr "前往" #: changedetectionio/blueprint/ui/templates/preview.html:69 msgid "Current erroring screenshot from most recent request" -msgstr "最近請求的當前錯誤屏幕截圖" +msgstr "最近請求的目前錯誤截圖" #: changedetectionio/blueprint/ui/templates/preview.html:91 msgid "" "Screenshot requires a Content Fetcher ( Sockpuppetbrowser, selenium, etc " ") that supports screenshots." -msgstr "" +msgstr "截圖需要支援截圖的內容抓取器 (Sockpuppetbrowser, selenium 等)。" #: changedetectionio/blueprint/watchlist/templates/watch-overview.html:31 msgid "Add a new web page change detection watch" -msgstr "添加新的網頁更改檢測監視" +msgstr "新增網頁變更檢測任務" #: changedetectionio/blueprint/watchlist/templates/watch-overview.html:34 msgid "Watch this URL!" -msgstr "監控此URL!" +msgstr "監測此 URL!" #: changedetectionio/blueprint/watchlist/templates/watch-overview.html:35 msgid "Edit first then Watch" -msgstr "編輯後監控" +msgstr "先編輯後監測" #: changedetectionio/blueprint/watchlist/templates/watch-overview.html:45 msgid "Create a shareable link" -msgstr "創建可共享鏈接" +msgstr "建立可分享連結" #: changedetectionio/blueprint/watchlist/templates/watch-overview.html:45 msgid "Tip: You can also add 'shared' watches." -msgstr "提示:您還可以添加“共享”手錶。" +msgstr "提示:您也可以新增「共享」監測任務。" #: changedetectionio/blueprint/watchlist/templates/watch-overview.html:45 msgid "More info" -msgstr "更多信息" +msgstr "更多資訊" #: changedetectionio/blueprint/watchlist/templates/watch-overview.html:53 msgid "Pause" @@ -1951,7 +1907,7 @@ msgstr "取消暫停" #: changedetectionio/blueprint/watchlist/templates/watch-overview.html:55 msgid "Mute" -msgstr "沉默的" +msgstr "靜音" #: changedetectionio/blueprint/watchlist/templates/watch-overview.html:56 msgid "UnMute" @@ -1968,11 +1924,11 @@ msgstr "標籤" #: changedetectionio/blueprint/watchlist/templates/watch-overview.html:59 msgid "Mark viewed" -msgstr "標記已查看" +msgstr "標記為已讀" #: changedetectionio/blueprint/watchlist/templates/watch-overview.html:60 msgid "Use default notification" -msgstr "使用默認通知" +msgstr "使用預設通知" #: changedetectionio/blueprint/watchlist/templates/watch-overview.html:61 msgid "Clear errors" @@ -1980,31 +1936,31 @@ msgstr "清除錯誤" #: changedetectionio/blueprint/watchlist/templates/watch-overview.html:65 msgid "Clear Histories" -msgstr "清晰的歷史記錄" +msgstr "清除歷史記錄" #: changedetectionio/blueprint/watchlist/templates/watch-overview.html:66 msgid "" "<p>Are you sure you want to clear history for the selected " "items?</p><p>This action cannot be undone.</p>" -msgstr "" +msgstr "<p>您確定要清除所選項目的歷史記錄嗎?</p><p>此動作無法復原。</p>" #: changedetectionio/blueprint/watchlist/templates/watch-overview.html:67 msgid "OK" -msgstr "好的" +msgstr "確定" #: changedetectionio/blueprint/watchlist/templates/watch-overview.html:67 msgid "Clear/reset history" -msgstr "清除/重置歷史記錄" +msgstr "清除 / 重置歷史記錄" #: changedetectionio/blueprint/watchlist/templates/watch-overview.html:71 msgid "Delete Watches?" -msgstr "刪除手錶?" +msgstr "刪除監測任務?" #: changedetectionio/blueprint/watchlist/templates/watch-overview.html:72 msgid "" "<p>Are you sure you want to delete the selected " "watches?</strong></p><p>This action cannot be undone.</p>" -msgstr "" +msgstr "<p>您確定要刪除所選的監測任務嗎?</strong></p><p>此動作無法復原。</p>" #: changedetectionio/blueprint/watchlist/templates/watch-overview.html:78 msgid "Searching" @@ -2020,40 +1976,40 @@ msgstr "網站" #: changedetectionio/blueprint/watchlist/templates/watch-overview.html:120 msgid "Restock & Price" -msgstr "補貨及價格" +msgstr "補貨與價格" #: changedetectionio/blueprint/watchlist/templates/watch-overview.html:122 #: changedetectionio/blueprint/watchlist/templates/watch-overview.html:123 msgid "Last" -msgstr "最後的" +msgstr "上次" #: changedetectionio/blueprint/watchlist/templates/watch-overview.html:122 msgid "Checked" -msgstr "已檢查" +msgstr "檢查" #: changedetectionio/blueprint/watchlist/templates/watch-overview.html:123 msgid "Changed" -msgstr "改變了" +msgstr "變更" #: changedetectionio/blueprint/watchlist/templates/watch-overview.html:130 msgid "No website watches configured, please add a URL in the box above, or" -msgstr "未配置網站監視,請在上面的框中添加 URL,或者" +msgstr "未設定網站監測任務,請在上方欄位新增 URL,或" #: changedetectionio/blueprint/watchlist/templates/watch-overview.html:130 msgid "import a list" -msgstr "導入列表" +msgstr "匯入列表" #: changedetectionio/blueprint/watchlist/templates/watch-overview.html:213 msgid "Detecting restock and price" -msgstr "檢測補貨和價格" +msgstr "檢測補貨與價格" #: changedetectionio/blueprint/watchlist/templates/watch-overview.html:215 msgid "In stock" -msgstr "有存貨" +msgstr "有庫存" #: changedetectionio/blueprint/watchlist/templates/watch-overview.html:215 msgid "Not in stock" -msgstr "沒有庫存" +msgstr "無庫存" #: changedetectionio/blueprint/watchlist/templates/watch-overview.html:221 msgid "Price" @@ -2061,20 +2017,20 @@ msgstr "價格" #: changedetectionio/blueprint/watchlist/templates/watch-overview.html:226 msgid "No information" -msgstr "暫無信息" +msgstr "無資訊" #: changedetectionio/blueprint/watchlist/templates/watch-overview.html:234 #: changedetectionio/templates/base.html:353 msgid "Checking now" -msgstr "立即檢查" +msgstr "正在檢查" #: changedetectionio/blueprint/watchlist/templates/watch-overview.html:247 msgid "Queued" -msgstr "排隊" +msgstr "已排程" #: changedetectionio/blueprint/watchlist/templates/watch-overview.html:250 msgid "History" -msgstr "歷史" +msgstr "歷史記錄" #: changedetectionio/blueprint/watchlist/templates/watch-overview.html:251 msgid "Preview" @@ -2086,12 +2042,12 @@ msgstr "有錯誤" #: changedetectionio/blueprint/watchlist/templates/watch-overview.html:263 msgid "Mark all viewed" -msgstr "標記所有已查看" +msgstr "標記所有為已讀" #: changedetectionio/blueprint/watchlist/templates/watch-overview.html:267 #, python-format msgid "Mark all viewed in '%(title)s'" -msgstr "標記所有在“%(title)s”中查看過的內容" +msgstr "標記 '%(title)s' 中的所有項目為已讀" #: changedetectionio/blueprint/watchlist/templates/watch-overview.html:271 msgid "Unread" @@ -2099,93 +2055,91 @@ msgstr "未讀" #: changedetectionio/blueprint/watchlist/templates/watch-overview.html:274 msgid "Recheck all" -msgstr "重新檢查所有" +msgstr "複查全部" #: changedetectionio/blueprint/watchlist/templates/watch-overview.html:274 #, python-format msgid "in '%(title)s'" -msgstr "在“%(title)s”中" +msgstr "於 '%(title)s'" #: changedetectionio/processors/extract.py:131 msgid "No matches found while scanning all of the watch history for that RegEx." -msgstr "" +msgstr "掃描此 RegEx 的所有監測歷史記錄時找不到相符項目。" #: changedetectionio/processors/image_ssim_diff/difference.py:328 msgid "Not enough history to compare. Need at least 2 snapshots." -msgstr "" +msgstr "歷史記錄不足以進行比較。至少需要 2 個快照。" #: changedetectionio/processors/image_ssim_diff/difference.py:363 #, python-brace-format msgid "Failed to load screenshots: {}" -msgstr "" +msgstr "無法載入截圖:{}" #: changedetectionio/processors/image_ssim_diff/difference.py:412 #, python-brace-format msgid "Failed to calculate diff: {}" -msgstr "" +msgstr "無法計算差異:{}" #: changedetectionio/processors/image_ssim_diff/forms.py:19 #: changedetectionio/processors/image_ssim_diff/forms.py:69 msgid "Bounding box value is too long" -msgstr "邊界框值太長" +msgstr "邊界框數值太長" #: changedetectionio/processors/image_ssim_diff/forms.py:23 msgid "Bounding box must be in format: x,y,width,height (integers only)" -msgstr "邊界框的格式必須為:x,y,寬度,高度(僅限整數)" +msgstr "邊界框格式必須為:x,y,width,height(僅限整數)" #: changedetectionio/processors/image_ssim_diff/forms.py:29 msgid "Bounding box values must be non-negative" -msgstr "邊界框值必須是非負數" +msgstr "邊界框數值必須為非負數" #: changedetectionio/processors/image_ssim_diff/forms.py:31 msgid "Bounding box values are too large" -msgstr "邊界框值太大" +msgstr "邊界框數值太大" #: changedetectionio/processors/image_ssim_diff/forms.py:40 msgid "Selection mode must be either \"element\" or \"draw\"" -msgstr "" +msgstr "選擇模式必須是 \"element\" 或 \"draw\"" #: changedetectionio/processors/image_ssim_diff/forms.py:47 msgid "Minimum Change Percentage" -msgstr "最小變化百分比" +msgstr "最小變更百分比" #: changedetectionio/processors/image_ssim_diff/forms.py:56 msgid "Pixel Difference Sensitivity" msgstr "像素差異靈敏度" #: changedetectionio/processors/image_ssim_diff/forms.py:58 -#, fuzzy msgid "Use global default" -msgstr "使用系統默認值" +msgstr "使用全域預設值" #: changedetectionio/processors/image_ssim_diff/forms.py:66 msgid "Bounding Box" msgstr "邊界框" #: changedetectionio/processors/image_ssim_diff/forms.py:76 -#, fuzzy msgid "Selection Mode" -msgstr "選擇方式:" +msgstr "選擇模式" #: changedetectionio/processors/image_ssim_diff/forms.py:79 msgid "Selection mode value is too long" -msgstr "選擇模式值太長" +msgstr "選擇模式數值太長" #: changedetectionio/processors/image_ssim_diff/forms.py:87 msgid "Screenshot Comparison" -msgstr "截圖對比" +msgstr "截圖比對" #: changedetectionio/processors/image_ssim_diff/preview.py:91 msgid "Preview unavailable - No snapshots captured yet" -msgstr "" +msgstr "無法預覽 - 尚未擷取快照" #: changedetectionio/processors/image_ssim_diff/processor.py:21 msgid "Visual / Image screenshot change detection" -msgstr "視覺/圖像截圖變化檢測" +msgstr "視覺 / 圖片截圖變更檢測" #: changedetectionio/processors/image_ssim_diff/processor.py:22 msgid "Compares screenshots using fast OpenCV algorithm, 10-100x faster than SSIM" -msgstr "" +msgstr "使用快速 OpenCV 演算法比對截圖,比 SSIM 快 10-100 倍" #: changedetectionio/processors/restock_diff/forms.py:15 msgid "Re-stock detection" @@ -2201,11 +2155,11 @@ msgstr "任何可用性變更" #: changedetectionio/processors/restock_diff/forms.py:18 msgid "Off, don't follow availability/restock" -msgstr "關閉,不遵循庫存/補貨情況" +msgstr "關閉,不追蹤可用性 / 補貨" #: changedetectionio/processors/restock_diff/forms.py:21 msgid "Below price to trigger notification" -msgstr "低於價格觸發通知" +msgstr "低於此價格觸發通知" #: changedetectionio/processors/restock_diff/forms.py:22 #: changedetectionio/processors/restock_diff/forms.py:24 @@ -2214,12 +2168,12 @@ msgstr "無限制" #: changedetectionio/processors/restock_diff/forms.py:23 msgid "Above price to trigger notification" -msgstr "高於價格觸發通知" +msgstr "高於此價格觸發通知" #: changedetectionio/processors/restock_diff/forms.py:25 #, python-format msgid "Threshold in %% for price changes since the original price" -msgstr "自原始價格以來價格變化的閾值(百分比)" +msgstr "自原始價格以來價格變化的閾值(%%)" #: changedetectionio/processors/restock_diff/forms.py:28 msgid "Should be between 0 and 100" @@ -2227,16 +2181,15 @@ msgstr "應介於 0 到 100 之間" #: changedetectionio/processors/restock_diff/forms.py:31 msgid "Follow price changes" -msgstr "關注價格變化" +msgstr "追蹤價格變化" #: changedetectionio/processors/restock_diff/forms.py:37 -#, fuzzy msgid "Restock & Price Detection" -msgstr "補貨及價格" +msgstr "補貨與價格檢測" #: changedetectionio/processors/restock_diff/processor.py:13 msgid "Re-stock & Price detection for pages with a SINGLE product" -msgstr "單個產品頁面的補貨和價格檢測" +msgstr "針對單一產品頁面的補貨與價格檢測" #: changedetectionio/processors/restock_diff/processor.py:14 msgid "Detects if the product goes back to in-stock" @@ -2244,153 +2197,140 @@ msgstr "檢測產品是否恢復庫存" #: changedetectionio/processors/text_json_diff/processor.py:22 msgid "Webpage Text/HTML, JSON and PDF changes" -msgstr "網頁文本/HTML、JSON 和 PDF 更改" +msgstr "網頁文字 / HTML、JSON 和 PDF 變更" #: changedetectionio/processors/text_json_diff/processor.py:23 msgid "Detects all text changes where possible" -msgstr "盡可能檢測所有文本更改" +msgstr "盡可能檢測所有文字變更" #: changedetectionio/templates/_helpers.html:25 msgid "Entry" -msgstr "" +msgstr "項目" #: changedetectionio/templates/_helpers.html:153 -#, fuzzy msgid "Actions" -msgstr "狀況" +msgstr "動作" #: changedetectionio/templates/_helpers.html:172 msgid "Add a row/rule after" -msgstr "" +msgstr "在後方新增一行 / 規則" #: changedetectionio/templates/_helpers.html:173 msgid "Remove this row/rule" -msgstr "" +msgstr "移除此行 / 規則" #: changedetectionio/templates/_helpers.html:174 msgid "Verify this rule against current snapshot" -msgstr "" +msgstr "針對目前快照驗證此規則" #: changedetectionio/templates/_helpers.html:184 msgid "" "Error - This watch needs Chrome (with playwright/sockpuppetbrowser), but " "Chrome based fetching is not enabled." -msgstr "" +msgstr "錯誤 - 此監測任務需要 Chrome(搭配 playwright / sockpuppetbrowser),但未啟用基於 Chrome 的抓取功能。" #: changedetectionio/templates/_helpers.html:184 msgid "Alternatively try our" -msgstr "" +msgstr "或者嘗試我們" #: changedetectionio/templates/_helpers.html:184 msgid "" "very affordable subscription based service which has all this setup for " "you" -msgstr "" +msgstr "非常實惠的訂閱服務,為您準備好所有設定" #: changedetectionio/templates/_helpers.html:185 -#, fuzzy msgid "You may need to" -msgstr "你需要" +msgstr "您可能需要" #: changedetectionio/templates/_helpers.html:185 msgid "Enable playwright environment variable" -msgstr "" +msgstr "啟用 playwright 環境變數" #: changedetectionio/templates/_helpers.html:185 msgid "and uncomment the" -msgstr "" +msgstr "並取消註解" #: changedetectionio/templates/_helpers.html:185 -#, fuzzy msgid "in the" -msgstr "這" +msgstr "於" #: changedetectionio/templates/_helpers.html:185 -#, fuzzy msgid "file" -msgstr "標題" +msgstr "檔案" #: changedetectionio/templates/_helpers.html:240 msgid "Set a hourly/week day schedule" -msgstr "" +msgstr "設定每小時 / 平日排程" #: changedetectionio/templates/_helpers.html:247 -#, fuzzy msgid "Schedule time limits" -msgstr "複檢時間(分鐘)" +msgstr "排程時間限制" #: changedetectionio/templates/_helpers.html:248 msgid "Business hours" -msgstr "" +msgstr "營業時間" #: changedetectionio/templates/_helpers.html:249 -#, fuzzy msgid "Weekends" -msgstr "週數" +msgstr "週末" #: changedetectionio/templates/_helpers.html:250 -#, fuzzy msgid "Reset" -msgstr "要求" +msgstr "重置" #: changedetectionio/templates/_helpers.html:259 msgid "" "Warning, one or more of your 'days' has a duration that would extend into" " the next day." -msgstr "" +msgstr "警告,您設定的一個或多個「天」持續時間將延伸至隔天。" #: changedetectionio/templates/_helpers.html:260 msgid "This could have unintended consequences." -msgstr "" +msgstr "這可能會產生非預期的後果。" #: changedetectionio/templates/_helpers.html:270 -#, fuzzy msgid "More help and examples about using the scheduler" -msgstr "更多幫助和示例請參見此處" +msgstr "關於使用排程器的更多幫助和範例" #: changedetectionio/templates/_helpers.html:275 -#, fuzzy msgid "Want to use a time schedule?" -msgstr "使用時間調度器" +msgstr "想要使用時間排程嗎?" #: changedetectionio/templates/_helpers.html:275 msgid "First confirm/save your Time Zone Settings" -msgstr "" +msgstr "請先確認 / 儲存您的時區設定" #: changedetectionio/templates/_helpers.html:284 msgid "" "Triggers a change if this text appears, AND something changed in the " "document." -msgstr "" +msgstr "如果出現此文字,且文件中有些內容變更,則觸發變更。" #: changedetectionio/templates/_helpers.html:284 -#, fuzzy msgid "Triggered text" -msgstr "錯誤文本" +msgstr "觸發的文字" #: changedetectionio/templates/_helpers.html:285 msgid "Ignored for calculating changes, but still shown." -msgstr "" +msgstr "計算變更時忽略,但仍會顯示。" #: changedetectionio/templates/_helpers.html:285 -#, fuzzy msgid "Ignored text" -msgstr "錯誤文本" +msgstr "忽略的文字" #: changedetectionio/templates/_helpers.html:286 -#, fuzzy msgid "No change-detection will occur because this text exists." -msgstr "文本匹配時阻止更改檢測" +msgstr "因為存在此文字,將不會進行變更檢測。" #: changedetectionio/templates/_helpers.html:286 -#, fuzzy msgid "Blocked text" -msgstr "錯誤文本" +msgstr "被阻擋的文字" #: changedetectionio/templates/base.html:78 #: changedetectionio/templates/base.html:168 msgid "GROUPS" -msgstr "團體" +msgstr "群組" #: changedetectionio/templates/base.html:81 #: changedetectionio/templates/base.html:169 @@ -2400,7 +2340,7 @@ msgstr "設定" #: changedetectionio/templates/base.html:84 #: changedetectionio/templates/base.html:170 msgid "IMPORT" -msgstr "導入" +msgstr "匯入" #: changedetectionio/templates/base.html:87 #: changedetectionio/templates/base.html:171 @@ -2415,19 +2355,19 @@ msgstr "編輯" #: changedetectionio/templates/base.html:101 #: changedetectionio/templates/base.html:177 msgid "LOG OUT" -msgstr "退出" +msgstr "登出" #: changedetectionio/templates/base.html:108 msgid "Search, or Use Alt+S Key" -msgstr "搜索或使用 Alt+S 鍵" +msgstr "搜尋,或使用 Alt+S 鍵" #: changedetectionio/templates/base.html:114 msgid "Toggle Light/Dark Mode" -msgstr "切換亮/暗模式" +msgstr "切換亮 / 暗模式" #: changedetectionio/templates/base.html:115 msgid "Toggle light/dark mode" -msgstr "切換亮/暗模式" +msgstr "切換亮 / 暗模式" #: changedetectionio/templates/base.html:125 msgid "Change Language" @@ -2438,41 +2378,37 @@ msgid "Change language" msgstr "更改語言" #: changedetectionio/templates/base.html:253 -#, fuzzy msgid "Watch List" -msgstr "監控列表" +msgstr "監測列表" #: changedetectionio/templates/base.html:258 -#, fuzzy msgid "Watches" -msgstr "監控項" +msgstr "監測任務" #: changedetectionio/templates/base.html:261 msgid "Queue Status" -msgstr "" +msgstr "佇列狀態" #: changedetectionio/templates/base.html:270 -#, fuzzy msgid "Queue" -msgstr "排隊" +msgstr "佇列" #: changedetectionio/templates/base.html:274 #: changedetectionio/templates/base.html:279 -#, fuzzy msgid "Settings" msgstr "設定" #: changedetectionio/templates/base.html:293 msgid "Sitemap Crawler" -msgstr "" +msgstr "Sitemap 爬蟲" #: changedetectionio/templates/base.html:318 msgid "Sitemap" -msgstr "" +msgstr "Sitemap" #: changedetectionio/templates/base.html:354 msgid "Real-time updates offline" -msgstr "離線實時更新" +msgstr "離線即時更新" #: changedetectionio/templates/base.html:364 msgid "Select Language" @@ -2482,26 +2418,24 @@ msgstr "選擇語言" msgid "" "Language support is in beta, please help us improve by opening a PR on " "GitHub with any updates." -msgstr "" +msgstr "語言支援尚在 Beta 階段,請在 GitHub 上提交 PR 以協助我們改進。" #: changedetectionio/templates/base.html:387 #: changedetectionio/templates/base.html:400 -#, fuzzy msgid "Search" -msgstr "搜尋中" +msgstr "搜尋" #: changedetectionio/templates/base.html:392 msgid "URL or Title" -msgstr "" +msgstr "URL 或標題" #: changedetectionio/templates/base.html:392 -#, fuzzy msgid "in" -msgstr "資訊" +msgstr "於" #: changedetectionio/templates/base.html:393 msgid "Enter search term..." -msgstr "" +msgstr "輸入搜尋關鍵字 ..." #: changedetectionio/templates/login.html:11 msgid "Password" @@ -2509,409 +2443,4 @@ msgstr "密碼" #: changedetectionio/templates/login.html:17 msgid "Login" -msgstr "登入" - -#~ msgid "Invalid time format. Use HH:MM." -#~ msgstr "時間格式無效。使用時:分。" - -#~ msgid "Not a valid timezone name" -#~ msgstr "不是有效的時區名稱" - -#~ msgid "not set" -#~ msgstr "還沒有" - -#~ msgid "Start At" -#~ msgstr "統計數據" - -#~ msgid "Run duration" -#~ msgstr "暫無信息" - -#~ msgid "Use time scheduler" -#~ msgstr "使用時間調度器" - -#~ msgid "Optional timezone to run in" -#~ msgstr "運行時的可選時區" - -#~ msgid "Monday" -#~ msgstr "週一" - -#~ msgid "Tuesday" -#~ msgstr "週二" - -#~ msgid "Wednesday" -#~ msgstr "週三" - -#~ msgid "Thursday" -#~ msgstr "週四" - -#~ msgid "Friday" -#~ msgstr "星期五" - -#~ msgid "Saturday" -#~ msgstr "週六" - -#~ msgid "Sunday" -#~ msgstr "星期日" - -#~ msgid "Weeks" -#~ msgstr "週數" - -#~ msgid "Should contain zero or more seconds" -#~ msgstr "應包含零或更多秒" - -#~ msgid "Days" -#~ msgstr "天" - -#~ msgid "Hours" -#~ msgstr "字" - -#~ msgid "Minutes" -#~ msgstr "沉默的" - -#~ msgid "Seconds" -#~ msgstr "秒" - -#~ msgid "Empty value not allowed." -#~ msgstr "不允許為空值。" - -#~ msgid "Invalid value." -#~ msgstr "無效值。" - -#~ msgid "Watch" -#~ msgstr "# 手錶" - -#~ msgid "Processor" -#~ msgstr "處理器" - -#~ msgid "Edit > Watch" -#~ msgstr "先編輯後觀看" - -#~ msgid "Fetch Method" -#~ msgstr "設置獲取方法" - -#~ msgid "Notification Body" -#~ msgstr "通知" - -#~ msgid "Notification format" -#~ msgstr "通知" - -#~ msgid "Notification Title" -#~ msgstr "通知" - -#~ msgid "Notification URL List" -#~ msgstr "通知" - -#~ msgid "Processor - What do you want to achieve?" -#~ msgstr "處理器 - 您想要實現什麼?" - -#~ msgid "Default timezone for watch check scheduler" -#~ msgstr "手錶檢查調度程序的默認時區" - -#~ msgid "Wait seconds before extracting text" -#~ msgstr "提取文本前幾秒。" - -#~ msgid "Should contain one or more seconds" -#~ msgstr "應包含一秒或多秒" - -#~ msgid "URLs" -#~ msgstr "網址" - -#~ msgid "Upload .xlsx file" -#~ msgstr "上傳 .xlsx 文件" - -#~ msgid "Must be .xlsx file!" -#~ msgstr "必須是 .xlsx 文件!" - -#~ msgid "File mapping" -#~ msgstr "文件映射類型。" - -#~ msgid "Operation" -#~ msgstr "用戶界面選項" - -#~ msgid "Selector" -#~ msgstr "選擇方式:" - -#~ msgid "value" -#~ msgstr "暫停" - -#~ msgid "Use global settings for time between check and scheduler." -#~ msgstr "使用全局設置檢查和調度程序之間的時間。" - -#~ msgid "CSS/JSONPath/JQ/XPath Filters" -#~ msgstr "CSS/xPath 過濾器" - -#~ msgid "Remove elements" -#~ msgstr "已刪除" - -#~ msgid "Extract text" -#~ msgstr "提取數據" - -#~ msgid "Ignore lines containing" -#~ msgstr "忽略任何匹配的行" - -#~ msgid "Request body" -#~ msgstr "要求" - -#~ msgid "Request method" -#~ msgstr "要求" - -#~ msgid "Ignore status codes (process non-2xx status codes as normal)" -#~ msgstr "忽略狀態代碼(正常處理非 2xx 狀態代碼)" - -#~ msgid "Only trigger when unique lines appear in all history" -#~ msgstr "僅當出現唯一線條時觸發" - -#~ msgid "Sort text alphabetically" -#~ msgstr "按字母順序對文本進行排序" - -#~ msgid "Strip ignored lines" -#~ msgstr "去掉忽略的行" - -#~ msgid "Trim whitespace before and after text" -#~ msgstr "刪除每行文本前後的所有空格" - -#~ msgid "Added lines" -#~ msgstr "線路" - -#~ msgid "Replaced/changed lines" -#~ msgstr "更換/更改線路" - -#~ msgid "Removed lines" -#~ msgstr "已刪除" - -#~ msgid "Keyword triggers - Trigger/wait for text" -#~ msgstr "關鍵字觸發器 - 觸發/等待文本" - -#~ msgid "Block change-detection while text matches" -#~ msgstr "文本匹配時阻止更改檢測" - -#~ msgid "Execute JavaScript before change detection" -#~ msgstr "在更改檢測之前執行 JavaScript" - -#~ msgid "Proxy" -#~ msgstr "代理人" - -#~ msgid "Send a notification when the filter can no longer be found on the page" -#~ msgstr "當頁面上找不到過濾器時發送通知" - -#~ msgid "On" -#~ msgstr "沒有任何" - -#~ msgid "Attach screenshot to notification (where possible)" -#~ msgstr "將屏幕截圖附加到通知(如果可能)" - -#~ msgid "Match" -#~ msgstr "# 手錶" - -#~ msgid "Match all of the following" -#~ msgstr "匹配以下所有內容" - -#~ msgid "Match any of the following" -#~ msgstr "匹配以下任意一項" - -#~ msgid "Use page <title> in list" -#~ msgstr "使用列表中的頁面<標題>" - -#~ msgid "Name" -#~ msgstr "取消靜音" - -#~ msgid "Proxy URL" -#~ msgstr "代理網址" - -#~ msgid "Proxy URLs must start with http://, https:// or socks5://" -#~ msgstr "代理 URL 必須以 http://、https:// 或ocks5:// 開頭" - -#~ msgid "Browser connection URL" -#~ msgstr "瀏覽器連接網址" - -#~ msgid "Browser URLs must start with wss:// or ws://" -#~ msgstr "瀏覽器 URL 必須以 wss:// 或 ws:// 開頭" - -#~ msgid "Plaintext requests" -#~ msgstr "明文請求" - -#~ msgid "Chrome requests" -#~ msgstr "要求" - -#~ msgid "Default proxy" -#~ msgstr "默認代理" - -#~ msgid "Random jitter seconds ± check" -#~ msgstr "隨機抖動秒±檢查" - -#~ msgid "Number of fetch workers" -#~ msgstr "取貨工人數量" - -#~ msgid "Should be between 1 and 50" -#~ msgstr "應介於 1 到 50 之間" - -#~ msgid "Requests timeout in seconds" -#~ msgstr "請求超時(以秒為單位)" - -#~ msgid "Should be between 1 and 999" -#~ msgstr "應介於 1 到 999 之間" - -#~ msgid "Default User-Agent overrides" -#~ msgstr "默認用戶代理覆蓋" - -#~ msgid "Open 'History' page in a new tab" -#~ msgstr "在新選項卡中打開“歷史記錄”頁面" - -#~ msgid "Realtime UI Updates Enabled" -#~ msgstr "離線實時更新" - -#~ msgid "Favicons Enabled" -#~ msgstr "考慮啟用" - -#~ msgid "Use page <title> in watch overview list" -#~ msgstr "在觀看概覽列表中使用頁面<標題>" - -#~ msgid "API access token security check enabled" -#~ msgstr "已啟用 API 訪問令牌安全檢查" - -#~ msgid "Notification base URL override" -#~ msgstr "通知警報計數" - -#~ msgid "Treat empty pages as a change?" -#~ msgstr "將空頁視為更改?" - -#~ msgid "Ignore Text" -#~ msgstr "錯誤文本" - -#~ msgid "Ignore whitespace" -#~ msgstr "忽略空格" - -#~ msgid "Must be between 0 and 100" -#~ msgstr "必須介於 0 到 100 之間" - -#~ msgid "Pager size" -#~ msgstr "尋呼機尺寸" - -#~ msgid "Should be atleast zero (disabled)" -#~ msgstr "應至少為零(禁用)" - -#~ msgid "RSS Content format" -#~ msgstr "RSS 內容格式" - -#~ msgid "RSS <description> body built from" -#~ msgstr "RSS <描述> 正文構建於" - -#~ msgid "Render anchor tag content" -#~ msgstr "渲染錨標記內容" - -#~ msgid "Allow anonymous access to watch history page when password is enabled" -#~ msgstr "啟用密碼後允許匿名訪問觀看歷史記錄頁面" - -#~ msgid "Hide muted watches from RSS feed" -#~ msgstr "從 RSS 源中隱藏靜音的手錶" - -#~ msgid "Enable RSS reader mode " -#~ msgstr "啟用 RSS 閱讀器模式" - -#~ msgid "Number of changes to show in watch RSS feed" -#~ msgstr "觀看 RSS 源中顯示的更改數量" - -#~ msgid "Should contain zero or more attempts" -#~ msgstr "應包含零次或多次嘗試" - -#~ msgid "Number of times the filter can be missing before sending a notification" -#~ msgstr "發送通知之前過濾器可能丟失的次數" - -#~ msgid "RegEx to extract" -#~ msgstr "要提取的正則表達式" - -#~ msgid "Extract as CSV" -#~ msgstr "提取數據" - -#~ msgid "Bounding box value is too long" -#~ msgstr "邊界框值太長" - -#~ msgid "Bounding box must be in format: x,y,width,height (integers only)" -#~ msgstr "邊界框的格式必須為:x,y,寬度,高度(僅限整數)" - -#~ msgid "Bounding box values must be non-negative" -#~ msgstr "邊界框值必須是非負數" - -#~ msgid "Bounding box values are too large" -#~ msgstr "邊界框值太大" - -#~ msgid "Minimum Change Percentage" -#~ msgstr "最小變化百分比" - -#~ msgid "Pixel Difference Sensitivity" -#~ msgstr "像素差異靈敏度" - -#~ msgid "Use global default" -#~ msgstr "使用系統默認值" - -#~ msgid "Bounding Box" -#~ msgstr "邊界框" - -#~ msgid "Selection Mode" -#~ msgstr "選擇方式:" - -#~ msgid "Selection mode value is too long" -#~ msgstr "選擇模式值太長" - -#~ msgid "Screenshot Comparison" -#~ msgstr "截圖對比" - -#~ msgid "Re-stock detection" -#~ msgstr "補貨檢測" - -#~ msgid "In Stock only (Out Of Stock -> In Stock only)" -#~ msgstr "僅有庫存(缺貨 -> 僅有庫存)" - -#~ msgid "Any availability changes" -#~ msgstr "任何可用性變更" - -#~ msgid "Off, don't follow availability/restock" -#~ msgstr "關閉,不遵循庫存/補貨情況" - -#~ msgid "Below price to trigger notification" -#~ msgstr "低於價格觸發通知" - -#~ msgid "No limit" -#~ msgstr "無限制" - -#~ msgid "Above price to trigger notification" -#~ msgstr "高於價格觸發通知" - -#~ msgid "Threshold in %% for price changes since the original price" -#~ msgstr "自原始價格以來價格變化的閾值(百分比)" - -#~ msgid "Should be between 0 and 100" -#~ msgstr "應介於 0 到 100 之間" - -#~ msgid "Follow price changes" -#~ msgstr "關注價格變化" - -#~ msgid "Restock & Price Detection" -#~ msgstr "補貨及價格" - -#~ msgid "Visual / Image screenshot change detection" -#~ msgstr "視覺/圖像截圖變化檢測" - -#~ msgid "" -#~ "Compares screenshots using fast OpenCV " -#~ "algorithm, 10-100x faster than SSIM" -#~ msgstr "使用快速 OpenCV 算法比較屏幕截圖,比 SSIM 快 10-100 倍" - -#~ msgid "Visual" -#~ msgstr "視覺的" - -#~ msgid "Re-stock & Price detection for pages with a SINGLE product" -#~ msgstr "單個產品頁面的補貨和價格檢測" - -#~ msgid "Detects if the product goes back to in-stock" -#~ msgstr "檢測產品是否恢復庫存" - -#~ msgid "Restock" -#~ msgstr "補貨" - -#~ msgid "Webpage Text/HTML, JSON and PDF changes" -#~ msgstr "網頁文本/HTML、JSON 和 PDF 更改" - -#~ msgid "Detects all text changes where possible" -#~ msgstr "盡可能檢測所有文本更改" - +msgstr "登入" \ No newline at end of file From 4643082c5b4f2df8a79462156527c349a0b9c115 Mon Sep 17 00:00:00 2001 From: dgtlmoon <dgtlmoon@gmail.com> Date: Thu, 15 Jan 2026 13:21:49 +0100 Subject: [PATCH 06/11] i18n: Recompile zh_Hant_TW/LC_MESSAGES/messages.mo --- .../zh_Hant_TW/LC_MESSAGES/messages.mo | Bin 41490 -> 41916 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/changedetectionio/translations/zh_Hant_TW/LC_MESSAGES/messages.mo b/changedetectionio/translations/zh_Hant_TW/LC_MESSAGES/messages.mo index a4499f4303cea8b5bb30a935141531a7b28debc8..ddfd0282d55955f709e9a63beaa12ed4c6c5d366 100644 GIT binary patch delta 9422 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 K14+df`u{J@%lV4{ delta 8993 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 Owqa4$j*IzUcm6;0GKT*E From 04de3979165768b62f8f1146f26430345414b076 Mon Sep 17 00:00:00 2001 From: dgtlmoon <dgtlmoon@gmail.com> Date: Thu, 15 Jan 2026 13:56:08 +0100 Subject: [PATCH 07/11] Revert sub-process brotli saving because it could fork-bomb/use up too many system resources (#3747) --- changedetectionio/__init__.py | 3 +- changedetectionio/model/Watch.py | 138 ++++-------------- .../image_handler/isolated_libvips.py | 22 ++- 3 files changed, 43 insertions(+), 120 deletions(-) diff --git a/changedetectionio/__init__.py b/changedetectionio/__init__.py index 02ad45093..dd16abdc1 100644 --- a/changedetectionio/__init__.py +++ b/changedetectionio/__init__.py @@ -41,9 +41,10 @@ from loguru import logger # # IMPLEMENTATION: # 1. Explicit contexts everywhere (primary protection): -# - Watch.py: ctx = multiprocessing.get_context('spawn') # - playwright.py: ctx = multiprocessing.get_context('spawn') # - puppeteer.py: ctx = multiprocessing.get_context('spawn') +# - isolated_opencv.py: ctx = multiprocessing.get_context('spawn') +# - isolated_libvips.py: ctx = multiprocessing.get_context('spawn') # # 2. Global default (defense-in-depth, below): # - Safety net if future code forgets explicit context diff --git a/changedetectionio/model/Watch.py b/changedetectionio/model/Watch.py index 79e0f8737..f5bc8593b 100644 --- a/changedetectionio/model/Watch.py +++ b/changedetectionio/model/Watch.py @@ -18,21 +18,31 @@ BROTLI_COMPRESS_SIZE_THRESHOLD = int(os.getenv('SNAPSHOT_BROTLI_COMPRESSION_THRE minimum_seconds_recheck_time = int(os.getenv('MINIMUM_SECONDS_RECHECK_TIME', 3)) mtable = {'seconds': 1, 'minutes': 60, 'hours': 3600, 'days': 86400, 'weeks': 86400 * 7} -def _brotli_compress_worker(conn, filepath, mode=None): +def _brotli_save(contents, filepath, mode=None, fallback_uncompressed=False): """ - Worker function to compress data with brotli in a separate process. - This isolates memory - when process exits, OS reclaims all memory. + Save compressed data using native brotli. + Testing shows no memory leak when using gc.collect() after compression. Args: - conn: multiprocessing.Pipe connection to receive data + contents: data to compress (str or bytes) filepath: destination file path mode: brotli compression mode (e.g., brotli.MODE_TEXT) + fallback_uncompressed: if True, save uncompressed on failure; if False, raise exception + + Returns: + str: actual filepath saved (may differ from input if fallback used) + + Raises: + Exception: if compression fails and fallback_uncompressed is False """ import brotli + import gc + + # Ensure contents are bytes + if isinstance(contents, str): + contents = contents.encode('utf-8') try: - # Receive data from parent process via pipe (avoids pickle overhead) - contents = conn.recv() logger.debug(f"Starting brotli compression of {len(contents)} bytes.") if mode is not None: @@ -43,111 +53,25 @@ def _brotli_compress_worker(conn, filepath, mode=None): with open(filepath, 'wb') as f: f.write(compressed_data) - # Send success status back - conn.send(True) logger.debug(f"Finished brotli compression - From {len(contents)} to {len(compressed_data)} bytes.") - # No need for explicit cleanup - process exit frees all memory - except Exception as e: - logger.critical(f"Brotli compression worker failed: {e}") - conn.send(False) - finally: - conn.close() + # Force garbage collection to prevent memory buildup + gc.collect() -def _brotli_subprocess_save(contents, filepath, mode=None, timeout=30, fallback_uncompressed=False): - """ - Save compressed data using subprocess to isolate memory. - Uses Pipe to avoid pickle overhead for large data. - - Args: - contents: data to compress (str or bytes) - filepath: destination file path - mode: brotli compression mode (e.g., brotli.MODE_TEXT) - timeout: subprocess timeout in seconds - fallback_uncompressed: if True, save uncompressed on failure; if False, raise exception - - Returns: - str: actual filepath saved (may differ from input if fallback used) - - Raises: - Exception: if compression fails and fallback_uncompressed is False - """ - import multiprocessing - import sys - - # Ensure contents are bytes - if isinstance(contents, str): - contents = contents.encode('utf-8') - - # Use explicit spawn context for thread safety (avoids fork() with multi-threaded parent) - # Always use spawn - consistent behavior in tests and production - ctx = multiprocessing.get_context('spawn') - parent_conn, child_conn = ctx.Pipe() - - # Run compression in subprocess using spawn (not fork) - proc = ctx.Process(target=_brotli_compress_worker, args=(child_conn, filepath, mode)) - - # Windows-safe: Set daemon=False explicitly to avoid issues with process cleanup - proc.daemon = False - proc.start() - - try: - # Send data to subprocess via pipe (avoids pickle) - parent_conn.send(contents) - - # Wait for result with timeout - if parent_conn.poll(timeout): - success = parent_conn.recv() - else: - success = False - logger.warning(f"Brotli compression subprocess timed out after {timeout}s") - # Graceful termination with platform-aware cleanup - try: - proc.terminate() - except Exception as term_error: - logger.debug(f"Process termination issue (may be normal on Windows): {term_error}") - - parent_conn.close() - proc.join(timeout=5) - - # Force kill if still alive after graceful termination - if proc.is_alive(): - try: - if sys.platform == 'win32': - # Windows: use kill() which is more forceful - proc.kill() - else: - # Unix: terminate() already sent SIGTERM, now try SIGKILL - proc.kill() - proc.join(timeout=2) - except Exception as kill_error: - logger.warning(f"Failed to kill brotli compression process: {kill_error}") - - # Check if file was created successfully - if success and os.path.exists(filepath): - return filepath + return filepath except Exception as e: logger.error(f"Brotli compression error: {e}") - try: - parent_conn.close() - except: - pass - try: - proc.terminate() - proc.join(timeout=2) - except: - pass - # Compression failed - if fallback_uncompressed: - logger.warning(f"Brotli compression failed for {filepath}, saving uncompressed") - fallback_path = filepath.replace('.br', '') - with open(fallback_path, 'wb') as f: - f.write(contents) - return fallback_path - else: - raise Exception(f"Brotli compression subprocess failed for {filepath}") + # Compression failed + if fallback_uncompressed: + logger.warning(f"Brotli compression failed for {filepath}, saving uncompressed") + fallback_path = filepath.replace('.br', '') + with open(fallback_path, 'wb') as f: + f.write(contents) + return fallback_path + else: + raise Exception(f"Brotli compression failed for {filepath}: {e}") class model(watch_base): @@ -523,7 +447,7 @@ class model(watch_base): if not os.path.exists(dest): try: - actual_dest = _brotli_subprocess_save(contents, dest, mode=brotli.MODE_TEXT, fallback_uncompressed=True) + actual_dest = _brotli_save(contents, dest, mode=brotli.MODE_TEXT, fallback_uncompressed=True) if actual_dest != dest: snapshot_fname = os.path.basename(actual_dest) except Exception as e: @@ -949,13 +873,13 @@ class model(watch_base): def save_last_text_fetched_before_filters(self, contents): import brotli filepath = os.path.join(self.watch_data_dir, 'last-fetched.br') - _brotli_subprocess_save(contents, filepath, mode=brotli.MODE_TEXT, fallback_uncompressed=False) + _brotli_save(contents, filepath, mode=brotli.MODE_TEXT, fallback_uncompressed=False) def save_last_fetched_html(self, timestamp, contents): self.ensure_data_dir_exists() snapshot_fname = f"{timestamp}.html.br" filepath = os.path.join(self.watch_data_dir, snapshot_fname) - _brotli_subprocess_save(contents, filepath, mode=None, fallback_uncompressed=True) + _brotli_save(contents, filepath, mode=None, fallback_uncompressed=True) self._prune_last_fetched_html_snapshots() def get_fetched_html(self, timestamp): diff --git a/changedetectionio/processors/image_ssim_diff/image_handler/isolated_libvips.py b/changedetectionio/processors/image_ssim_diff/image_handler/isolated_libvips.py index ceb63b0b7..d0b55507d 100644 --- a/changedetectionio/processors/image_ssim_diff/image_handler/isolated_libvips.py +++ b/changedetectionio/processors/image_ssim_diff/image_handler/isolated_libvips.py @@ -13,14 +13,9 @@ Research: https://github.com/libvips/pyvips/issues/234 import multiprocessing -# CRITICAL: Use 'spawn' instead of 'fork' to avoid inheriting parent's +# CRITICAL: Use 'spawn' context instead of 'fork' to avoid inheriting parent's # LibVIPS threading state which can cause hangs in gaussblur operations # https://docs.python.org/3/library/multiprocessing.html#contexts-and-start-methods -try: - multiprocessing.set_start_method('spawn', force=False) -except RuntimeError: - # Already set, ignore - pass def _worker_generate_diff(conn, img_bytes_from, img_bytes_to, threshold, blur_sigma, max_width, max_height): @@ -95,9 +90,10 @@ def generate_diff_isolated(img_bytes_from, img_bytes_to, threshold, blur_sigma, Returns: bytes: JPEG diff image or None on failure """ - parent_conn, child_conn = multiprocessing.Pipe() + ctx = multiprocessing.get_context('spawn') + parent_conn, child_conn = ctx.Pipe() - p = multiprocessing.Process( + p = ctx.Process( target=_worker_generate_diff, args=(child_conn, img_bytes_from, img_bytes_to, threshold, blur_sigma, max_width, max_height) ) @@ -140,7 +136,8 @@ def calculate_change_percentage_isolated(img_bytes_from, img_bytes_to, threshold Returns: float: Change percentage """ - parent_conn, child_conn = multiprocessing.Pipe() + ctx = multiprocessing.get_context('spawn') + parent_conn, child_conn = ctx.Pipe() def _worker_calculate(conn): try: @@ -185,7 +182,7 @@ def calculate_change_percentage_isolated(img_bytes_from, img_bytes_to, threshold finally: conn.close() - p = multiprocessing.Process(target=_worker_calculate, args=(child_conn,)) + p = ctx.Process(target=_worker_calculate, args=(child_conn,)) p.start() result = 0.0 @@ -233,7 +230,8 @@ def compare_images_isolated(img_bytes_from, img_bytes_to, threshold, blur_sigma, tuple: (changed_detected, change_percentage) """ print(f"[Parent] Starting compare_images_isolated subprocess", flush=True) - parent_conn, child_conn = multiprocessing.Pipe() + ctx = multiprocessing.get_context('spawn') + parent_conn, child_conn = ctx.Pipe() def _worker_compare(conn): try: @@ -301,7 +299,7 @@ def compare_images_isolated(img_bytes_from, img_bytes_to, threshold, blur_sigma, finally: conn.close() - p = multiprocessing.Process(target=_worker_compare, args=(child_conn,)) + p = ctx.Process(target=_worker_compare, args=(child_conn,)) print(f"[Parent] Starting subprocess (pid will be assigned)", flush=True) p.start() print(f"[Parent] Subprocess started (pid={p.pid}), waiting for result (30s timeout)", flush=True) From 15cdfac9d985fa75f0fa4f5e7d4dff9105706788 Mon Sep 17 00:00:00 2001 From: dgtlmoon <dgtlmoon@gmail.com> Date: Thu, 15 Jan 2026 14:07:09 +0100 Subject: [PATCH 08/11] 0.52.5 --- changedetectionio/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changedetectionio/__init__.py b/changedetectionio/__init__.py index dd16abdc1..424865eff 100644 --- a/changedetectionio/__init__.py +++ b/changedetectionio/__init__.py @@ -2,7 +2,7 @@ # Read more https://github.com/dgtlmoon/changedetection.io/wiki # Semver means never use .01, or 00. Should be .1. -__version__ = '0.52.4' +__version__ = '0.52.5' from changedetectionio.strtobool import strtobool from json.decoder import JSONDecodeError From 15f16455fcaafc15231cbb012d4a0f4e46b15a8f Mon Sep 17 00:00:00 2001 From: dgtlmoon <dgtlmoon@gmail.com> Date: Thu, 15 Jan 2026 17:28:09 +0100 Subject: [PATCH 09/11] UI - Show queue size above watch table in realtime --- .../blueprint/watchlist/__init__.py | 5 ++-- .../watchlist/templates/watch-overview.html | 11 ++++++-- changedetectionio/static/js/realtime.js | 6 +++- .../static/styles/scss/parts/_pagination.scss | 2 -- .../styles/scss/parts/_watch_table.scss | 28 +++++++++++++++++++ changedetectionio/static/styles/styles.css | 2 +- 6 files changed, 45 insertions(+), 9 deletions(-) diff --git a/changedetectionio/blueprint/watchlist/__init__.py b/changedetectionio/blueprint/watchlist/__init__.py index 56a7f184d..e78bc9146 100644 --- a/changedetectionio/blueprint/watchlist/__init__.py +++ b/changedetectionio/blueprint/watchlist/__init__.py @@ -2,7 +2,6 @@ import os import time from flask import Blueprint, request, make_response, render_template, redirect, url_for, flash, session -from flask_login import current_user from flask_paginate import Pagination, get_page_parameter from changedetectionio import forms @@ -85,6 +84,7 @@ def construct_blueprint(datastore: ChangeDetectionStore, update_q, queuedWatchMe app_rss_token=datastore.data['settings']['application'].get('rss_access_token'), datastore=datastore, errored_count=errored_count, + extra_classes='has-queue' if len(update_q.queue) else '', form=form, generate_tag_colors=processors.generate_processor_badge_colors, guid=datastore.data['app_guid'], @@ -92,9 +92,10 @@ def construct_blueprint(datastore: ChangeDetectionStore, update_q, queuedWatchMe hosted_sticky=os.getenv("SALTED_PASS", False) == False, now_time_server=round(time.time()), pagination=pagination, + processor_badge_css=processors.get_processor_badge_css(), processor_badge_texts=processors.get_processor_badge_texts(), processor_descriptions=processors.get_processor_descriptions(), - processor_badge_css=processors.get_processor_badge_css(), + queue_size=len(update_q.queue), queued_uuids=[q_uuid.item['uuid'] for q_uuid in update_q.queue], search_q=request.args.get('q', '').strip(), sort_attribute=request.args.get('sort') if request.args.get('sort') else request.cookies.get('sort'), diff --git a/changedetectionio/blueprint/watchlist/templates/watch-overview.html b/changedetectionio/blueprint/watchlist/templates/watch-overview.html index fa51302fe..b21393ac2 100644 --- a/changedetectionio/blueprint/watchlist/templates/watch-overview.html +++ b/changedetectionio/blueprint/watchlist/templates/watch-overview.html @@ -99,9 +99,14 @@ html[data-darkmode="true"] .watch-tag-list.tag-{{ class_name }} { data-confirm-message="{{ _('<p>Are you sure you want to delete the selected watches?</strong></p><p>This action cannot be undone.</p>') }}" data-confirm-button="{{ _('Delete') }}"><i data-feather="trash" style="width: 14px; height: 14px; stroke: white; margin-right: 4px;"></i>{{ _('Delete') }}</button> </div> - {%- if watches|length >= pagination.per_page -%} - {{ pagination.info }} - {%- endif -%} + + <div id="stats_row"> + <div class="left">{%- if watches|length >= pagination.per_page -%}{{ pagination.info }}{%- endif -%}</div> + <div class="right" >{{ _('Queued size') }}: <span id="queue-size-int">{{ queue_size }}</span></div> + </div> + + + {%- if search_q -%}<div id="search-result-info">{{ _('Searching') }} "<strong><i>{{search_q}}</i></strong>"</div>{%- endif -%} <div> <a href="{{url_for('watchlist.index')}}" class="pure-button button-tag {{'active' if not active_tag_uuid }}">{{ _('All') }}</a> diff --git a/changedetectionio/static/js/realtime.js b/changedetectionio/static/js/realtime.js index c64a9c297..474b2df0b 100644 --- a/changedetectionio/static/js/realtime.js +++ b/changedetectionio/static/js/realtime.js @@ -76,7 +76,7 @@ $(document).ready(function () { // Cache DOM elements for performance const queueBubble = document.getElementById('queue-bubble'); - + const queueSizePagerInfoText = document.getElementById('queue-size-int'); // Only try to connect if authentication isn't required or user is authenticated // The 'is_authenticated' variable will be set in the template if (typeof is_authenticated !== 'undefined' ? is_authenticated : true) { @@ -118,6 +118,10 @@ $(document).ready(function () { socket.on('queue_size', function (data) { console.log(`${data.event_timestamp} - Queue size update: ${data.q_length}`); + if(queueSizePagerInfoText) { + queueSizePagerInfoText.textContent = parseInt(data.q_length).toLocaleString() || 'None'; + } + document.body.classList.toggle('has-queue', parseInt(data.q_length) > 0); // Update queue bubble in action sidebar //if (queueBubble) { diff --git a/changedetectionio/static/styles/scss/parts/_pagination.scss b/changedetectionio/static/styles/scss/parts/_pagination.scss index 3624548a3..502a41f57 100644 --- a/changedetectionio/static/styles/scss/parts/_pagination.scss +++ b/changedetectionio/static/styles/scss/parts/_pagination.scss @@ -1,6 +1,4 @@ .pagination-page-info { - color: #fff; - font-size: 0.85rem; text-transform: capitalize; } diff --git a/changedetectionio/static/styles/scss/parts/_watch_table.scss b/changedetectionio/static/styles/scss/parts/_watch_table.scss index afcb66afc..bc66aa7fc 100644 --- a/changedetectionio/static/styles/scss/parts/_watch_table.scss +++ b/changedetectionio/static/styles/scss/parts/_watch_table.scss @@ -1,4 +1,32 @@ /* table related */ +#stats_row { + display: flex; + align-items: center; + width: 100%; + color: #fff; + font-size: 0.85rem; + >* { + padding-bottom: 0.5rem; + } + .left { + text-align: left; + } + + .right { + opacity: 0.5; + transition: opacity 0.6s ease; + margin-left: auto; /* pushes it to the far right */ + text-align: right; + } +} +body.has-queue { + #stats_row { + .right { + opacity: 1.0; + } + } +} + .watch-table { width: 100%; font-size: 80%; diff --git a/changedetectionio/static/styles/styles.css b/changedetectionio/static/styles/styles.css index 5850ac6dc..1ca89e5dc 100644 --- a/changedetectionio/static/styles/styles.css +++ b/changedetectionio/static/styles/styles.css @@ -1 +1 @@ -:root{--color-white: #fff;--color-grey-50: #111;--color-grey-100: #262626;--color-grey-200: #333;--color-grey-300: #444;--color-grey-325: #555;--color-grey-350: #565d64;--color-grey-400: #666;--color-grey-500: #777;--color-grey-600: #999;--color-grey-700: #cbcbcb;--color-grey-750: #ddd;--color-grey-800: #e0e0e0;--color-grey-850: #eee;--color-grey-900: #f2f2f2;--color-black: #000;--color-dark-red: #a00;--color-light-red: #dd0000;--color-background-page: var(--color-grey-100);--color-background-gradient-first: #5ad8f7;--color-background-gradient-second: #2f50af;--color-background-gradient-third: #9150bf;--color-background: var(--color-white);--color-text: var(--color-grey-200);--color-link: #1b98f8;--color-menu-accent: #ed5900;--color-background-code: var(--color-grey-850);--color-error: var(--color-dark-red);--color-error-input: #ffebeb;--color-error-list: var(--color-light-red);--color-table-background: var(--color-background);--color-table-stripe: var(--color-grey-900);--color-text-tab: var(--color-white);--color-background-tab: rgba(255, 255, 255, 0.2);--color-background-tab-hover: rgba(255, 255, 255, 0.5);--color-text-tab-active: #222;--color-api-key: #0078e7;--color-background-button-primary: #0078e7;--color-background-button-green: #42dd53;--color-background-button-red: #dd4242;--color-background-button-success: rgb(28, 184, 65);--color-background-button-error: rgb(202, 60, 60);--color-text-button-error: var(--color-white);--color-background-button-warning: rgb(202, 60, 60);--color-text-button-warning: var(--color-white);--color-background-button-secondary: rgb(66, 184, 221);--color-background-button-cancel: rgb(200, 200, 200);--color-text-button: var(--color-white);--color-background-button-tag: rgb(99, 99, 99);--color-background-snapshot-age: #dfdfdf;--color-error-text-snapshot-age: var(--color-white);--color-error-background-snapshot-age: #ff0000;--color-background-button-tag-active: #9c9c9c;--color-text-messages: var(--color-white);--color-background-messages-message: rgba(255, 255, 255, .2);--color-background-messages-error: rgba(255, 1, 1, .5);--color-background-messages-notice: rgba(255, 255, 255, .5);--color-border-notification: #ccc;--color-background-checkbox-operations: rgba(0, 0, 0, 0.05);--color-warning: #ff3300;--color-border-warning: var(--color-warning);--color-text-legend: var(--color-white);--color-link-new-version: #e07171;--color-last-checked: #bbb;--color-text-footer: #444;--color-border-watch-table-cell: #eee;--color-text-watch-tag-list: rgba(231, 0, 105, 0.4);--color-background-new-watch-form: rgba(0, 0, 0, 0.05);--color-background-new-watch-input: var(--color-white);--color-background-new-watch-input-transparent: rgba(255, 255, 255, 0.1);--color-text-new-watch-input: var(--color-text);--color-border-input: var(--color-grey-500);--color-shadow-input: var(--color-grey-400);--color-background-input: var(--color-white);--color-text-input: var(--color-text);--color-text-input-description: var(--color-grey-500);--color-text-input-placeholder: var(--color-grey-600);--color-background-table-thead: var(--color-grey-800);--color-border-table-cell: var(--color-grey-700);--color-text-menu-heading: var(--color-grey-350);--color-text-menu-link: var(--color-grey-500);--color-background-menu-link-hover: var(--color-grey-850);--color-text-menu-link-hover: var(--color-grey-300);--color-shadow-jump: var(--color-grey-500);--color-icon-github: var(--color-black);--color-icon-github-hover: var(--color-grey-300);--color-watch-table-error: var(--color-dark-red);--color-watch-table-row-text: var(--color-grey-100);--highlight-trigger-text-bg-color: #1b98f8;--highlight-ignored-text-bg-color: var(--color-grey-700);--highlight-blocked-text-bg-color: rgb(202, 60, 60)}html[data-darkmode=true]{--color-link: #59bdfb;--color-text: var(--color-white);--color-background-gradient-first: #3f90a5;--color-background-gradient-second: #1e316c;--color-background-gradient-third: #4d2c64;--color-background-new-watch-input: var(--color-grey-100);--color-background-new-watch-input-transparent: var(--color-grey-100);--color-text-new-watch-input: var(--color-text);--color-background-table-thead: var(--color-grey-200);--color-table-background: var(--color-grey-300);--color-table-stripe: var(--color-grey-325);--color-background: var(--color-grey-300);--color-text-menu-heading: var(--color-grey-850);--color-text-menu-link: var(--color-grey-800);--color-border-table-cell: var(--color-grey-400);--color-text-tab-active: var(--color-text);--color-border-input: var(--color-grey-400);--color-shadow-input: var(--color-grey-50);--color-background-input: var(--color-grey-350);--color-text-input-description: var(--color-grey-600);--color-text-input-placeholder: var(--color-grey-600);--color-text-watch-tag-list: rgba(250, 62, 146, 0.4);--color-background-code: var(--color-grey-200);--color-background-tab: rgba(0, 0, 0, 0.2);--color-background-tab-hover: rgba(0, 0, 0, 0.5);--color-background-snapshot-age: var(--color-grey-200);--color-shadow-jump: var(--color-grey-200);--color-icon-github: var(--color-white);--color-icon-github-hover: var(--color-grey-700);--color-watch-table-error: var(--color-light-red);--color-watch-table-row-text: var(--color-grey-800)}html[data-darkmode=true] .icon-spread{filter:hue-rotate(-10deg) brightness(1.5)}html[data-darkmode=true] .watch-table .title-col a[target=_blank]::after,html[data-darkmode=true] .watch-table .current-diff-url::after{filter:invert(0.5) hue-rotate(10deg) brightness(2)}html[data-darkmode=true] .watch-table .status-browsersteps{filter:invert(0.5) hue-rotate(10deg) brightness(1.5)}html[data-darkmode=true] .watch-table .watch-controls .state-off img{opacity:.3}html[data-darkmode=true] .watch-table .watch-controls .state-on img{opacity:1}html[data-darkmode=true] .watch-table .unviewed{color:#fff}html[data-darkmode=true] .watch-table .unviewed.error{color:var(--color-watch-table-error)}.arrow{border:solid #1b98f8;border-width:0 2px 2px 0;display:inline-block;padding:3px}.arrow.right{transform:rotate(-45deg);-webkit-transform:rotate(-45deg)}.arrow.left{transform:rotate(135deg);-webkit-transform:rotate(135deg)}.arrow.up,.arrow.asc{transform:rotate(-135deg);-webkit-transform:rotate(-135deg)}.arrow.down,.arrow.desc{transform:rotate(45deg);-webkit-transform:rotate(45deg)}#browser_steps th{display:none}#browser_steps li{list-style:decimal;padding:5px}#browser_steps li.browser-step-with-error{background-color:#ffd6d6;border-radius:4px}#browser_steps li:not(:first-child):hover{opacity:1}#browser_steps li .control{padding-left:5px;padding-right:5px}#browser_steps li .control a{font-size:70%}#browser_steps li.empty{padding:0px;opacity:.35}#browser_steps li.empty .control{display:none}#browser_steps li:hover{background:#eee}#browser_steps li>label{display:none}@media only screen and (min-width: 760px){#browser-steps .flex-wrapper{display:flex;flex-flow:row;height:70vh;font-size:80%}#browser-steps .flex-wrapper #browser-steps-ui{flex-grow:1;flex-shrink:1;flex-basis:0;background-color:#eee;border-radius:5px}#browser-steps-fieldlist{flex-grow:0;flex-shrink:0;flex-basis:auto;max-width:400px;padding-left:1rem;overflow-y:scroll}#browsersteps-selector-wrapper{height:100% !important}}#browsersteps-selector-wrapper{width:100%;overflow-y:scroll;position:relative;height:80vh}#browsersteps-selector-wrapper>img{position:absolute;max-width:100%}#browsersteps-selector-wrapper>canvas{position:relative;max-width:100%}#browsersteps-selector-wrapper>canvas:hover{cursor:pointer}#browsersteps-selector-wrapper .loader{position:absolute;left:50%;top:50%;transform:translate(-50%, -50%);z-index:100;max-width:350px;text-align:center}#browsersteps-selector-wrapper .spinner,#browsersteps-selector-wrapper .spinner:after{width:80px;height:80px;font-size:3px}#browsersteps-selector-wrapper #browsersteps-click-start{color:var(--color-grey-400)}#browsersteps-selector-wrapper #browsersteps-click-start:hover{cursor:pointer}ul#requests-extra_proxies{list-style:none}ul#requests-extra_proxies li>label{display:none}ul#requests-extra_proxies table tr{display:table-row}ul#requests-extra_proxies table tr input[type=text]{width:100%}@media only screen and (min-width: 1024px){ul#requests-extra_proxies table tr{display:inline}}#request label[for=proxy]{display:inline-block}body.proxy-check-active #request .proxy-check-details{font-size:80%;color:#555;display:block;padding-left:2em;max-width:500px}body.proxy-check-active #request .proxy-timing{font-size:80%;padding-left:1rem;color:var(--color-link)}#recommended-proxy{display:grid;gap:2rem;padding-bottom:1em}@media(min-width: 991px){#recommended-proxy{grid-template-columns:repeat(2, 1fr)}}#recommended-proxy>div{border:1px #aaa solid;border-radius:4px;padding:1em}#extra-proxies-setting{border:1px solid var(--color-grey-800);border-radius:4px;margin:1em;padding:1em}ul#requests-extra_browsers{list-style:none}ul#requests-extra_browsers li>label{display:none}ul#requests-extra_browsers table tr{display:table-row}ul#requests-extra_browsers table tr input[type=text]{width:100%}@media only screen and (min-width: 1280px){ul#requests-extra_browsers table tr{display:inline}ul#requests-extra_browsers table tr input[type=text]{width:100%}}#extra-browsers-setting{border:1px solid var(--color-grey-800);border-radius:4px;margin:1em;padding:1em}.pagination-page-info{color:#fff;font-size:.85rem;text-transform:capitalize}.pagination.menu>*{display:inline-block}.pagination.menu li{display:inline-block}.pagination.menu a{padding:.65rem;margin:3px;border:none;background:#444;border-radius:2px;color:var(--color-text-button)}.pagination.menu a.disabled{display:none}.pagination.menu a.active{font-weight:bold;background:#888}.pagination.menu a:hover{background:#999}.spinner,.spinner:after{border-radius:50%;width:10px;height:10px}.spinner{margin:0px auto;font-size:3px;vertical-align:middle;display:inline-block;text-indent:-9999em;border-top:1.1em solid rgba(38,104,237,.2);border-right:1.1em solid rgba(38,104,237,.2);border-bottom:1.1em solid rgba(38,104,237,.2);border-left:1.1em solid #2668ed;-webkit-transform:translateZ(0);-ms-transform:translateZ(0);transform:translateZ(0);-webkit-animation:load8 1.1s infinite linear;animation:load8 1.1s infinite linear}@-webkit-keyframes load8{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes load8{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}.toggle-light-mode .icon-dark{display:none}html[data-darkmode=true] .toggle-light-mode .icon-light{display:none}html[data-darkmode=true] .toggle-light-mode .icon-dark{display:block}.pure-menu-link{padding:.5rem 1em;line-height:1.2rem}.pure-menu-item svg{height:1.2rem}.pure-menu-item *{vertical-align:middle}.pure-menu-item .github-link{height:1.8rem;display:block}.pure-menu-item .github-link svg{height:100%}.pure-menu-item .bi-heart:hover{cursor:pointer}.pure-menu-item.active .pure-menu-link{background-color:var(--color-background-menu-link-hover);color:var(--color-text-menu-link-hover)}#cdio-logo{padding-left:.5em}#inline-menu-extras-group>*{display:inline-block}#overlay{opacity:.95;position:fixed;width:350px;max-width:100%;height:100%;top:0;right:-350px;background-color:var(--color-table-stripe);z-index:2;transform:translateX(0);transition:transform .5s ease}#overlay.visible{transform:translateX(-100%)}#overlay .content{font-size:.875rem;padding:1rem;margin-top:5rem;max-width:400px;color:var(--color-watch-table-row-text)}#heartpath{transition:all ease .3s !important}#heartpath:hover{fill:red !important;transition:all ease .3s !important}.minitabs-wrapper{width:100%}.minitabs-wrapper>div[id]{padding:20px;border:1px solid #ccc;border-top:none}.minitabs-wrapper .minitabs-content{width:100%;display:flex}.minitabs-wrapper .minitabs-content>div{flex:1 1 auto;min-width:0;overflow:scroll}.minitabs-wrapper .minitabs{display:flex;border-bottom:1px solid #ccc}.minitabs-wrapper .minitab{flex:1;text-align:center;padding:12px 0;text-decoration:none;color:#333;background-color:#f1f1f1;border:1px solid #ccc;border-bottom:none;cursor:pointer;transition:background-color .3s}.minitabs-wrapper .minitab:hover{background-color:#ddd}.minitabs-wrapper .minitab.active{background-color:#fff;font-weight:bold}@media(min-width: 800px){body.preview-text-enabled #filters-and-triggers>div{display:flex;gap:20px;position:relative}}body.preview-text-enabled #edit-text-filter,body.preview-text-enabled #text-preview{flex:1;align-self:flex-start}body.preview-text-enabled #edit-text-filter #pro-tips{display:none}body.preview-text-enabled #text-preview{position:sticky;top:20px;padding-top:1rem;padding-bottom:1rem;display:block !important}body.preview-text-enabled #activate-text-preview{background-color:var(--color-grey-500)}body.preview-text-enabled .monospace-preview{background:var(--color-background-input);border:1px solid var(--color-grey-600);padding:1rem;color:var(--color-text-input);font-family:"Courier New",Courier,monospace;font-size:70%;word-break:break-word;white-space:pre-wrap}#activate-text-preview{right:0;position:absolute;z-index:3;box-shadow:1px 1px 4px var(--color-shadow-jump)}.watch-table{width:100%;font-size:80%}.watch-table tr{color:var(--color-watch-table-row-text)}.watch-table tr.unviewed{font-weight:bold}.watch-table td{white-space:nowrap}.watch-table td.title-col{word-break:break-all;white-space:normal}.watch-table td a.external::after{content:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAQElEQVR42qXKwQkAIAxDUUdxtO6/RBQkQZvSi8I/pL4BoGw/XPkh4XigPmsUgh0626AjRsgxHTkUThsG2T/sIlzdTsp52kSS1wAAAABJRU5ErkJggg==);margin:0 3px 0 5px}.watch-table th{white-space:nowrap}.watch-table th a{font-weight:normal}.watch-table th a.active{font-weight:bolder}.watch-table th a.inactive .arrow{display:none}.watch-table tr.checking-now td:first-child{position:relative}.watch-table tr.checking-now td:first-child::before{content:"";position:absolute;top:0;bottom:0;left:0;width:3px;background-color:#293eff}.watch-table tr.checking-now td.last-checked .spinner-wrapper{display:inline-block !important}.watch-table tr.checking-now td.last-checked .innertext{display:none !important}.watch-table tr.queued a.recheck{display:none !important}.watch-table tr.queued a.already-in-queue-button{display:inline-block !important}.watch-table tr.paused a.pause-toggle.state-on{display:inline !important}.watch-table tr.paused a.pause-toggle.state-off{display:none !important}.watch-table tr.notification_muted a.mute-toggle.state-on{display:inline !important}.watch-table tr.notification_muted a.mute-toggle.state-off{display:none !important}.watch-table tr.has-error{color:var(--color-watch-table-error)}.watch-table tr.has-error .error-text{display:block !important}.watch-table tr.single-history a.preview-link{display:inline-block !important}.watch-table tr.multiple-history a.history-link{display:inline-block !important}#watch-table-wrapper #post-list-buttons{text-align:right;padding:0px;margin:0px}#watch-table-wrapper #post-list-buttons li{display:inline-block}#watch-table-wrapper #post-list-buttons a{border-top-left-radius:initial;border-top-right-radius:initial;border-bottom-left-radius:5px;border-bottom-right-radius:5px}#watch-table-wrapper.has-error #post-list-buttons #post-list-with-errors{display:inline-block !important}#watch-table-wrapper.has-unread-changes #post-list-buttons #post-list-unread,#watch-table-wrapper.has-unread-changes #post-list-buttons #post-list-mark-views,#watch-table-wrapper.has-unread-changes #post-list-buttons #post-list-unread{display:inline-block !important}@media(max-width: 767px){.watch-table thead{display:block}.watch-table thead tr th{display:inline-block}}@media(max-width: 767px)and (max-width: 768px){.watch-table thead tr th .hide-on-mobile{display:none}}@media(max-width: 767px){.watch-table thead .empty-cell{display:none}.watch-table .last-checked{margin-left:calc(20px + .5rem)}.watch-table .last-checked>span{vertical-align:middle}.watch-table .last-changed{margin-left:calc(20px + .5rem)}.watch-table .last-checked::before{color:var(--color-text);content:"Last Checked "}.watch-table .last-changed::before{color:var(--color-text);content:"Last Changed "}.watch-table td.inline{display:inline-block}.watch-table .pure-table td,.watch-table .pure-table th{border:none}.watch-table td{border:none;border-bottom:1px solid var(--color-border-watch-table-cell);vertical-align:middle}.watch-table td:before{top:6px;left:6px;width:45%;padding-right:10px;white-space:nowrap}.watch-table.pure-table-striped tr{background-color:var(--color-table-background)}.watch-table.pure-table-striped tr:nth-child(2n-1){background-color:var(--color-table-stripe)}.watch-table.pure-table-striped tr:nth-child(2n-1) td{background-color:inherit}}@media(max-width: 767px){.watch-table tbody tr{padding-bottom:10px;padding-top:10px;display:grid;grid-template-columns:20px 1fr 100px;grid-template-rows:auto auto auto auto;gap:.5rem}.watch-table tbody tr .counter-i{display:none}.watch-table tbody tr td.checkbox-uuid{display:grid;place-items:center}.watch-table tbody tr>td{border-bottom:none}.watch-table tbody tr>td.title-col{grid-column:1/-1;grid-row:1}.watch-table tbody tr>td.title-col .watch-title{font-size:.92rem}.watch-table tbody tr>td.title-col .link-spread{display:none}.watch-table tbody tr>td.last-checked{grid-column:1/-1;grid-row:2}.watch-table tbody tr>td.last-changed{grid-column:1/-1;grid-row:3}.watch-table tbody tr>td.checkbox-uuid{grid-column:1;grid-row:4}.watch-table tbody tr>td.buttons{grid-column:2;grid-row:4;display:flex;align-items:center;justify-content:flex-start}.watch-table tbody tr>td.watch-controls{grid-column:3;grid-row:4;display:grid;place-items:center}.watch-table tbody tr>td.watch-controls a img{padding:10px}.pure-table td{padding:3px !important}}ul#conditions_match_logic{list-style:none}ul#conditions_match_logic input,ul#conditions_match_logic label,ul#conditions_match_logic li{display:inline-block}ul#conditions_match_logic li{padding-right:1em}.fieldlist_formfields{width:100%;background-color:var(--color-background, #fff);border-radius:4px;border:1px solid var(--color-border-table-cell, #cbcbcb)}.fieldlist_formfields .fieldlist-header{display:flex;background-color:var(--color-background-table-thead, #e0e0e0);font-weight:bold;border-bottom:1px solid var(--color-border-table-cell, #cbcbcb)}.fieldlist_formfields .fieldlist-header-cell{flex:1;padding:.5em 1em;text-align:left}.fieldlist_formfields .fieldlist-header-cell:last-child{flex:0 0 120px}.fieldlist_formfields .fieldlist-body{display:flex;flex-direction:column}.fieldlist_formfields .fieldlist-row{display:flex;border-bottom:1px solid var(--color-border-table-cell, #cbcbcb)}.fieldlist_formfields .fieldlist-row:last-child{border-bottom:none}.fieldlist_formfields .fieldlist-row:nth-child(2n-1){background-color:var(--color-table-stripe, #f2f2f2)}.fieldlist_formfields .fieldlist-row.error-row{background-color:var(--color-error-input, #ffdddd)}.fieldlist_formfields .fieldlist-cell{flex:1;padding:.5em 1em;display:flex;flex-direction:column;justify-content:center}.fieldlist_formfields .fieldlist-cell input,.fieldlist_formfields .fieldlist-cell select{width:100%}.fieldlist_formfields .fieldlist-cell.fieldlist-actions{flex:0 0 120px;display:flex;flex-direction:row;align-items:center;gap:4px}.fieldlist_formfields ul.errors{margin-top:.5em;margin-bottom:0;padding:.5em;background-color:var(--color-error-background-snapshot-age, #ffdddd);border-radius:4px;list-style-position:inside}@media only screen and (max-width: 760px){.fieldlist_formfields .fieldlist-header,.fieldlist_formfields .fieldlist-row{flex-direction:column}.fieldlist_formfields .fieldlist-header-cell{display:none}.fieldlist_formfields .fieldlist-row{padding:.5em 0;border-bottom:2px solid var(--color-border-table-cell, #cbcbcb)}.fieldlist_formfields .fieldlist-cell{padding:.25em .5em}.fieldlist_formfields .fieldlist-cell.fieldlist-actions{flex:1;justify-content:flex-start;padding-top:.5em}.fieldlist_formfields .fieldlist-cell:not(:last-child){margin-bottom:.5em}.fieldlist_formfields .fieldlist-cell::before{content:attr(data-label);font-weight:bold;margin-bottom:.25em}}.fieldlist_formfields .addRuleRow,.fieldlist_formfields .removeRuleRow,.fieldlist_formfields .verifyRuleRow{cursor:pointer;border:none;padding:4px 8px;border-radius:3px;font-weight:bold;background-color:#aaa;color:var(--color-foreground-text, #fff)}.fieldlist_formfields .addRuleRow:hover,.fieldlist_formfields .removeRuleRow:hover,.fieldlist_formfields .verifyRuleRow:hover{background-color:#999}.watch-table.favicon-not-enabled tr .favicon{display:none}.watch-table tr td.inline.title-col .flex-wrapper{display:flex;align-items:center;gap:4px}.watch-table td,.watch-table th{vertical-align:middle}.watch-table tr.has-favicon.unviewed img.favicon{opacity:1 !important}.watch-table .status-icons{white-space:nowrap;display:flex;align-items:center;gap:4px}.watch-table .status-icons>*{vertical-align:middle}.title-col{padding:10px}.title-wrapper{display:flex;align-items:center;gap:10px}.title-col-inner{display:inline-block;vertical-align:middle}.watch-table img.favicon{vertical-align:middle;max-width:25px;max-height:25px;height:25px;padding-right:4px}body.checking-now #checking-now-fixed-tab{display:block !important}#checking-now-fixed-tab{background:#ccc;border-radius:5px;bottom:0;color:var(--color-text);display:none;font-size:.8rem;left:0;padding:5px;position:fixed}#selector-wrapper{height:100%;text-align:center;max-height:70vh;overflow-y:scroll;position:relative}#selector-wrapper>img{position:absolute;z-index:4;max-width:100%}#selector-wrapper>canvas{position:relative;z-index:5;max-width:100%}#selector-wrapper>canvas:hover{cursor:pointer}#selector-current-xpath{font-size:80%}.ternary-radio-group{display:flex;gap:0;border:1px solid var(--color-grey-750);border-radius:4px;overflow:hidden;width:fit-content;background:var(--color-background)}.ternary-radio-group .ternary-radio-option{position:relative;cursor:pointer;margin:0;display:flex;align-items:center}.ternary-radio-group .ternary-radio-option input[type=radio]{position:absolute;opacity:0;width:0;height:0}.ternary-radio-group .ternary-radio-option .ternary-radio-label{padding:8px 16px;background:var(--color-grey-900);border:none;border-right:1px solid var(--color-grey-750);font-size:13px;font-weight:500;color:var(--color-text);transition:all .2s ease;cursor:pointer;display:block;text-align:center}.ternary-radio-group .ternary-radio-option:last-child .ternary-radio-label{border-right:none}.ternary-radio-group .ternary-radio-option input:checked+.ternary-radio-label{background:var(--color-link);color:var(--color-text-button);font-weight:600}.ternary-radio-group .ternary-radio-option input:checked+.ternary-radio-label.ternary-default{background:var(--color-grey-600);color:var(--color-text-button)}.ternary-radio-group .ternary-radio-option input:checked+.ternary-radio-label:hover{background:#1a7bc4}.ternary-radio-group .ternary-radio-option input:checked+.ternary-radio-label:hover.ternary-default{background:var(--color-grey-500)}.ternary-radio-group .ternary-radio-option:hover .ternary-radio-label{background:var(--color-grey-800)}@media(max-width: 480px){.ternary-radio-group{width:100%}.ternary-radio-group .ternary-radio-label{flex:1;min-width:auto}}input[type=radio].pure-radio:checked+label,input[type=radio].pure-radio:checked{background:var(--color-link);color:var(--color-text-button)}html[data-darkmode=true] .ternary-radio-group .ternary-radio-option .ternary-radio-label{background:var(--color-grey-350)}html[data-darkmode=true] .ternary-radio-group .ternary-radio-option:hover .ternary-radio-label{background:var(--color-grey-400)}html[data-darkmode=true] .ternary-radio-group .ternary-radio-option input:checked+.ternary-radio-label{background:var(--color-link);color:var(--color-text-button)}html[data-darkmode=true] .ternary-radio-group .ternary-radio-option input:checked+.ternary-radio-label.ternary-default{background:var(--color-grey-600)}html[data-darkmode=true] .ternary-radio-group .ternary-radio-option input:checked+.ternary-radio-label:hover{background:#1a7bc4}html[data-darkmode=true] .ternary-radio-group .ternary-radio-option input:checked+.ternary-radio-label:hover.ternary-default{background:var(--color-grey-500)}body.processor-image_ssim_diff #edit-text-filter .text-filtering{display:none}body.processor-image_ssim_diff #conditions-tab{display:none}.modal-dialog{border:none;border-radius:10px;padding:0;background:var(--color-background);color:var(--color-text);box-shadow:0 5px 20px rgba(0,0,0,.3);max-width:500px;width:90%}.modal-dialog::backdrop{background:rgba(0,0,0,.6);backdrop-filter:blur(3px);animation:fadeIn .2s ease-out}.modal-dialog[open]{animation:slideIn .25s ease-out}.modal-dialog .modal-header{padding:1.5rem;border-bottom:1px solid var(--color-border-table-cell);display:flex;align-items:center;gap:1rem}.modal-dialog .modal-header .modal-icon{font-size:2rem;line-height:1;flex-shrink:0}.modal-dialog .modal-header .modal-icon.warning{color:var(--color-warning)}.modal-dialog .modal-header .modal-icon.danger{color:var(--color-background-button-error)}.modal-dialog .modal-header .modal-icon.info{color:var(--color-background-button-primary)}.modal-dialog .modal-header .modal-title{font-size:1.3rem;font-weight:bold;margin:0;color:var(--color-text)}.modal-dialog .modal-body{padding:1.5rem;line-height:1.6}.modal-dialog .modal-body p{margin:0 0 1rem 0}.modal-dialog .modal-body p:last-child{margin-bottom:0}.modal-dialog .modal-body strong{color:var(--color-text);font-weight:600}.modal-dialog .modal-footer{padding:1rem 1.5rem;border-top:1px solid var(--color-border-table-cell);display:flex;gap:.75rem;justify-content:flex-end;background:var(--color-grey-900)}.modal-dialog .modal-footer button{padding:.6rem 1.5rem;border:none;border-radius:4px;cursor:pointer;font-weight:500;transition:all .2s ease;font-size:.95rem}.modal-dialog .modal-footer button:hover{transform:translateY(-1px);box-shadow:0 2px 8px rgba(0,0,0,.15)}.modal-dialog .modal-footer button:active{transform:translateY(0)}.modal-dialog .modal-footer button.modal-btn-cancel{background:var(--color-background-button-cancel);color:var(--color-grey-200)}.modal-dialog .modal-footer button.modal-btn-cancel:hover{background:var(--color-grey-700)}.modal-dialog .modal-footer button.modal-btn-confirm{background:var(--color-background-button-primary);color:var(--color-white)}.modal-dialog .modal-footer button.modal-btn-confirm:hover{opacity:.9}.modal-dialog .modal-footer button.modal-btn-danger{background:var(--color-background-button-error);color:var(--color-white)}.modal-dialog .modal-footer button.modal-btn-danger:hover{background:var(--color-dark-red)}.modal-dialog .modal-footer button.modal-btn-warning{background:var(--color-background-button-warning);color:var(--color-white)}.modal-dialog .modal-footer button.modal-btn-warning:hover{opacity:.9}html[data-darkmode=true] .modal-dialog{box-shadow:0 5px 30px rgba(0,0,0,.7)}html[data-darkmode=true] .modal-dialog .modal-footer{background:var(--color-grey-200)}@keyframes fadeIn{from{opacity:0}to{opacity:1}}@keyframes slideIn{from{opacity:0;transform:translateY(-20px) scale(0.95)}to{opacity:1;transform:translateY(0) scale(1)}}@media only screen and (max-width: 760px){.modal-dialog{width:95%;max-width:none}.modal-dialog .modal-header{padding:1rem}.modal-dialog .modal-header .modal-title{font-size:1.1rem}.modal-dialog .modal-body{padding:1rem;font-size:.95rem}.modal-dialog .modal-footer{padding:.75rem 1rem;flex-wrap:wrap}.modal-dialog .modal-footer button{flex:1;min-width:120px}}#language-selector-flag{display:inline-block;width:1.2em;height:1.2em;vertical-align:middle;border-radius:50%;overflow:hidden;opacity:.6}#language-selector-flag:hover{opacity:1}.language-list{display:flex;flex-direction:column;gap:.5rem;padding:.5rem 0}.language-option{display:flex;align-items:center;gap:1rem;padding:.25rem;border-radius:4px;transition:background-color .2s ease;text-decoration:none;color:var(--color-text);border:1px solid rgba(0,0,0,0)}.language-option:hover{background-color:var(--color-background-menu-link-hover);border-color:var(--color-border-table-cell)}.language-option.active{background-color:var(--color-link);color:var(--color-text-button);font-weight:600}.language-option .flag{font-size:1.5rem;flex-shrink:0}.language-option .language-name{flex-grow:1;font-size:1rem}#language-modal .language-list .lang-option{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;margin-right:.5em;border-radius:50%;overflow:hidden}.content-wrapper{display:flex;gap:0;width:100%;max-width:100%;position:relative}@media only screen and (max-width: 900px){.content-wrapper{flex-direction:column}}.action-sidebar{position:sticky;top:100px;flex-shrink:0;width:80px;height:fit-content;background:rgba(0,0,0,0);padding:1.5rem 0;display:flex;flex-direction:column;gap:.5rem;align-items:center;z-index:0}@media only screen and (max-width: 900px){.action-sidebar{position:relative;top:0;width:100%;flex-direction:row;justify-content:space-around;padding:0;overflow-x:auto}}.action-sidebar-item{position:relative;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.35rem;padding:.75rem .5rem;min-width:64px;text-decoration:none;opacity:.8;transition:opacity .2s ease}.action-sidebar-item:hover{opacity:1}.action-sidebar-item.active{opacity:1}.action-sidebar-item.active .action-icon{stroke:#fff;stroke-width:2.5}.action-sidebar-item.active .action-label{color:#fff;font-weight:700}.action-icon{width:28px;height:28px;stroke:#fff;stroke-width:2;fill:none;stroke-linecap:round;stroke-linejoin:round;transition:stroke .2s ease}.action-label{font-size:.65rem;font-weight:500;text-align:center;line-height:1.1;letter-spacing:.02em;text-transform:uppercase;color:#fff;transition:color .2s ease;max-width:60px;word-wrap:break-word}.content-main{flex:0 1 auto;width:100%;min-width:0;padding:0;display:flex;flex-direction:column;align-items:center}.hamburger-menu{display:none;background:rgba(0,0,0,0);border:none;cursor:pointer;padding:.5rem;z-index:10001;position:relative}@media only screen and (max-width: 980px){.hamburger-menu{display:flex;flex-direction:column;justify-content:center;align-items:center}}.hamburger-icon{width:24px;height:20px;position:relative;display:flex;flex-direction:column;justify-content:space-between}.hamburger-icon span{display:block;height:3px;width:100%;background:var(--color-text);border-radius:2px;transition:all .3s cubic-bezier(0.68, -0.55, 0.265, 1.55);transform-origin:center}.hamburger-menu.active .hamburger-icon span:nth-child(1){transform:translateY(8.5px) rotate(45deg)}.hamburger-menu.active .hamburger-icon span:nth-child(2){opacity:0;transform:translateX(-10px)}.hamburger-menu.active .hamburger-icon span:nth-child(3){transform:translateY(-8.5px) rotate(-45deg)}.mobile-menu-overlay{display:none;position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,.5);z-index:9999;opacity:0;transition:opacity .3s ease}.mobile-menu-overlay.active{display:block;opacity:1}.mobile-menu-drawer{position:fixed;top:0;right:-280px;width:280px;height:100%;background:var(--color-background);opacity:1;box-shadow:-2px 0 8px rgba(0,0,0,.15);z-index:10000;transition:right .3s cubic-bezier(0.68, -0.55, 0.265, 1.55);overflow-y:auto;padding-top:60px}.mobile-menu-drawer.active{right:0}.mobile-menu-drawer .mobile-menu-items{list-style:none;padding:1rem 0;margin:0}.mobile-menu-drawer .mobile-menu-items li{border-bottom:1px solid var(--color-border-table-cell)}.mobile-menu-drawer .mobile-menu-items li>*{display:block;padding:1rem 1.5rem;color:var(--color-text);text-decoration:none;font-weight:500;transition:background .2s ease}.mobile-menu-drawer .mobile-menu-items li>*:hover{background:var(--color-background-menu-link-hover)}.logo-cdio{font-weight:bold;font-size:1.1rem}.logo-cdio .logo-cd{color:var(--color-grey-500)}.logo-cdio .logo-io{color:var(--color-text)}.menu-always-visible{display:flex;align-items:center;gap:.5rem;margin-left:auto}@media only screen and (max-width: 980px){#top-right-menu .menu-collapsible{display:none !important}.pure-menu-horizontal{overflow-x:visible !important}#nav-menu{overflow-x:visible !important}}@media only screen and (min-width: 1025px){.hamburger-menu,.mobile-menu-drawer,.mobile-menu-overlay{display:none !important}}html[data-darkmode=true] .mobile-menu-drawer{box-shadow:-2px 0 8px rgba(0,0,0,.4)}#search-modal .modal-body{padding:2rem 1.5rem}#search-modal .modal-body .pure-control-group{padding-bottom:0}#search-modal .modal-body .pure-control-group label{display:block;margin-bottom:.5rem;font-size:.9rem;font-weight:600;color:var(--color-text)}#search-modal .modal-body .pure-control-group #search-modal-input{width:100%;max-width:100%;box-sizing:border-box;padding:.6rem .8rem;font-size:1rem;border:1px solid var(--color-border-input);border-radius:4px;background-color:var(--color-background-input);color:var(--color-text-input);box-shadow:inset 0 1px 3px var(--color-shadow-input);transition:border-color .2s ease,box-shadow .2s ease}#search-modal .modal-body .pure-control-group #search-modal-input:focus{outline:none;border-color:var(--color-link);box-shadow:0 0 0 3px rgba(27,152,248,.1)}#search-modal .modal-body .pure-control-group #search-modal-input::placeholder{color:var(--color-text-input-placeholder);opacity:.7}html[data-darkmode=true] #search-modal #search-modal-input:focus{box-shadow:0 0 0 3px rgba(89,189,251,.15)}.action-sidebar-item{position:relative}.action-sidebar-item .notification-bubble{position:absolute;top:8px;left:8px;min-width:18px;height:18px;background:#f44;color:#fff;font-size:10px;font-weight:700;line-height:18px;text-align:center;border-radius:9px;padding:0 2px;box-shadow:0 2px 4px rgba(0,0,0,.3);pointer-events:none;transition:all .2s ease;display:none}.action-sidebar-item .notification-bubble.red-bubble{background:#f44}.action-sidebar-item .notification-bubble.blue-bubble{background:#4a9eff;color:#fff}.action-sidebar-item .notification-bubble.visible{display:block}.action-sidebar-item .notification-bubble.pulse{animation:bubblePulse .4s ease-out}.action-sidebar-item .notification-bubble.large-number{font-size:8px;min-width:20px;height:20px;line-height:20px;border-radius:10px}@keyframes bubblePulse{0%{transform:scale(1)}50%{transform:scale(1.3)}100%{transform:scale(1)}}html[data-darkmode=true] .notification-bubble{box-shadow:0 2px 6px rgba(0,0,0,.6)}.toast-container{position:fixed;display:flex;flex-direction:column;gap:.75rem;pointer-events:none;z-index:10000}.toast-container.toast-top-right{top:20px;right:20px}.toast-container.toast-top-center{top:100px;left:50%;transform:translateX(-50%)}.toast-container.toast-top-left{top:20px;left:20px}.toast-container.toast-bottom-right{bottom:20px;right:20px}.toast-container.toast-bottom-center{bottom:20px;left:50%;transform:translateX(-50%)}.toast-container.toast-bottom-left{bottom:20px;left:20px}.toast{position:relative;display:flex;align-items:center;gap:.75rem;min-width:300px;max-width:500px;padding:1rem 1.25rem;background:var(--color-background);border-radius:8px;box-shadow:0 4px 12px rgba(0,0,0,.15),0 0 0 1px rgba(0,0,0,.05);pointer-events:auto;overflow:hidden;opacity:0;transform:translateY(-50px);transition:all .3s cubic-bezier(0.68, -0.55, 0.265, 1.55);font-family:inherit}.toast.toast-show{opacity:1;transform:translateY(0)}.toast.toast-hide{opacity:0;transform:translateY(-50px) scale(0.95)}.toast.toast-success{border-left:4px solid #10b981}.toast.toast-success .toast-icon{color:#10b981}.toast.toast-error{border-left:4px solid #ef4444}.toast.toast-error .toast-icon{color:#ef4444}.toast.toast-warning{border-left:4px solid #f59e0b}.toast.toast-warning .toast-icon{color:#f59e0b}.toast.toast-info{border-left:4px solid #3b82f6}.toast.toast-info .toast-icon{color:#3b82f6}.toast.toast-default{border-left:4px solid var(--color-grey-500)}.toast-icon{flex-shrink:0;width:24px;height:24px}.toast-icon svg{width:100%;height:100%}.toast-message{flex:1;font-size:.875rem;line-height:1.5;color:var(--color-text);word-break:break-word;font-family:inherit}.toast-close{flex-shrink:0;width:24px;height:24px;display:flex;align-items:center;justify-content:center;background:rgba(0,0,0,0);border:none;border-radius:4px;color:var(--color-grey-500);font-size:1.5rem;line-height:1;cursor:pointer;transition:all .2s ease;padding:0;margin-left:.25rem}.toast-close:hover{background:var(--color-grey-800);color:var(--color-text)}.toast-close:active{transform:scale(0.95)}.toast-progress{position:absolute;bottom:0;left:0;right:0;height:3px;background:currentColor;opacity:.3;transform-origin:left;transition:transform linear}html[data-darkmode=true] .toast{background:var(--color-grey-300);box-shadow:0 4px 12px rgba(0,0,0,.4),0 0 0 1px hsla(0,0%,100%,.05)}html[data-darkmode=true] .toast-close:hover{background:var(--color-grey-400)}@media only screen and (max-width: 768px){.toast-container{left:10px !important;right:10px !important;top:10px !important;transform:none !important;align-items:stretch}.toast-container.toast-bottom-right,.toast-container.toast-bottom-center,.toast-container.toast-bottom-left{top:auto !important;bottom:10px !important}.toast{min-width:auto;max-width:none;width:100%;transform:translateY(-100px)}.toast.toast-show{transform:translateY(0)}.toast.toast-hide{transform:translateY(-100px) scale(0.95)}}@media(prefers-reduced-motion: reduce){.toast{transition:opacity .2s ease;transform:none !important}.toast.toast-show{opacity:1}.toast.toast-hide{opacity:0}}.login-form{min-height:52vh;display:flex;align-items:center;justify-content:center;padding:2rem 1rem}.login-form .inner{background:var(--color-background);border-radius:16px;box-shadow:0 10px 40px rgba(0,0,0,.08),0 2px 8px rgba(0,0,0,.04);padding:3rem 2.5rem;width:100%;max-width:420px;position:relative;overflow:hidden;transition:transform .3s ease,box-shadow .3s ease}.login-form .inner:hover{box-shadow:0 15px 50px rgba(0,0,0,.12),0 5px 15px rgba(0,0,0,.06)}.login-form form{margin:0}.login-form fieldset{border:none;padding:0;margin:0}.login-form .pure-control-group{margin-bottom:1.75rem}.login-form .pure-control-group:last-of-type{margin-bottom:0;margin-top:2rem}.login-form label{display:block;margin-bottom:.5rem;font-weight:600;font-size:.9rem;color:var(--color-text);letter-spacing:.01em}.login-form input[type=password]{width:100%;padding:.875rem 1rem;border:2px solid var(--color-grey-800);border-radius:8px;font-size:1rem;background:var(--color-background-input);color:var(--color-text-input);transition:all .2s ease;box-sizing:border-box}.login-form input[type=password]:focus{outline:none;border-color:var(--color-link);box-shadow:0 0 0 3px rgba(27,152,248,.1);transform:translateY(-1px)}.login-form input[type=password]::placeholder{color:var(--color-text-input-placeholder)}.login-form button[type=submit]{width:100%;padding:.875rem 1.5rem;font-size:1rem;font-weight:600;border-radius:8px;border:none;background:var(--color-background-button-primary);color:var(--color-text-button);cursor:pointer;transition:all .2s ease;box-shadow:0 2px 8px rgba(27,152,248,.2)}.login-form button[type=submit]:hover{box-shadow:0 4px 12px rgba(27,152,248,.3);background:#06c}.login-form button[type=submit]:active{transform:translateY(0);box-shadow:0 2px 4px rgba(27,152,248,.2)}.content-main>ul.messages{position:fixed;top:120px;left:50%;transform:translateX(-50%);list-style:none;padding:0;margin:0;z-index:1000;min-width:300px;max-width:500px}.content-main>ul.messages li{padding:1rem 1.25rem;border-radius:8px;font-size:.95rem;line-height:1.5;font-weight:500;box-shadow:0 4px 12px rgba(0,0,0,.15);animation:slideDown .3s ease-out;border:2px solid rgba(0,0,0,0)}.content-main>ul.messages li.error{background:#fee;border:2px solid #ef4444;color:#991b1b;font-weight:600}.content-main>ul.messages li.success{background:#f0fdf4;border:2px solid #10b981;color:#166534}.content-main>ul.messages li.info,.content-main>ul.messages li.message{background:#eff6ff;border:2px solid #3b82f6;color:#1e40af}@keyframes slideDown{from{opacity:0;transform:translateY(-20px)}to{opacity:1;transform:translateY(0)}}html[data-darkmode=true] .login-form .inner{box-shadow:0 10px 40px rgba(0,0,0,.4),0 2px 8px rgba(0,0,0,.2)}html[data-darkmode=true] .login-form .inner:hover{box-shadow:0 15px 50px rgba(0,0,0,.5),0 5px 15px rgba(0,0,0,.3)}html[data-darkmode=true] .login-form input[type=password]{border-color:var(--color-grey-400)}html[data-darkmode=true] .login-form input[type=password]:focus{border-color:var(--color-link)}html[data-darkmode=true] .content-main>ul.messages li{box-shadow:0 4px 12px rgba(0,0,0,.4)}html[data-darkmode=true] .content-main>ul.messages li.error{background:#4a1d1d;border-color:#ef4444;color:#fca5a5}html[data-darkmode=true] .content-main>ul.messages li.success{background:#1a3a2a;border-color:#10b981;color:#86efac}html[data-darkmode=true] .content-main>ul.messages li.info,html[data-darkmode=true] .content-main>ul.messages li.message{background:#1e3a5f;border-color:#3b82f6;color:#93c5fd}@media only screen and (max-width: 768px){.login-form{min-height:auto;padding:1rem .5rem;padding-top:5rem}.login-form .inner{padding:2rem 1.5rem;border-radius:12px}.content-main>ul.messages{top:70px;left:10px;right:10px;transform:none;min-width:auto}}body.wrapped-tabs .tabs ul{grid-template-columns:repeat(auto-fill, minmax(var(--tab-width, 180px), 1fr));grid-auto-flow:row;grid-auto-columns:unset;gap:0;column-gap:5px}body.wrapped-tabs .tabs ul li{border-radius:0}.tabs ul{margin:0px;padding:0px;display:grid;grid-auto-flow:column;grid-auto-columns:max-content;gap:5px;list-style:none}.tabs ul li{white-space:nowrap;color:var(--color-text-tab);border-top-left-radius:5px;border-top-right-radius:5px;background-color:var(--color-background-tab)}.tabs ul li:not(.active):hover{background-color:var(--color-background-tab-hover)}.tabs ul li.active,.tabs ul li :target{background-color:var(--color-background)}.tabs ul li.active a,.tabs ul li :target a{color:var(--color-text-tab-active);font-weight:bold}.tabs ul li a{display:block;padding:.7em;color:var(--color-text-tab)}body{color:var(--color-text);background:var(--color-background-page);font-family:Helvetica Neue,Helvetica,Lucida Grande,Arial,Ubuntu,Cantarell,Fira Sans,sans-serif}.visually-hidden{clip:rect(0 0 0 0);clip-path:inset(50%);height:1px;overflow:hidden;position:absolute;white-space:nowrap;width:1px}.status-icon{display:inline-block;height:1rem;vertical-align:middle}.pure-table-even{background:var(--color-background)}a{text-decoration:none;color:var(--color-link)}a.github-link{color:var(--color-icon-github);margin:0 1rem 0 .5rem}a.github-link svg{fill:currentColor}a.github-link:hover{color:var(--color-icon-github-hover)}#search-result-info{color:#fff}button.toggle-button{vertical-align:middle;background:rgba(0,0,0,0);border:none;cursor:pointer;color:var(--color-icon-github)}button.toggle-button:hover{color:var(--color-icon-github-hover)}button.toggle-button svg{fill:currentColor}button.toggle-button .icon-light{display:block}.pure-menu-horizontal{background:var(--color-background);padding:5px;display:flex;justify-content:space-between;align-items:center}#pure-menu-horizontal-spinner{height:3px;background:linear-gradient(-75deg, #ff6000, #ff8f00, #ffdd00, #ed0000);background-size:400% 400%;width:100%;animation:gradient 200s ease infinite}body.spinner-active #pure-menu-horizontal-spinner{animation:gradient 1s ease infinite}@keyframes gradient{0%{background-position:0% 50%}50%{background-position:100% 50%}100%{background-position:0% 50%}}.pure-menu-heading{color:var(--color-text-menu-heading)}.pure-menu-link{color:var(--color-text-menu-link)}.pure-menu-link:hover{background-color:var(--color-background-menu-link-hover);color:var(--color-text-menu-link-hover)}.tab-pane-inner{scroll-margin-top:200px}section.content{padding-bottom:1em;flex-direction:column;display:flex;align-items:center;justify-content:center}@media only screen and (max-width: 980px){section.content{padding-top:80px}}@media only screen and (min-width: 980px){section.content{padding-top:100px}}code{background:var(--color-background-code);color:var(--color-text)}.inline-tag,.restock-label,.tracking-ldjson-price-data,.watch-tag-list,.processor-badge{white-space:nowrap;border-radius:5px;padding:2px 5px;margin-right:4px;line-height:1.2rem}.processor-badge{font-weight:900}.watch-tag-list{color:var(--color-white);background:var(--color-text-watch-tag-list)}@media(min-width: 768px){.box{margin:0 1em !important}}.box{max-width:100%;margin:0 .3em;flex-direction:column;display:flex;justify-content:center}body:after{content:"";background:linear-gradient(130deg, var(--color-background-gradient-first), var(--color-background-gradient-second) 41.07%, var(--color-background-gradient-third) 84.05%)}body:after,body:before{display:block;height:650px;position:absolute;top:0;left:0;width:100%;z-index:-1}body::after{opacity:.91}body::before{content:""}body:after,body:before{-webkit-clip-path:polygon(100% 0, 0 0, 0 77.5%, 1% 77.4%, 2% 77.1%, 3% 76.6%, 4% 75.9%, 5% 75.05%, 6% 74.05%, 7% 72.95%, 8% 71.75%, 9% 70.55%, 10% 69.3%, 11% 68.05%, 12% 66.9%, 13% 65.8%, 14% 64.8%, 15% 64%, 16% 63.35%, 17% 62.85%, 18% 62.6%, 19% 62.5%, 20% 62.65%, 21% 63%, 22% 63.5%, 23% 64.2%, 24% 65.1%, 25% 66.1%, 26% 67.2%, 27% 68.4%, 28% 69.65%, 29% 70.9%, 30% 72.15%, 31% 73.3%, 32% 74.35%, 33% 75.3%, 34% 76.1%, 35% 76.75%, 36% 77.2%, 37% 77.45%, 38% 77.5%, 39% 77.3%, 40% 76.95%, 41% 76.4%, 42% 75.65%, 43% 74.75%, 44% 73.75%, 45% 72.6%, 46% 71.4%, 47% 70.15%, 48% 68.9%, 49% 67.7%, 50% 66.55%, 51% 65.5%, 52% 64.55%, 53% 63.75%, 54% 63.15%, 55% 62.75%, 56% 62.55%, 57% 62.5%, 58% 62.7%, 59% 63.1%, 60% 63.7%, 61% 64.45%, 62% 65.4%, 63% 66.45%, 64% 67.6%, 65% 68.8%, 66% 70.05%, 67% 71.3%, 68% 72.5%, 69% 73.6%, 70% 74.65%, 71% 75.55%, 72% 76.35%, 73% 76.9%, 74% 77.3%, 75% 77.5%, 76% 77.45%, 77% 77.25%, 78% 76.8%, 79% 76.2%, 80% 75.4%, 81% 74.45%, 82% 73.4%, 83% 72.25%, 84% 71.05%, 85% 69.8%, 86% 68.55%, 87% 67.35%, 88% 66.2%, 89% 65.2%, 90% 64.3%, 91% 63.55%, 92% 63%, 93% 62.65%, 94% 62.5%, 95% 62.55%, 96% 62.8%, 97% 63.3%, 98% 63.9%, 99% 64.75%, 100% 65.7%);clip-path:polygon(100% 0, 0 0, 0 77.5%, 1% 77.4%, 2% 77.1%, 3% 76.6%, 4% 75.9%, 5% 75.05%, 6% 74.05%, 7% 72.95%, 8% 71.75%, 9% 70.55%, 10% 69.3%, 11% 68.05%, 12% 66.9%, 13% 65.8%, 14% 64.8%, 15% 64%, 16% 63.35%, 17% 62.85%, 18% 62.6%, 19% 62.5%, 20% 62.65%, 21% 63%, 22% 63.5%, 23% 64.2%, 24% 65.1%, 25% 66.1%, 26% 67.2%, 27% 68.4%, 28% 69.65%, 29% 70.9%, 30% 72.15%, 31% 73.3%, 32% 74.35%, 33% 75.3%, 34% 76.1%, 35% 76.75%, 36% 77.2%, 37% 77.45%, 38% 77.5%, 39% 77.3%, 40% 76.95%, 41% 76.4%, 42% 75.65%, 43% 74.75%, 44% 73.75%, 45% 72.6%, 46% 71.4%, 47% 70.15%, 48% 68.9%, 49% 67.7%, 50% 66.55%, 51% 65.5%, 52% 64.55%, 53% 63.75%, 54% 63.15%, 55% 62.75%, 56% 62.55%, 57% 62.5%, 58% 62.7%, 59% 63.1%, 60% 63.7%, 61% 64.45%, 62% 65.4%, 63% 66.45%, 64% 67.6%, 65% 68.8%, 66% 70.05%, 67% 71.3%, 68% 72.5%, 69% 73.6%, 70% 74.65%, 71% 75.55%, 72% 76.35%, 73% 76.9%, 74% 77.3%, 75% 77.5%, 76% 77.45%, 77% 77.25%, 78% 76.8%, 79% 76.2%, 80% 75.4%, 81% 74.45%, 82% 73.4%, 83% 72.25%, 84% 71.05%, 85% 69.8%, 86% 68.55%, 87% 67.35%, 88% 66.2%, 89% 65.2%, 90% 64.3%, 91% 63.55%, 92% 63%, 93% 62.65%, 94% 62.5%, 95% 62.55%, 96% 62.8%, 97% 63.3%, 98% 63.9%, 99% 64.75%, 100% 65.7%)}.button-small{font-size:85%}.button-xsmall{font-size:70%}.fetch-error{padding-top:1em;font-size:80%;max-width:400px;display:block}.pure-button-primary,a.pure-button-primary,.pure-button-selected,a.pure-button-selected{background-color:var(--color-background-button-primary)}.button-secondary{color:var(--color-text-button);border-radius:4px;text-shadow:0 1px 1px rgba(0,0,0,.2)}.button-success{background:var(--color-background-button-success)}.button-tag{background:var(--color-background-button-tag);color:var(--color-text-button);font-size:65%;border-bottom-left-radius:initial;border-bottom-right-radius:initial;margin-right:4px}.button-tag.active{background:var(--color-background-button-tag-active);font-weight:bold}.button-error{background:var(--color-background-button-error);color:var(--color-text-button-error)}.button-warning{background:var(--color-background-button-warning);color:var(--color-text-button-warning)}.button-secondary{background:var(--color-background-button-secondary)}.button-cancel{background:var(--color-background-button-cancel)}.messages li{list-style:none;padding:1em;border-radius:10px;color:var(--color-text-messages);font-weight:bold}.messages li.message{background:var(--color-background-messages-message)}.messages li.error{background:var(--color-background-messages-error)}.messages li.notice{background:var(--color-background-messages-notice)}.messages.with-share-link>*:hover{cursor:pointer}.notifications-wrapper{padding-top:.5rem}.notifications-wrapper #notification-test-log{margin-top:1rem;padding:1rem;white-space:pre-wrap;word-break:break-word;overflow-wrap:break-word;max-width:100%;box-sizing:border-box;max-height:12rem;overflow-y:scroll;border:1px solid var(--color-border-notification);border-radius:5px}label:hover{cursor:pointer}.grey-form-border{border:1px solid var(--color-border-notification);padding:.5rem;border-radius:5px}#notification-error-log{border:1px solid var(--color-border-notification);padding:1rem;border-radius:5px;overflow-wrap:break-word}#token-table.pure-table td,#token-table.pure-table th{font-size:80%}.pure-form input[type=text].transparent-field{background-color:var(--color-background-new-watch-input-transparent) !important;color:var(--color-white) !important;border:1px solid hsla(0,0%,100%,.2) !important;box-shadow:none !important;-webkit-box-shadow:none !important}.pure-form input[type=text].transparent-field::placeholder{opacity:.5;color:hsla(0,0%,100%,.7);font-weight:lighter}#new-watch-form{background:var(--color-background-new-watch-form);padding:1em;border-radius:10px;margin-bottom:1em;max-width:100%}#new-watch-form #url::placeholder{font-weight:bold}#new-watch-form input{display:inline-block;margin-bottom:5px}#new-watch-form input:not(.pure-button){background-color:var(--color-background-new-watch-input);color:var(--color-text-new-watch-input)}#new-watch-form .label{display:none}#new-watch-form legend{color:var(--color-text-legend);font-weight:bold}@media only screen and (min-width: 760px){#new-watch-form #watch-add-wrapper-zone{display:flex;gap:.3rem;flex-direction:row;min-width:70vw}}#new-watch-form #watch-add-wrapper-zone>span{flex-grow:0}#new-watch-form #watch-add-wrapper-zone>span input{width:100%;padding-right:1em}#new-watch-form #watch-add-wrapper-zone>span:first-child{flex-grow:1}@media only screen and (max-width: 760px){#new-watch-form #watch-add-wrapper-zone #url{width:100%}}#new-watch-form #watch-group-tag{font-size:.9rem;padding:.3rem;display:flex;align-items:center;gap:.5rem;color:var(--color-white)}#new-watch-form #watch-group-tag label,#new-watch-form #watch-group-tag input{margin:0}#new-watch-form #watch-group-tag input{flex:1}#diff-col{padding-left:40px}#diff-jump{position:fixed;left:0px;top:120px;background:var(--color-background);padding:10px;border-top-right-radius:5px;border-bottom-right-radius:5px;box-shadow:1px 1px 4px var(--color-shadow-jump)}#diff-jump a{color:var(--color-link);cursor:pointer;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none;user-select:none;-o-user-select:none}footer{padding:10px;background:var(--color-background);color:var(--color-text-footer);text-align:center}#feed-icon{vertical-align:middle}.sticky-tab{position:absolute;top:60px;font-size:65%;background:var(--color-background);padding:10px}@media only screen and (max-width: 980px){.sticky-tab{display:none}}.sticky-tab#left-sticky{left:0;position:fixed;border-top-right-radius:5px;border-bottom-right-radius:5px;box-shadow:1px 1px 4px var(--color-shadow-jump)}.sticky-tab#right-sticky{right:0px}.sticky-tab#hosted-sticky{right:0px;top:100px;font-weight:bold}#new-version-text a{color:var(--color-link-new-version)}.watch-controls{color:#f8321b}.watch-controls .state-on img{opacity:.8}.watch-controls img{opacity:.2}.watch-controls img:hover{transition:opacity .3s;opacity:.8}.monospaced-textarea textarea{width:100%;font-family:monospace;white-space:pre;overflow-wrap:normal;overflow-x:auto}.pure-form fieldset{padding-top:0px}.pure-form fieldset ul{padding-bottom:0px;margin-bottom:0px}.pure-form .pure-control-group,.pure-form .pure-group,.pure-form .pure-controls{padding-bottom:1em}.pure-form .pure-control-group div,.pure-form .pure-group div,.pure-form .pure-controls div{margin:0px}.pure-form .pure-control-group .checkbox>*,.pure-form .pure-group .checkbox>*,.pure-form .pure-controls .checkbox>*{display:inline;vertical-align:middle}.pure-form .pure-control-group .checkbox>label,.pure-form .pure-group .checkbox>label,.pure-form .pure-controls .checkbox>label{padding-left:5px}.pure-form .pure-control-group legend,.pure-form .pure-group legend,.pure-form .pure-controls legend{color:var(--color-text-legend)}.pure-form .error input{background-color:var(--color-error-input)}.pure-form ul.errors{padding:.5em .6em;border:1px solid var(--color-error-list);border-radius:4px;vertical-align:middle;-webkit-box-sizing:border-box;box-sizing:border-box}.pure-form ul.errors li{margin-left:1em;color:var(--color-error-list)}.pure-form label{font-weight:bold}.pure-form textarea{width:100%}.pure-form .inline-radio ul{margin:0px;list-style:none}.pure-form .inline-radio ul li{display:flex;align-items:center;gap:1em}@media only screen and (max-width: 760px),(min-device-width: 768px)and (max-device-width: 980px){.edit-form{padding:.5em;margin:0}#nav-menu{overflow-x:scroll}}@media only screen and (max-width: 760px),(min-device-width: 768px)and (max-device-width: 980px){input[type=text]{width:100%}}.pure-table{border-color:var(--color-border-table-cell)}.pure-table thead{background-color:var(--color-background-table-thead);color:var(--color-text);border-bottom:1px solid var(--color-background-table-thead)}.pure-table td,.pure-table th{border-left-color:var(--color-border-table-cell)}.pure-table-striped tr:nth-child(2n-1) td{background-color:var(--color-table-stripe)}.pure-form input[type=color],.pure-form input[type=date],.pure-form input[type=datetime-local],.pure-form input[type=datetime],.pure-form input[type=email],.pure-form input[type=month],.pure-form input[type=number],.pure-form input[type=password],.pure-form input[type=search],.pure-form input[type=tel],.pure-form input[type=text],.pure-form input[type=time],.pure-form input[type=url],.pure-form input[type=week],.pure-form select,.pure-form textarea{border:var(--color-border-input);box-shadow:inset 0 1px 3px var(--color-shadow-input);background-color:var(--color-background-input);color:var(--color-text-input)}.pure-form input[type=color]:active,.pure-form input[type=date]:active,.pure-form input[type=datetime-local]:active,.pure-form input[type=datetime]:active,.pure-form input[type=email]:active,.pure-form input[type=month]:active,.pure-form input[type=number]:active,.pure-form input[type=password]:active,.pure-form input[type=search]:active,.pure-form input[type=tel]:active,.pure-form input[type=text]:active,.pure-form input[type=time]:active,.pure-form input[type=url]:active,.pure-form input[type=week]:active,.pure-form select:active,.pure-form textarea:active{background-color:var(--color-background-input)}input::placeholder,textarea::placeholder{color:var(--color-text-input-placeholder)}.m-d{min-width:100%}@media only screen and (min-width: 761px){.m-d{min-width:80%}}.pure-form-stacked>div:first-child{display:block}.tab-pane-inner{padding:0px}.tab-pane-inner:not(:target){display:none}.tab-pane-inner:target{display:block}.beta-logo{height:50px;right:-3px;top:-3px;position:absolute}#selector-header{padding-bottom:1em}body.full-width .edit-form{width:95%}.edit-form{min-width:70%;max-width:95%}.edit-form .box-wrap{position:relative}.edit-form .inner{background:var(--color-background);padding:20px}.edit-form #actions{display:block;background:var(--color-background)}.edit-form #actions .pure-control-group{display:flex;gap:.625em;flex-wrap:wrap}.edit-form .pure-form-message-inline{padding-left:0;color:var(--color-text-input-description)}.edit-form .pure-form-message-inline code{font-size:.875em}.border-fieldset{border:1px solid #ccc;padding:1rem;border-radius:5px;margin-bottom:1rem}.border-fieldset h3{margin-top:0}.border-fieldset fieldset:last-of-type{padding-bottom:0}.border-fieldset fieldset:last-of-type .pure-control-group{padding-bottom:0}ul{padding-left:1em;padding-top:0px;margin-top:4px}.time-check-widget tr{display:inline}.time-check-widget tr input[type=number]{width:5em}@media only screen and (max-width: 760px){.time-check-widget tbody{display:grid;grid-template-columns:auto 1fr auto 1fr;gap:.625em .3125em;align-items:center}.time-check-widget tr{display:contents}.time-check-widget tr th{text-align:right;padding-right:5px}.time-check-widget tr input[type=number]{width:100%;max-width:5em}}#webdriver_delay{width:5em}#api-key:hover{cursor:pointer}#api-key-copy{color:var(--color-api-key)}.button-green{background-color:var(--color-background-button-green)}.button-red{background-color:var(--color-background-button-red)}.noselect{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}#checkbox-operations{background:var(--color-background-checkbox-operations);padding:1em;border-radius:10px;margin-bottom:1em;display:none}#checkbox-operations button{margin-bottom:3px;margin-top:3px;display:inline-flex;align-items:center}.checkbox-uuid>*{vertical-align:middle}.inline-warning{border:1px solid var(--color-border-warning);padding:.5rem;border-radius:5px;color:var(--color-warning)}.inline-warning>span{display:inline-block;vertical-align:middle}.inline-warning img.inline-warning-icon{display:inline;height:26px;vertical-align:middle}.tracking-ldjson-price-data{background-color:var(--color-background-button-green);color:#000;opacity:.6}.ldjson-price-track-offer{font-weight:bold;font-style:italic}.ldjson-price-track-offer a.pure-button{border-radius:3px;padding:3px;background-color:var(--color-background-button-green)}.price-follow-tag-icon{display:inline-block;height:.8rem;vertical-align:middle}#quick-watch-processor-type ul#processor{color:#fff;padding-left:0px}#quick-watch-processor-type ul#processor li{list-style:none;font-size:.9rem;display:grid;grid-template-columns:auto 1fr;align-items:center;gap:.5rem;margin-bottom:.5rem}#quick-watch-processor-type label,#quick-watch-processor-type input{padding:0;margin:0}.restock-label.in-stock{background-color:var(--color-background-button-green);color:#fff}.restock-label.not-in-stock{background-color:var(--color-background-button-cancel);color:#777}.restock-label.error{background-color:var(--color-background-button-error);color:#fff;opacity:.7}.restock-label svg{vertical-align:middle}#chrome-extension-link{padding:9px;border:1px solid var(--color-grey-800);border-radius:10px;vertical-align:middle}#chrome-extension-link img{height:21px;padding:2px;vertical-align:middle}#realtime-conn-error{position:fixed;bottom:0;left:0;background:var(--color-warning);padding:10px;font-size:.8rem;color:#fff;opacity:.8}#bottom-horizontal-offscreen{position:fixed;bottom:0;left:0;right:0;width:100%;min-height:50px;max-height:50vh;background:hsla(0,0%,100%,.7215686275);border-top:1px solid var(--color-border-table-cell);padding:10px;box-shadow:0 -2px 10px rgba(0,0,0,.2);z-index:100;overflow-y:auto;transition:opacity .3s ease-in-out;scroll-margin-bottom:10px;display:flex;justify-content:center;align-items:center}ul#highlightSnippetActions{list-style:none}ul#highlightSnippetActions li{display:inline-block} +:root{--color-white: #fff;--color-grey-50: #111;--color-grey-100: #262626;--color-grey-200: #333;--color-grey-300: #444;--color-grey-325: #555;--color-grey-350: #565d64;--color-grey-400: #666;--color-grey-500: #777;--color-grey-600: #999;--color-grey-700: #cbcbcb;--color-grey-750: #ddd;--color-grey-800: #e0e0e0;--color-grey-850: #eee;--color-grey-900: #f2f2f2;--color-black: #000;--color-dark-red: #a00;--color-light-red: #dd0000;--color-background-page: var(--color-grey-100);--color-background-gradient-first: #5ad8f7;--color-background-gradient-second: #2f50af;--color-background-gradient-third: #9150bf;--color-background: var(--color-white);--color-text: var(--color-grey-200);--color-link: #1b98f8;--color-menu-accent: #ed5900;--color-background-code: var(--color-grey-850);--color-error: var(--color-dark-red);--color-error-input: #ffebeb;--color-error-list: var(--color-light-red);--color-table-background: var(--color-background);--color-table-stripe: var(--color-grey-900);--color-text-tab: var(--color-white);--color-background-tab: rgba(255, 255, 255, 0.2);--color-background-tab-hover: rgba(255, 255, 255, 0.5);--color-text-tab-active: #222;--color-api-key: #0078e7;--color-background-button-primary: #0078e7;--color-background-button-green: #42dd53;--color-background-button-red: #dd4242;--color-background-button-success: rgb(28, 184, 65);--color-background-button-error: rgb(202, 60, 60);--color-text-button-error: var(--color-white);--color-background-button-warning: rgb(202, 60, 60);--color-text-button-warning: var(--color-white);--color-background-button-secondary: rgb(66, 184, 221);--color-background-button-cancel: rgb(200, 200, 200);--color-text-button: var(--color-white);--color-background-button-tag: rgb(99, 99, 99);--color-background-snapshot-age: #dfdfdf;--color-error-text-snapshot-age: var(--color-white);--color-error-background-snapshot-age: #ff0000;--color-background-button-tag-active: #9c9c9c;--color-text-messages: var(--color-white);--color-background-messages-message: rgba(255, 255, 255, .2);--color-background-messages-error: rgba(255, 1, 1, .5);--color-background-messages-notice: rgba(255, 255, 255, .5);--color-border-notification: #ccc;--color-background-checkbox-operations: rgba(0, 0, 0, 0.05);--color-warning: #ff3300;--color-border-warning: var(--color-warning);--color-text-legend: var(--color-white);--color-link-new-version: #e07171;--color-last-checked: #bbb;--color-text-footer: #444;--color-border-watch-table-cell: #eee;--color-text-watch-tag-list: rgba(231, 0, 105, 0.4);--color-background-new-watch-form: rgba(0, 0, 0, 0.05);--color-background-new-watch-input: var(--color-white);--color-background-new-watch-input-transparent: rgba(255, 255, 255, 0.1);--color-text-new-watch-input: var(--color-text);--color-border-input: var(--color-grey-500);--color-shadow-input: var(--color-grey-400);--color-background-input: var(--color-white);--color-text-input: var(--color-text);--color-text-input-description: var(--color-grey-500);--color-text-input-placeholder: var(--color-grey-600);--color-background-table-thead: var(--color-grey-800);--color-border-table-cell: var(--color-grey-700);--color-text-menu-heading: var(--color-grey-350);--color-text-menu-link: var(--color-grey-500);--color-background-menu-link-hover: var(--color-grey-850);--color-text-menu-link-hover: var(--color-grey-300);--color-shadow-jump: var(--color-grey-500);--color-icon-github: var(--color-black);--color-icon-github-hover: var(--color-grey-300);--color-watch-table-error: var(--color-dark-red);--color-watch-table-row-text: var(--color-grey-100);--highlight-trigger-text-bg-color: #1b98f8;--highlight-ignored-text-bg-color: var(--color-grey-700);--highlight-blocked-text-bg-color: rgb(202, 60, 60)}html[data-darkmode=true]{--color-link: #59bdfb;--color-text: var(--color-white);--color-background-gradient-first: #3f90a5;--color-background-gradient-second: #1e316c;--color-background-gradient-third: #4d2c64;--color-background-new-watch-input: var(--color-grey-100);--color-background-new-watch-input-transparent: var(--color-grey-100);--color-text-new-watch-input: var(--color-text);--color-background-table-thead: var(--color-grey-200);--color-table-background: var(--color-grey-300);--color-table-stripe: var(--color-grey-325);--color-background: var(--color-grey-300);--color-text-menu-heading: var(--color-grey-850);--color-text-menu-link: var(--color-grey-800);--color-border-table-cell: var(--color-grey-400);--color-text-tab-active: var(--color-text);--color-border-input: var(--color-grey-400);--color-shadow-input: var(--color-grey-50);--color-background-input: var(--color-grey-350);--color-text-input-description: var(--color-grey-600);--color-text-input-placeholder: var(--color-grey-600);--color-text-watch-tag-list: rgba(250, 62, 146, 0.4);--color-background-code: var(--color-grey-200);--color-background-tab: rgba(0, 0, 0, 0.2);--color-background-tab-hover: rgba(0, 0, 0, 0.5);--color-background-snapshot-age: var(--color-grey-200);--color-shadow-jump: var(--color-grey-200);--color-icon-github: var(--color-white);--color-icon-github-hover: var(--color-grey-700);--color-watch-table-error: var(--color-light-red);--color-watch-table-row-text: var(--color-grey-800)}html[data-darkmode=true] .icon-spread{filter:hue-rotate(-10deg) brightness(1.5)}html[data-darkmode=true] .watch-table .title-col a[target=_blank]::after,html[data-darkmode=true] .watch-table .current-diff-url::after{filter:invert(0.5) hue-rotate(10deg) brightness(2)}html[data-darkmode=true] .watch-table .status-browsersteps{filter:invert(0.5) hue-rotate(10deg) brightness(1.5)}html[data-darkmode=true] .watch-table .watch-controls .state-off img{opacity:.3}html[data-darkmode=true] .watch-table .watch-controls .state-on img{opacity:1}html[data-darkmode=true] .watch-table .unviewed{color:#fff}html[data-darkmode=true] .watch-table .unviewed.error{color:var(--color-watch-table-error)}.arrow{border:solid #1b98f8;border-width:0 2px 2px 0;display:inline-block;padding:3px}.arrow.right{transform:rotate(-45deg);-webkit-transform:rotate(-45deg)}.arrow.left{transform:rotate(135deg);-webkit-transform:rotate(135deg)}.arrow.up,.arrow.asc{transform:rotate(-135deg);-webkit-transform:rotate(-135deg)}.arrow.down,.arrow.desc{transform:rotate(45deg);-webkit-transform:rotate(45deg)}#browser_steps th{display:none}#browser_steps li{list-style:decimal;padding:5px}#browser_steps li.browser-step-with-error{background-color:#ffd6d6;border-radius:4px}#browser_steps li:not(:first-child):hover{opacity:1}#browser_steps li .control{padding-left:5px;padding-right:5px}#browser_steps li .control a{font-size:70%}#browser_steps li.empty{padding:0px;opacity:.35}#browser_steps li.empty .control{display:none}#browser_steps li:hover{background:#eee}#browser_steps li>label{display:none}@media only screen and (min-width: 760px){#browser-steps .flex-wrapper{display:flex;flex-flow:row;height:70vh;font-size:80%}#browser-steps .flex-wrapper #browser-steps-ui{flex-grow:1;flex-shrink:1;flex-basis:0;background-color:#eee;border-radius:5px}#browser-steps-fieldlist{flex-grow:0;flex-shrink:0;flex-basis:auto;max-width:400px;padding-left:1rem;overflow-y:scroll}#browsersteps-selector-wrapper{height:100% !important}}#browsersteps-selector-wrapper{width:100%;overflow-y:scroll;position:relative;height:80vh}#browsersteps-selector-wrapper>img{position:absolute;max-width:100%}#browsersteps-selector-wrapper>canvas{position:relative;max-width:100%}#browsersteps-selector-wrapper>canvas:hover{cursor:pointer}#browsersteps-selector-wrapper .loader{position:absolute;left:50%;top:50%;transform:translate(-50%, -50%);z-index:100;max-width:350px;text-align:center}#browsersteps-selector-wrapper .spinner,#browsersteps-selector-wrapper .spinner:after{width:80px;height:80px;font-size:3px}#browsersteps-selector-wrapper #browsersteps-click-start{color:var(--color-grey-400)}#browsersteps-selector-wrapper #browsersteps-click-start:hover{cursor:pointer}ul#requests-extra_proxies{list-style:none}ul#requests-extra_proxies li>label{display:none}ul#requests-extra_proxies table tr{display:table-row}ul#requests-extra_proxies table tr input[type=text]{width:100%}@media only screen and (min-width: 1024px){ul#requests-extra_proxies table tr{display:inline}}#request label[for=proxy]{display:inline-block}body.proxy-check-active #request .proxy-check-details{font-size:80%;color:#555;display:block;padding-left:2em;max-width:500px}body.proxy-check-active #request .proxy-timing{font-size:80%;padding-left:1rem;color:var(--color-link)}#recommended-proxy{display:grid;gap:2rem;padding-bottom:1em}@media(min-width: 991px){#recommended-proxy{grid-template-columns:repeat(2, 1fr)}}#recommended-proxy>div{border:1px #aaa solid;border-radius:4px;padding:1em}#extra-proxies-setting{border:1px solid var(--color-grey-800);border-radius:4px;margin:1em;padding:1em}ul#requests-extra_browsers{list-style:none}ul#requests-extra_browsers li>label{display:none}ul#requests-extra_browsers table tr{display:table-row}ul#requests-extra_browsers table tr input[type=text]{width:100%}@media only screen and (min-width: 1280px){ul#requests-extra_browsers table tr{display:inline}ul#requests-extra_browsers table tr input[type=text]{width:100%}}#extra-browsers-setting{border:1px solid var(--color-grey-800);border-radius:4px;margin:1em;padding:1em}.pagination-page-info{text-transform:capitalize}.pagination.menu>*{display:inline-block}.pagination.menu li{display:inline-block}.pagination.menu a{padding:.65rem;margin:3px;border:none;background:#444;border-radius:2px;color:var(--color-text-button)}.pagination.menu a.disabled{display:none}.pagination.menu a.active{font-weight:bold;background:#888}.pagination.menu a:hover{background:#999}.spinner,.spinner:after{border-radius:50%;width:10px;height:10px}.spinner{margin:0px auto;font-size:3px;vertical-align:middle;display:inline-block;text-indent:-9999em;border-top:1.1em solid rgba(38,104,237,.2);border-right:1.1em solid rgba(38,104,237,.2);border-bottom:1.1em solid rgba(38,104,237,.2);border-left:1.1em solid #2668ed;-webkit-transform:translateZ(0);-ms-transform:translateZ(0);transform:translateZ(0);-webkit-animation:load8 1.1s infinite linear;animation:load8 1.1s infinite linear}@-webkit-keyframes load8{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes load8{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}.toggle-light-mode .icon-dark{display:none}html[data-darkmode=true] .toggle-light-mode .icon-light{display:none}html[data-darkmode=true] .toggle-light-mode .icon-dark{display:block}.pure-menu-link{padding:.5rem 1em;line-height:1.2rem}.pure-menu-item svg{height:1.2rem}.pure-menu-item *{vertical-align:middle}.pure-menu-item .github-link{height:1.8rem;display:block}.pure-menu-item .github-link svg{height:100%}.pure-menu-item .bi-heart:hover{cursor:pointer}.pure-menu-item.active .pure-menu-link{background-color:var(--color-background-menu-link-hover);color:var(--color-text-menu-link-hover)}#cdio-logo{padding-left:.5em}#inline-menu-extras-group>*{display:inline-block}#overlay{opacity:.95;position:fixed;width:350px;max-width:100%;height:100%;top:0;right:-350px;background-color:var(--color-table-stripe);z-index:2;transform:translateX(0);transition:transform .5s ease}#overlay.visible{transform:translateX(-100%)}#overlay .content{font-size:.875rem;padding:1rem;margin-top:5rem;max-width:400px;color:var(--color-watch-table-row-text)}#heartpath{transition:all ease .3s !important}#heartpath:hover{fill:red !important;transition:all ease .3s !important}.minitabs-wrapper{width:100%}.minitabs-wrapper>div[id]{padding:20px;border:1px solid #ccc;border-top:none}.minitabs-wrapper .minitabs-content{width:100%;display:flex}.minitabs-wrapper .minitabs-content>div{flex:1 1 auto;min-width:0;overflow:scroll}.minitabs-wrapper .minitabs{display:flex;border-bottom:1px solid #ccc}.minitabs-wrapper .minitab{flex:1;text-align:center;padding:12px 0;text-decoration:none;color:#333;background-color:#f1f1f1;border:1px solid #ccc;border-bottom:none;cursor:pointer;transition:background-color .3s}.minitabs-wrapper .minitab:hover{background-color:#ddd}.minitabs-wrapper .minitab.active{background-color:#fff;font-weight:bold}@media(min-width: 800px){body.preview-text-enabled #filters-and-triggers>div{display:flex;gap:20px;position:relative}}body.preview-text-enabled #edit-text-filter,body.preview-text-enabled #text-preview{flex:1;align-self:flex-start}body.preview-text-enabled #edit-text-filter #pro-tips{display:none}body.preview-text-enabled #text-preview{position:sticky;top:20px;padding-top:1rem;padding-bottom:1rem;display:block !important}body.preview-text-enabled #activate-text-preview{background-color:var(--color-grey-500)}body.preview-text-enabled .monospace-preview{background:var(--color-background-input);border:1px solid var(--color-grey-600);padding:1rem;color:var(--color-text-input);font-family:"Courier New",Courier,monospace;font-size:70%;word-break:break-word;white-space:pre-wrap}#activate-text-preview{right:0;position:absolute;z-index:3;box-shadow:1px 1px 4px var(--color-shadow-jump)}#stats_row{display:flex;align-items:center;width:100%;color:#fff;font-size:.85rem}#stats_row>*{padding-bottom:.5rem}#stats_row .left{text-align:left}#stats_row .right{opacity:.5;transition:opacity .6s ease;margin-left:auto;text-align:right}body.has-queue #stats_row .right{opacity:1}.watch-table{width:100%;font-size:80%}.watch-table tr{color:var(--color-watch-table-row-text)}.watch-table tr.unviewed{font-weight:bold}.watch-table td{white-space:nowrap}.watch-table td.title-col{word-break:break-all;white-space:normal}.watch-table td a.external::after{content:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAQElEQVR42qXKwQkAIAxDUUdxtO6/RBQkQZvSi8I/pL4BoGw/XPkh4XigPmsUgh0626AjRsgxHTkUThsG2T/sIlzdTsp52kSS1wAAAABJRU5ErkJggg==);margin:0 3px 0 5px}.watch-table th{white-space:nowrap}.watch-table th a{font-weight:normal}.watch-table th a.active{font-weight:bolder}.watch-table th a.inactive .arrow{display:none}.watch-table tr.checking-now td:first-child{position:relative}.watch-table tr.checking-now td:first-child::before{content:"";position:absolute;top:0;bottom:0;left:0;width:3px;background-color:#293eff}.watch-table tr.checking-now td.last-checked .spinner-wrapper{display:inline-block !important}.watch-table tr.checking-now td.last-checked .innertext{display:none !important}.watch-table tr.queued a.recheck{display:none !important}.watch-table tr.queued a.already-in-queue-button{display:inline-block !important}.watch-table tr.paused a.pause-toggle.state-on{display:inline !important}.watch-table tr.paused a.pause-toggle.state-off{display:none !important}.watch-table tr.notification_muted a.mute-toggle.state-on{display:inline !important}.watch-table tr.notification_muted a.mute-toggle.state-off{display:none !important}.watch-table tr.has-error{color:var(--color-watch-table-error)}.watch-table tr.has-error .error-text{display:block !important}.watch-table tr.single-history a.preview-link{display:inline-block !important}.watch-table tr.multiple-history a.history-link{display:inline-block !important}#watch-table-wrapper #post-list-buttons{text-align:right;padding:0px;margin:0px}#watch-table-wrapper #post-list-buttons li{display:inline-block}#watch-table-wrapper #post-list-buttons a{border-top-left-radius:initial;border-top-right-radius:initial;border-bottom-left-radius:5px;border-bottom-right-radius:5px}#watch-table-wrapper.has-error #post-list-buttons #post-list-with-errors{display:inline-block !important}#watch-table-wrapper.has-unread-changes #post-list-buttons #post-list-unread,#watch-table-wrapper.has-unread-changes #post-list-buttons #post-list-mark-views,#watch-table-wrapper.has-unread-changes #post-list-buttons #post-list-unread{display:inline-block !important}@media(max-width: 767px){.watch-table thead{display:block}.watch-table thead tr th{display:inline-block}}@media(max-width: 767px)and (max-width: 768px){.watch-table thead tr th .hide-on-mobile{display:none}}@media(max-width: 767px){.watch-table thead .empty-cell{display:none}.watch-table .last-checked{margin-left:calc(20px + .5rem)}.watch-table .last-checked>span{vertical-align:middle}.watch-table .last-changed{margin-left:calc(20px + .5rem)}.watch-table .last-checked::before{color:var(--color-text);content:"Last Checked "}.watch-table .last-changed::before{color:var(--color-text);content:"Last Changed "}.watch-table td.inline{display:inline-block}.watch-table .pure-table td,.watch-table .pure-table th{border:none}.watch-table td{border:none;border-bottom:1px solid var(--color-border-watch-table-cell);vertical-align:middle}.watch-table td:before{top:6px;left:6px;width:45%;padding-right:10px;white-space:nowrap}.watch-table.pure-table-striped tr{background-color:var(--color-table-background)}.watch-table.pure-table-striped tr:nth-child(2n-1){background-color:var(--color-table-stripe)}.watch-table.pure-table-striped tr:nth-child(2n-1) td{background-color:inherit}}@media(max-width: 767px){.watch-table tbody tr{padding-bottom:10px;padding-top:10px;display:grid;grid-template-columns:20px 1fr 100px;grid-template-rows:auto auto auto auto;gap:.5rem}.watch-table tbody tr .counter-i{display:none}.watch-table tbody tr td.checkbox-uuid{display:grid;place-items:center}.watch-table tbody tr>td{border-bottom:none}.watch-table tbody tr>td.title-col{grid-column:1/-1;grid-row:1}.watch-table tbody tr>td.title-col .watch-title{font-size:.92rem}.watch-table tbody tr>td.title-col .link-spread{display:none}.watch-table tbody tr>td.last-checked{grid-column:1/-1;grid-row:2}.watch-table tbody tr>td.last-changed{grid-column:1/-1;grid-row:3}.watch-table tbody tr>td.checkbox-uuid{grid-column:1;grid-row:4}.watch-table tbody tr>td.buttons{grid-column:2;grid-row:4;display:flex;align-items:center;justify-content:flex-start}.watch-table tbody tr>td.watch-controls{grid-column:3;grid-row:4;display:grid;place-items:center}.watch-table tbody tr>td.watch-controls a img{padding:10px}.pure-table td{padding:3px !important}}ul#conditions_match_logic{list-style:none}ul#conditions_match_logic input,ul#conditions_match_logic label,ul#conditions_match_logic li{display:inline-block}ul#conditions_match_logic li{padding-right:1em}.fieldlist_formfields{width:100%;background-color:var(--color-background, #fff);border-radius:4px;border:1px solid var(--color-border-table-cell, #cbcbcb)}.fieldlist_formfields .fieldlist-header{display:flex;background-color:var(--color-background-table-thead, #e0e0e0);font-weight:bold;border-bottom:1px solid var(--color-border-table-cell, #cbcbcb)}.fieldlist_formfields .fieldlist-header-cell{flex:1;padding:.5em 1em;text-align:left}.fieldlist_formfields .fieldlist-header-cell:last-child{flex:0 0 120px}.fieldlist_formfields .fieldlist-body{display:flex;flex-direction:column}.fieldlist_formfields .fieldlist-row{display:flex;border-bottom:1px solid var(--color-border-table-cell, #cbcbcb)}.fieldlist_formfields .fieldlist-row:last-child{border-bottom:none}.fieldlist_formfields .fieldlist-row:nth-child(2n-1){background-color:var(--color-table-stripe, #f2f2f2)}.fieldlist_formfields .fieldlist-row.error-row{background-color:var(--color-error-input, #ffdddd)}.fieldlist_formfields .fieldlist-cell{flex:1;padding:.5em 1em;display:flex;flex-direction:column;justify-content:center}.fieldlist_formfields .fieldlist-cell input,.fieldlist_formfields .fieldlist-cell select{width:100%}.fieldlist_formfields .fieldlist-cell.fieldlist-actions{flex:0 0 120px;display:flex;flex-direction:row;align-items:center;gap:4px}.fieldlist_formfields ul.errors{margin-top:.5em;margin-bottom:0;padding:.5em;background-color:var(--color-error-background-snapshot-age, #ffdddd);border-radius:4px;list-style-position:inside}@media only screen and (max-width: 760px){.fieldlist_formfields .fieldlist-header,.fieldlist_formfields .fieldlist-row{flex-direction:column}.fieldlist_formfields .fieldlist-header-cell{display:none}.fieldlist_formfields .fieldlist-row{padding:.5em 0;border-bottom:2px solid var(--color-border-table-cell, #cbcbcb)}.fieldlist_formfields .fieldlist-cell{padding:.25em .5em}.fieldlist_formfields .fieldlist-cell.fieldlist-actions{flex:1;justify-content:flex-start;padding-top:.5em}.fieldlist_formfields .fieldlist-cell:not(:last-child){margin-bottom:.5em}.fieldlist_formfields .fieldlist-cell::before{content:attr(data-label);font-weight:bold;margin-bottom:.25em}}.fieldlist_formfields .addRuleRow,.fieldlist_formfields .removeRuleRow,.fieldlist_formfields .verifyRuleRow{cursor:pointer;border:none;padding:4px 8px;border-radius:3px;font-weight:bold;background-color:#aaa;color:var(--color-foreground-text, #fff)}.fieldlist_formfields .addRuleRow:hover,.fieldlist_formfields .removeRuleRow:hover,.fieldlist_formfields .verifyRuleRow:hover{background-color:#999}.watch-table.favicon-not-enabled tr .favicon{display:none}.watch-table tr td.inline.title-col .flex-wrapper{display:flex;align-items:center;gap:4px}.watch-table td,.watch-table th{vertical-align:middle}.watch-table tr.has-favicon.unviewed img.favicon{opacity:1 !important}.watch-table .status-icons{white-space:nowrap;display:flex;align-items:center;gap:4px}.watch-table .status-icons>*{vertical-align:middle}.title-col{padding:10px}.title-wrapper{display:flex;align-items:center;gap:10px}.title-col-inner{display:inline-block;vertical-align:middle}.watch-table img.favicon{vertical-align:middle;max-width:25px;max-height:25px;height:25px;padding-right:4px}body.checking-now #checking-now-fixed-tab{display:block !important}#checking-now-fixed-tab{background:#ccc;border-radius:5px;bottom:0;color:var(--color-text);display:none;font-size:.8rem;left:0;padding:5px;position:fixed}#selector-wrapper{height:100%;text-align:center;max-height:70vh;overflow-y:scroll;position:relative}#selector-wrapper>img{position:absolute;z-index:4;max-width:100%}#selector-wrapper>canvas{position:relative;z-index:5;max-width:100%}#selector-wrapper>canvas:hover{cursor:pointer}#selector-current-xpath{font-size:80%}.ternary-radio-group{display:flex;gap:0;border:1px solid var(--color-grey-750);border-radius:4px;overflow:hidden;width:fit-content;background:var(--color-background)}.ternary-radio-group .ternary-radio-option{position:relative;cursor:pointer;margin:0;display:flex;align-items:center}.ternary-radio-group .ternary-radio-option input[type=radio]{position:absolute;opacity:0;width:0;height:0}.ternary-radio-group .ternary-radio-option .ternary-radio-label{padding:8px 16px;background:var(--color-grey-900);border:none;border-right:1px solid var(--color-grey-750);font-size:13px;font-weight:500;color:var(--color-text);transition:all .2s ease;cursor:pointer;display:block;text-align:center}.ternary-radio-group .ternary-radio-option:last-child .ternary-radio-label{border-right:none}.ternary-radio-group .ternary-radio-option input:checked+.ternary-radio-label{background:var(--color-link);color:var(--color-text-button);font-weight:600}.ternary-radio-group .ternary-radio-option input:checked+.ternary-radio-label.ternary-default{background:var(--color-grey-600);color:var(--color-text-button)}.ternary-radio-group .ternary-radio-option input:checked+.ternary-radio-label:hover{background:#1a7bc4}.ternary-radio-group .ternary-radio-option input:checked+.ternary-radio-label:hover.ternary-default{background:var(--color-grey-500)}.ternary-radio-group .ternary-radio-option:hover .ternary-radio-label{background:var(--color-grey-800)}@media(max-width: 480px){.ternary-radio-group{width:100%}.ternary-radio-group .ternary-radio-label{flex:1;min-width:auto}}input[type=radio].pure-radio:checked+label,input[type=radio].pure-radio:checked{background:var(--color-link);color:var(--color-text-button)}html[data-darkmode=true] .ternary-radio-group .ternary-radio-option .ternary-radio-label{background:var(--color-grey-350)}html[data-darkmode=true] .ternary-radio-group .ternary-radio-option:hover .ternary-radio-label{background:var(--color-grey-400)}html[data-darkmode=true] .ternary-radio-group .ternary-radio-option input:checked+.ternary-radio-label{background:var(--color-link);color:var(--color-text-button)}html[data-darkmode=true] .ternary-radio-group .ternary-radio-option input:checked+.ternary-radio-label.ternary-default{background:var(--color-grey-600)}html[data-darkmode=true] .ternary-radio-group .ternary-radio-option input:checked+.ternary-radio-label:hover{background:#1a7bc4}html[data-darkmode=true] .ternary-radio-group .ternary-radio-option input:checked+.ternary-radio-label:hover.ternary-default{background:var(--color-grey-500)}body.processor-image_ssim_diff #edit-text-filter .text-filtering{display:none}body.processor-image_ssim_diff #conditions-tab{display:none}.modal-dialog{border:none;border-radius:10px;padding:0;background:var(--color-background);color:var(--color-text);box-shadow:0 5px 20px rgba(0,0,0,.3);max-width:500px;width:90%}.modal-dialog::backdrop{background:rgba(0,0,0,.6);backdrop-filter:blur(3px);animation:fadeIn .2s ease-out}.modal-dialog[open]{animation:slideIn .25s ease-out}.modal-dialog .modal-header{padding:1.5rem;border-bottom:1px solid var(--color-border-table-cell);display:flex;align-items:center;gap:1rem}.modal-dialog .modal-header .modal-icon{font-size:2rem;line-height:1;flex-shrink:0}.modal-dialog .modal-header .modal-icon.warning{color:var(--color-warning)}.modal-dialog .modal-header .modal-icon.danger{color:var(--color-background-button-error)}.modal-dialog .modal-header .modal-icon.info{color:var(--color-background-button-primary)}.modal-dialog .modal-header .modal-title{font-size:1.3rem;font-weight:bold;margin:0;color:var(--color-text)}.modal-dialog .modal-body{padding:1.5rem;line-height:1.6}.modal-dialog .modal-body p{margin:0 0 1rem 0}.modal-dialog .modal-body p:last-child{margin-bottom:0}.modal-dialog .modal-body strong{color:var(--color-text);font-weight:600}.modal-dialog .modal-footer{padding:1rem 1.5rem;border-top:1px solid var(--color-border-table-cell);display:flex;gap:.75rem;justify-content:flex-end;background:var(--color-grey-900)}.modal-dialog .modal-footer button{padding:.6rem 1.5rem;border:none;border-radius:4px;cursor:pointer;font-weight:500;transition:all .2s ease;font-size:.95rem}.modal-dialog .modal-footer button:hover{transform:translateY(-1px);box-shadow:0 2px 8px rgba(0,0,0,.15)}.modal-dialog .modal-footer button:active{transform:translateY(0)}.modal-dialog .modal-footer button.modal-btn-cancel{background:var(--color-background-button-cancel);color:var(--color-grey-200)}.modal-dialog .modal-footer button.modal-btn-cancel:hover{background:var(--color-grey-700)}.modal-dialog .modal-footer button.modal-btn-confirm{background:var(--color-background-button-primary);color:var(--color-white)}.modal-dialog .modal-footer button.modal-btn-confirm:hover{opacity:.9}.modal-dialog .modal-footer button.modal-btn-danger{background:var(--color-background-button-error);color:var(--color-white)}.modal-dialog .modal-footer button.modal-btn-danger:hover{background:var(--color-dark-red)}.modal-dialog .modal-footer button.modal-btn-warning{background:var(--color-background-button-warning);color:var(--color-white)}.modal-dialog .modal-footer button.modal-btn-warning:hover{opacity:.9}html[data-darkmode=true] .modal-dialog{box-shadow:0 5px 30px rgba(0,0,0,.7)}html[data-darkmode=true] .modal-dialog .modal-footer{background:var(--color-grey-200)}@keyframes fadeIn{from{opacity:0}to{opacity:1}}@keyframes slideIn{from{opacity:0;transform:translateY(-20px) scale(0.95)}to{opacity:1;transform:translateY(0) scale(1)}}@media only screen and (max-width: 760px){.modal-dialog{width:95%;max-width:none}.modal-dialog .modal-header{padding:1rem}.modal-dialog .modal-header .modal-title{font-size:1.1rem}.modal-dialog .modal-body{padding:1rem;font-size:.95rem}.modal-dialog .modal-footer{padding:.75rem 1rem;flex-wrap:wrap}.modal-dialog .modal-footer button{flex:1;min-width:120px}}#language-selector-flag{display:inline-block;width:1.2em;height:1.2em;vertical-align:middle;border-radius:50%;overflow:hidden;opacity:.6}#language-selector-flag:hover{opacity:1}.language-list{display:flex;flex-direction:column;gap:.5rem;padding:.5rem 0}.language-option{display:flex;align-items:center;gap:1rem;padding:.25rem;border-radius:4px;transition:background-color .2s ease;text-decoration:none;color:var(--color-text);border:1px solid rgba(0,0,0,0)}.language-option:hover{background-color:var(--color-background-menu-link-hover);border-color:var(--color-border-table-cell)}.language-option.active{background-color:var(--color-link);color:var(--color-text-button);font-weight:600}.language-option .flag{font-size:1.5rem;flex-shrink:0}.language-option .language-name{flex-grow:1;font-size:1rem}#language-modal .language-list .lang-option{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;margin-right:.5em;border-radius:50%;overflow:hidden}.content-wrapper{display:flex;gap:0;width:100%;max-width:100%;position:relative}@media only screen and (max-width: 900px){.content-wrapper{flex-direction:column}}.action-sidebar{position:sticky;top:100px;flex-shrink:0;width:80px;height:fit-content;background:rgba(0,0,0,0);padding:1.5rem 0;display:flex;flex-direction:column;gap:.5rem;align-items:center;z-index:0}@media only screen and (max-width: 900px){.action-sidebar{position:relative;top:0;width:100%;flex-direction:row;justify-content:space-around;padding:0;overflow-x:auto}}.action-sidebar-item{position:relative;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.35rem;padding:.75rem .5rem;min-width:64px;text-decoration:none;opacity:.8;transition:opacity .2s ease}.action-sidebar-item:hover{opacity:1}.action-sidebar-item.active{opacity:1}.action-sidebar-item.active .action-icon{stroke:#fff;stroke-width:2.5}.action-sidebar-item.active .action-label{color:#fff;font-weight:700}.action-icon{width:28px;height:28px;stroke:#fff;stroke-width:2;fill:none;stroke-linecap:round;stroke-linejoin:round;transition:stroke .2s ease}.action-label{font-size:.65rem;font-weight:500;text-align:center;line-height:1.1;letter-spacing:.02em;text-transform:uppercase;color:#fff;transition:color .2s ease;max-width:60px;word-wrap:break-word}.content-main{flex:0 1 auto;width:100%;min-width:0;padding:0;display:flex;flex-direction:column;align-items:center}.hamburger-menu{display:none;background:rgba(0,0,0,0);border:none;cursor:pointer;padding:.5rem;z-index:10001;position:relative}@media only screen and (max-width: 980px){.hamburger-menu{display:flex;flex-direction:column;justify-content:center;align-items:center}}.hamburger-icon{width:24px;height:20px;position:relative;display:flex;flex-direction:column;justify-content:space-between}.hamburger-icon span{display:block;height:3px;width:100%;background:var(--color-text);border-radius:2px;transition:all .3s cubic-bezier(0.68, -0.55, 0.265, 1.55);transform-origin:center}.hamburger-menu.active .hamburger-icon span:nth-child(1){transform:translateY(8.5px) rotate(45deg)}.hamburger-menu.active .hamburger-icon span:nth-child(2){opacity:0;transform:translateX(-10px)}.hamburger-menu.active .hamburger-icon span:nth-child(3){transform:translateY(-8.5px) rotate(-45deg)}.mobile-menu-overlay{display:none;position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,.5);z-index:9999;opacity:0;transition:opacity .3s ease}.mobile-menu-overlay.active{display:block;opacity:1}.mobile-menu-drawer{position:fixed;top:0;right:-280px;width:280px;height:100%;background:var(--color-background);opacity:1;box-shadow:-2px 0 8px rgba(0,0,0,.15);z-index:10000;transition:right .3s cubic-bezier(0.68, -0.55, 0.265, 1.55);overflow-y:auto;padding-top:60px}.mobile-menu-drawer.active{right:0}.mobile-menu-drawer .mobile-menu-items{list-style:none;padding:1rem 0;margin:0}.mobile-menu-drawer .mobile-menu-items li{border-bottom:1px solid var(--color-border-table-cell)}.mobile-menu-drawer .mobile-menu-items li>*{display:block;padding:1rem 1.5rem;color:var(--color-text);text-decoration:none;font-weight:500;transition:background .2s ease}.mobile-menu-drawer .mobile-menu-items li>*:hover{background:var(--color-background-menu-link-hover)}.logo-cdio{font-weight:bold;font-size:1.1rem}.logo-cdio .logo-cd{color:var(--color-grey-500)}.logo-cdio .logo-io{color:var(--color-text)}.menu-always-visible{display:flex;align-items:center;gap:.5rem;margin-left:auto}@media only screen and (max-width: 980px){#top-right-menu .menu-collapsible{display:none !important}.pure-menu-horizontal{overflow-x:visible !important}#nav-menu{overflow-x:visible !important}}@media only screen and (min-width: 1025px){.hamburger-menu,.mobile-menu-drawer,.mobile-menu-overlay{display:none !important}}html[data-darkmode=true] .mobile-menu-drawer{box-shadow:-2px 0 8px rgba(0,0,0,.4)}#search-modal .modal-body{padding:2rem 1.5rem}#search-modal .modal-body .pure-control-group{padding-bottom:0}#search-modal .modal-body .pure-control-group label{display:block;margin-bottom:.5rem;font-size:.9rem;font-weight:600;color:var(--color-text)}#search-modal .modal-body .pure-control-group #search-modal-input{width:100%;max-width:100%;box-sizing:border-box;padding:.6rem .8rem;font-size:1rem;border:1px solid var(--color-border-input);border-radius:4px;background-color:var(--color-background-input);color:var(--color-text-input);box-shadow:inset 0 1px 3px var(--color-shadow-input);transition:border-color .2s ease,box-shadow .2s ease}#search-modal .modal-body .pure-control-group #search-modal-input:focus{outline:none;border-color:var(--color-link);box-shadow:0 0 0 3px rgba(27,152,248,.1)}#search-modal .modal-body .pure-control-group #search-modal-input::placeholder{color:var(--color-text-input-placeholder);opacity:.7}html[data-darkmode=true] #search-modal #search-modal-input:focus{box-shadow:0 0 0 3px rgba(89,189,251,.15)}.action-sidebar-item{position:relative}.action-sidebar-item .notification-bubble{position:absolute;top:8px;left:8px;min-width:18px;height:18px;background:#f44;color:#fff;font-size:10px;font-weight:700;line-height:18px;text-align:center;border-radius:9px;padding:0 2px;box-shadow:0 2px 4px rgba(0,0,0,.3);pointer-events:none;transition:all .2s ease;display:none}.action-sidebar-item .notification-bubble.red-bubble{background:#f44}.action-sidebar-item .notification-bubble.blue-bubble{background:#4a9eff;color:#fff}.action-sidebar-item .notification-bubble.visible{display:block}.action-sidebar-item .notification-bubble.pulse{animation:bubblePulse .4s ease-out}.action-sidebar-item .notification-bubble.large-number{font-size:8px;min-width:20px;height:20px;line-height:20px;border-radius:10px}@keyframes bubblePulse{0%{transform:scale(1)}50%{transform:scale(1.3)}100%{transform:scale(1)}}html[data-darkmode=true] .notification-bubble{box-shadow:0 2px 6px rgba(0,0,0,.6)}.toast-container{position:fixed;display:flex;flex-direction:column;gap:.75rem;pointer-events:none;z-index:10000}.toast-container.toast-top-right{top:20px;right:20px}.toast-container.toast-top-center{top:100px;left:50%;transform:translateX(-50%)}.toast-container.toast-top-left{top:20px;left:20px}.toast-container.toast-bottom-right{bottom:20px;right:20px}.toast-container.toast-bottom-center{bottom:20px;left:50%;transform:translateX(-50%)}.toast-container.toast-bottom-left{bottom:20px;left:20px}.toast{position:relative;display:flex;align-items:center;gap:.75rem;min-width:300px;max-width:500px;padding:1rem 1.25rem;background:var(--color-background);border-radius:8px;box-shadow:0 4px 12px rgba(0,0,0,.15),0 0 0 1px rgba(0,0,0,.05);pointer-events:auto;overflow:hidden;opacity:0;transform:translateY(-50px);transition:all .3s cubic-bezier(0.68, -0.55, 0.265, 1.55);font-family:inherit}.toast.toast-show{opacity:1;transform:translateY(0)}.toast.toast-hide{opacity:0;transform:translateY(-50px) scale(0.95)}.toast.toast-success{border-left:4px solid #10b981}.toast.toast-success .toast-icon{color:#10b981}.toast.toast-error{border-left:4px solid #ef4444}.toast.toast-error .toast-icon{color:#ef4444}.toast.toast-warning{border-left:4px solid #f59e0b}.toast.toast-warning .toast-icon{color:#f59e0b}.toast.toast-info{border-left:4px solid #3b82f6}.toast.toast-info .toast-icon{color:#3b82f6}.toast.toast-default{border-left:4px solid var(--color-grey-500)}.toast-icon{flex-shrink:0;width:24px;height:24px}.toast-icon svg{width:100%;height:100%}.toast-message{flex:1;font-size:.875rem;line-height:1.5;color:var(--color-text);word-break:break-word;font-family:inherit}.toast-close{flex-shrink:0;width:24px;height:24px;display:flex;align-items:center;justify-content:center;background:rgba(0,0,0,0);border:none;border-radius:4px;color:var(--color-grey-500);font-size:1.5rem;line-height:1;cursor:pointer;transition:all .2s ease;padding:0;margin-left:.25rem}.toast-close:hover{background:var(--color-grey-800);color:var(--color-text)}.toast-close:active{transform:scale(0.95)}.toast-progress{position:absolute;bottom:0;left:0;right:0;height:3px;background:currentColor;opacity:.3;transform-origin:left;transition:transform linear}html[data-darkmode=true] .toast{background:var(--color-grey-300);box-shadow:0 4px 12px rgba(0,0,0,.4),0 0 0 1px hsla(0,0%,100%,.05)}html[data-darkmode=true] .toast-close:hover{background:var(--color-grey-400)}@media only screen and (max-width: 768px){.toast-container{left:10px !important;right:10px !important;top:10px !important;transform:none !important;align-items:stretch}.toast-container.toast-bottom-right,.toast-container.toast-bottom-center,.toast-container.toast-bottom-left{top:auto !important;bottom:10px !important}.toast{min-width:auto;max-width:none;width:100%;transform:translateY(-100px)}.toast.toast-show{transform:translateY(0)}.toast.toast-hide{transform:translateY(-100px) scale(0.95)}}@media(prefers-reduced-motion: reduce){.toast{transition:opacity .2s ease;transform:none !important}.toast.toast-show{opacity:1}.toast.toast-hide{opacity:0}}.login-form{min-height:52vh;display:flex;align-items:center;justify-content:center;padding:2rem 1rem}.login-form .inner{background:var(--color-background);border-radius:16px;box-shadow:0 10px 40px rgba(0,0,0,.08),0 2px 8px rgba(0,0,0,.04);padding:3rem 2.5rem;width:100%;max-width:420px;position:relative;overflow:hidden;transition:transform .3s ease,box-shadow .3s ease}.login-form .inner:hover{box-shadow:0 15px 50px rgba(0,0,0,.12),0 5px 15px rgba(0,0,0,.06)}.login-form form{margin:0}.login-form fieldset{border:none;padding:0;margin:0}.login-form .pure-control-group{margin-bottom:1.75rem}.login-form .pure-control-group:last-of-type{margin-bottom:0;margin-top:2rem}.login-form label{display:block;margin-bottom:.5rem;font-weight:600;font-size:.9rem;color:var(--color-text);letter-spacing:.01em}.login-form input[type=password]{width:100%;padding:.875rem 1rem;border:2px solid var(--color-grey-800);border-radius:8px;font-size:1rem;background:var(--color-background-input);color:var(--color-text-input);transition:all .2s ease;box-sizing:border-box}.login-form input[type=password]:focus{outline:none;border-color:var(--color-link);box-shadow:0 0 0 3px rgba(27,152,248,.1);transform:translateY(-1px)}.login-form input[type=password]::placeholder{color:var(--color-text-input-placeholder)}.login-form button[type=submit]{width:100%;padding:.875rem 1.5rem;font-size:1rem;font-weight:600;border-radius:8px;border:none;background:var(--color-background-button-primary);color:var(--color-text-button);cursor:pointer;transition:all .2s ease;box-shadow:0 2px 8px rgba(27,152,248,.2)}.login-form button[type=submit]:hover{box-shadow:0 4px 12px rgba(27,152,248,.3);background:#06c}.login-form button[type=submit]:active{transform:translateY(0);box-shadow:0 2px 4px rgba(27,152,248,.2)}.content-main>ul.messages{position:fixed;top:120px;left:50%;transform:translateX(-50%);list-style:none;padding:0;margin:0;z-index:1000;min-width:300px;max-width:500px}.content-main>ul.messages li{padding:1rem 1.25rem;border-radius:8px;font-size:.95rem;line-height:1.5;font-weight:500;box-shadow:0 4px 12px rgba(0,0,0,.15);animation:slideDown .3s ease-out;border:2px solid rgba(0,0,0,0)}.content-main>ul.messages li.error{background:#fee;border:2px solid #ef4444;color:#991b1b;font-weight:600}.content-main>ul.messages li.success{background:#f0fdf4;border:2px solid #10b981;color:#166534}.content-main>ul.messages li.info,.content-main>ul.messages li.message{background:#eff6ff;border:2px solid #3b82f6;color:#1e40af}@keyframes slideDown{from{opacity:0;transform:translateY(-20px)}to{opacity:1;transform:translateY(0)}}html[data-darkmode=true] .login-form .inner{box-shadow:0 10px 40px rgba(0,0,0,.4),0 2px 8px rgba(0,0,0,.2)}html[data-darkmode=true] .login-form .inner:hover{box-shadow:0 15px 50px rgba(0,0,0,.5),0 5px 15px rgba(0,0,0,.3)}html[data-darkmode=true] .login-form input[type=password]{border-color:var(--color-grey-400)}html[data-darkmode=true] .login-form input[type=password]:focus{border-color:var(--color-link)}html[data-darkmode=true] .content-main>ul.messages li{box-shadow:0 4px 12px rgba(0,0,0,.4)}html[data-darkmode=true] .content-main>ul.messages li.error{background:#4a1d1d;border-color:#ef4444;color:#fca5a5}html[data-darkmode=true] .content-main>ul.messages li.success{background:#1a3a2a;border-color:#10b981;color:#86efac}html[data-darkmode=true] .content-main>ul.messages li.info,html[data-darkmode=true] .content-main>ul.messages li.message{background:#1e3a5f;border-color:#3b82f6;color:#93c5fd}@media only screen and (max-width: 768px){.login-form{min-height:auto;padding:1rem .5rem;padding-top:5rem}.login-form .inner{padding:2rem 1.5rem;border-radius:12px}.content-main>ul.messages{top:70px;left:10px;right:10px;transform:none;min-width:auto}}body.wrapped-tabs .tabs ul{grid-template-columns:repeat(auto-fill, minmax(var(--tab-width, 180px), 1fr));grid-auto-flow:row;grid-auto-columns:unset;gap:0;column-gap:5px}body.wrapped-tabs .tabs ul li{border-radius:0}.tabs ul{margin:0px;padding:0px;display:grid;grid-auto-flow:column;grid-auto-columns:max-content;gap:5px;list-style:none}.tabs ul li{white-space:nowrap;color:var(--color-text-tab);border-top-left-radius:5px;border-top-right-radius:5px;background-color:var(--color-background-tab)}.tabs ul li:not(.active):hover{background-color:var(--color-background-tab-hover)}.tabs ul li.active,.tabs ul li :target{background-color:var(--color-background)}.tabs ul li.active a,.tabs ul li :target a{color:var(--color-text-tab-active);font-weight:bold}.tabs ul li a{display:block;padding:.7em;color:var(--color-text-tab)}body{color:var(--color-text);background:var(--color-background-page);font-family:Helvetica Neue,Helvetica,Lucida Grande,Arial,Ubuntu,Cantarell,Fira Sans,sans-serif}.visually-hidden{clip:rect(0 0 0 0);clip-path:inset(50%);height:1px;overflow:hidden;position:absolute;white-space:nowrap;width:1px}.status-icon{display:inline-block;height:1rem;vertical-align:middle}.pure-table-even{background:var(--color-background)}a{text-decoration:none;color:var(--color-link)}a.github-link{color:var(--color-icon-github);margin:0 1rem 0 .5rem}a.github-link svg{fill:currentColor}a.github-link:hover{color:var(--color-icon-github-hover)}#search-result-info{color:#fff}button.toggle-button{vertical-align:middle;background:rgba(0,0,0,0);border:none;cursor:pointer;color:var(--color-icon-github)}button.toggle-button:hover{color:var(--color-icon-github-hover)}button.toggle-button svg{fill:currentColor}button.toggle-button .icon-light{display:block}.pure-menu-horizontal{background:var(--color-background);padding:5px;display:flex;justify-content:space-between;align-items:center}#pure-menu-horizontal-spinner{height:3px;background:linear-gradient(-75deg, #ff6000, #ff8f00, #ffdd00, #ed0000);background-size:400% 400%;width:100%;animation:gradient 200s ease infinite}body.spinner-active #pure-menu-horizontal-spinner{animation:gradient 1s ease infinite}@keyframes gradient{0%{background-position:0% 50%}50%{background-position:100% 50%}100%{background-position:0% 50%}}.pure-menu-heading{color:var(--color-text-menu-heading)}.pure-menu-link{color:var(--color-text-menu-link)}.pure-menu-link:hover{background-color:var(--color-background-menu-link-hover);color:var(--color-text-menu-link-hover)}.tab-pane-inner{scroll-margin-top:200px}section.content{padding-bottom:1em;flex-direction:column;display:flex;align-items:center;justify-content:center}@media only screen and (max-width: 980px){section.content{padding-top:80px}}@media only screen and (min-width: 980px){section.content{padding-top:100px}}code{background:var(--color-background-code);color:var(--color-text)}.inline-tag,.restock-label,.tracking-ldjson-price-data,.watch-tag-list,.processor-badge{white-space:nowrap;border-radius:5px;padding:2px 5px;margin-right:4px;line-height:1.2rem}.processor-badge{font-weight:900}.watch-tag-list{color:var(--color-white);background:var(--color-text-watch-tag-list)}@media(min-width: 768px){.box{margin:0 1em !important}}.box{max-width:100%;margin:0 .3em;flex-direction:column;display:flex;justify-content:center}body:after{content:"";background:linear-gradient(130deg, var(--color-background-gradient-first), var(--color-background-gradient-second) 41.07%, var(--color-background-gradient-third) 84.05%)}body:after,body:before{display:block;height:650px;position:absolute;top:0;left:0;width:100%;z-index:-1}body::after{opacity:.91}body::before{content:""}body:after,body:before{-webkit-clip-path:polygon(100% 0, 0 0, 0 77.5%, 1% 77.4%, 2% 77.1%, 3% 76.6%, 4% 75.9%, 5% 75.05%, 6% 74.05%, 7% 72.95%, 8% 71.75%, 9% 70.55%, 10% 69.3%, 11% 68.05%, 12% 66.9%, 13% 65.8%, 14% 64.8%, 15% 64%, 16% 63.35%, 17% 62.85%, 18% 62.6%, 19% 62.5%, 20% 62.65%, 21% 63%, 22% 63.5%, 23% 64.2%, 24% 65.1%, 25% 66.1%, 26% 67.2%, 27% 68.4%, 28% 69.65%, 29% 70.9%, 30% 72.15%, 31% 73.3%, 32% 74.35%, 33% 75.3%, 34% 76.1%, 35% 76.75%, 36% 77.2%, 37% 77.45%, 38% 77.5%, 39% 77.3%, 40% 76.95%, 41% 76.4%, 42% 75.65%, 43% 74.75%, 44% 73.75%, 45% 72.6%, 46% 71.4%, 47% 70.15%, 48% 68.9%, 49% 67.7%, 50% 66.55%, 51% 65.5%, 52% 64.55%, 53% 63.75%, 54% 63.15%, 55% 62.75%, 56% 62.55%, 57% 62.5%, 58% 62.7%, 59% 63.1%, 60% 63.7%, 61% 64.45%, 62% 65.4%, 63% 66.45%, 64% 67.6%, 65% 68.8%, 66% 70.05%, 67% 71.3%, 68% 72.5%, 69% 73.6%, 70% 74.65%, 71% 75.55%, 72% 76.35%, 73% 76.9%, 74% 77.3%, 75% 77.5%, 76% 77.45%, 77% 77.25%, 78% 76.8%, 79% 76.2%, 80% 75.4%, 81% 74.45%, 82% 73.4%, 83% 72.25%, 84% 71.05%, 85% 69.8%, 86% 68.55%, 87% 67.35%, 88% 66.2%, 89% 65.2%, 90% 64.3%, 91% 63.55%, 92% 63%, 93% 62.65%, 94% 62.5%, 95% 62.55%, 96% 62.8%, 97% 63.3%, 98% 63.9%, 99% 64.75%, 100% 65.7%);clip-path:polygon(100% 0, 0 0, 0 77.5%, 1% 77.4%, 2% 77.1%, 3% 76.6%, 4% 75.9%, 5% 75.05%, 6% 74.05%, 7% 72.95%, 8% 71.75%, 9% 70.55%, 10% 69.3%, 11% 68.05%, 12% 66.9%, 13% 65.8%, 14% 64.8%, 15% 64%, 16% 63.35%, 17% 62.85%, 18% 62.6%, 19% 62.5%, 20% 62.65%, 21% 63%, 22% 63.5%, 23% 64.2%, 24% 65.1%, 25% 66.1%, 26% 67.2%, 27% 68.4%, 28% 69.65%, 29% 70.9%, 30% 72.15%, 31% 73.3%, 32% 74.35%, 33% 75.3%, 34% 76.1%, 35% 76.75%, 36% 77.2%, 37% 77.45%, 38% 77.5%, 39% 77.3%, 40% 76.95%, 41% 76.4%, 42% 75.65%, 43% 74.75%, 44% 73.75%, 45% 72.6%, 46% 71.4%, 47% 70.15%, 48% 68.9%, 49% 67.7%, 50% 66.55%, 51% 65.5%, 52% 64.55%, 53% 63.75%, 54% 63.15%, 55% 62.75%, 56% 62.55%, 57% 62.5%, 58% 62.7%, 59% 63.1%, 60% 63.7%, 61% 64.45%, 62% 65.4%, 63% 66.45%, 64% 67.6%, 65% 68.8%, 66% 70.05%, 67% 71.3%, 68% 72.5%, 69% 73.6%, 70% 74.65%, 71% 75.55%, 72% 76.35%, 73% 76.9%, 74% 77.3%, 75% 77.5%, 76% 77.45%, 77% 77.25%, 78% 76.8%, 79% 76.2%, 80% 75.4%, 81% 74.45%, 82% 73.4%, 83% 72.25%, 84% 71.05%, 85% 69.8%, 86% 68.55%, 87% 67.35%, 88% 66.2%, 89% 65.2%, 90% 64.3%, 91% 63.55%, 92% 63%, 93% 62.65%, 94% 62.5%, 95% 62.55%, 96% 62.8%, 97% 63.3%, 98% 63.9%, 99% 64.75%, 100% 65.7%)}.button-small{font-size:85%}.button-xsmall{font-size:70%}.fetch-error{padding-top:1em;font-size:80%;max-width:400px;display:block}.pure-button-primary,a.pure-button-primary,.pure-button-selected,a.pure-button-selected{background-color:var(--color-background-button-primary)}.button-secondary{color:var(--color-text-button);border-radius:4px;text-shadow:0 1px 1px rgba(0,0,0,.2)}.button-success{background:var(--color-background-button-success)}.button-tag{background:var(--color-background-button-tag);color:var(--color-text-button);font-size:65%;border-bottom-left-radius:initial;border-bottom-right-radius:initial;margin-right:4px}.button-tag.active{background:var(--color-background-button-tag-active);font-weight:bold}.button-error{background:var(--color-background-button-error);color:var(--color-text-button-error)}.button-warning{background:var(--color-background-button-warning);color:var(--color-text-button-warning)}.button-secondary{background:var(--color-background-button-secondary)}.button-cancel{background:var(--color-background-button-cancel)}.messages li{list-style:none;padding:1em;border-radius:10px;color:var(--color-text-messages);font-weight:bold}.messages li.message{background:var(--color-background-messages-message)}.messages li.error{background:var(--color-background-messages-error)}.messages li.notice{background:var(--color-background-messages-notice)}.messages.with-share-link>*:hover{cursor:pointer}.notifications-wrapper{padding-top:.5rem}.notifications-wrapper #notification-test-log{margin-top:1rem;padding:1rem;white-space:pre-wrap;word-break:break-word;overflow-wrap:break-word;max-width:100%;box-sizing:border-box;max-height:12rem;overflow-y:scroll;border:1px solid var(--color-border-notification);border-radius:5px}label:hover{cursor:pointer}.grey-form-border{border:1px solid var(--color-border-notification);padding:.5rem;border-radius:5px}#notification-error-log{border:1px solid var(--color-border-notification);padding:1rem;border-radius:5px;overflow-wrap:break-word}#token-table.pure-table td,#token-table.pure-table th{font-size:80%}.pure-form input[type=text].transparent-field{background-color:var(--color-background-new-watch-input-transparent) !important;color:var(--color-white) !important;border:1px solid hsla(0,0%,100%,.2) !important;box-shadow:none !important;-webkit-box-shadow:none !important}.pure-form input[type=text].transparent-field::placeholder{opacity:.5;color:hsla(0,0%,100%,.7);font-weight:lighter}#new-watch-form{background:var(--color-background-new-watch-form);padding:1em;border-radius:10px;margin-bottom:1em;max-width:100%}#new-watch-form #url::placeholder{font-weight:bold}#new-watch-form input{display:inline-block;margin-bottom:5px}#new-watch-form input:not(.pure-button){background-color:var(--color-background-new-watch-input);color:var(--color-text-new-watch-input)}#new-watch-form .label{display:none}#new-watch-form legend{color:var(--color-text-legend);font-weight:bold}@media only screen and (min-width: 760px){#new-watch-form #watch-add-wrapper-zone{display:flex;gap:.3rem;flex-direction:row;min-width:70vw}}#new-watch-form #watch-add-wrapper-zone>span{flex-grow:0}#new-watch-form #watch-add-wrapper-zone>span input{width:100%;padding-right:1em}#new-watch-form #watch-add-wrapper-zone>span:first-child{flex-grow:1}@media only screen and (max-width: 760px){#new-watch-form #watch-add-wrapper-zone #url{width:100%}}#new-watch-form #watch-group-tag{font-size:.9rem;padding:.3rem;display:flex;align-items:center;gap:.5rem;color:var(--color-white)}#new-watch-form #watch-group-tag label,#new-watch-form #watch-group-tag input{margin:0}#new-watch-form #watch-group-tag input{flex:1}#diff-col{padding-left:40px}#diff-jump{position:fixed;left:0px;top:120px;background:var(--color-background);padding:10px;border-top-right-radius:5px;border-bottom-right-radius:5px;box-shadow:1px 1px 4px var(--color-shadow-jump)}#diff-jump a{color:var(--color-link);cursor:pointer;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none;user-select:none;-o-user-select:none}footer{padding:10px;background:var(--color-background);color:var(--color-text-footer);text-align:center}#feed-icon{vertical-align:middle}.sticky-tab{position:absolute;top:60px;font-size:65%;background:var(--color-background);padding:10px}@media only screen and (max-width: 980px){.sticky-tab{display:none}}.sticky-tab#left-sticky{left:0;position:fixed;border-top-right-radius:5px;border-bottom-right-radius:5px;box-shadow:1px 1px 4px var(--color-shadow-jump)}.sticky-tab#right-sticky{right:0px}.sticky-tab#hosted-sticky{right:0px;top:100px;font-weight:bold}#new-version-text a{color:var(--color-link-new-version)}.watch-controls{color:#f8321b}.watch-controls .state-on img{opacity:.8}.watch-controls img{opacity:.2}.watch-controls img:hover{transition:opacity .3s;opacity:.8}.monospaced-textarea textarea{width:100%;font-family:monospace;white-space:pre;overflow-wrap:normal;overflow-x:auto}.pure-form fieldset{padding-top:0px}.pure-form fieldset ul{padding-bottom:0px;margin-bottom:0px}.pure-form .pure-control-group,.pure-form .pure-group,.pure-form .pure-controls{padding-bottom:1em}.pure-form .pure-control-group div,.pure-form .pure-group div,.pure-form .pure-controls div{margin:0px}.pure-form .pure-control-group .checkbox>*,.pure-form .pure-group .checkbox>*,.pure-form .pure-controls .checkbox>*{display:inline;vertical-align:middle}.pure-form .pure-control-group .checkbox>label,.pure-form .pure-group .checkbox>label,.pure-form .pure-controls .checkbox>label{padding-left:5px}.pure-form .pure-control-group legend,.pure-form .pure-group legend,.pure-form .pure-controls legend{color:var(--color-text-legend)}.pure-form .error input{background-color:var(--color-error-input)}.pure-form ul.errors{padding:.5em .6em;border:1px solid var(--color-error-list);border-radius:4px;vertical-align:middle;-webkit-box-sizing:border-box;box-sizing:border-box}.pure-form ul.errors li{margin-left:1em;color:var(--color-error-list)}.pure-form label{font-weight:bold}.pure-form textarea{width:100%}.pure-form .inline-radio ul{margin:0px;list-style:none}.pure-form .inline-radio ul li{display:flex;align-items:center;gap:1em}@media only screen and (max-width: 760px),(min-device-width: 768px)and (max-device-width: 980px){.edit-form{padding:.5em;margin:0}#nav-menu{overflow-x:scroll}}@media only screen and (max-width: 760px),(min-device-width: 768px)and (max-device-width: 980px){input[type=text]{width:100%}}.pure-table{border-color:var(--color-border-table-cell)}.pure-table thead{background-color:var(--color-background-table-thead);color:var(--color-text);border-bottom:1px solid var(--color-background-table-thead)}.pure-table td,.pure-table th{border-left-color:var(--color-border-table-cell)}.pure-table-striped tr:nth-child(2n-1) td{background-color:var(--color-table-stripe)}.pure-form input[type=color],.pure-form input[type=date],.pure-form input[type=datetime-local],.pure-form input[type=datetime],.pure-form input[type=email],.pure-form input[type=month],.pure-form input[type=number],.pure-form input[type=password],.pure-form input[type=search],.pure-form input[type=tel],.pure-form input[type=text],.pure-form input[type=time],.pure-form input[type=url],.pure-form input[type=week],.pure-form select,.pure-form textarea{border:var(--color-border-input);box-shadow:inset 0 1px 3px var(--color-shadow-input);background-color:var(--color-background-input);color:var(--color-text-input)}.pure-form input[type=color]:active,.pure-form input[type=date]:active,.pure-form input[type=datetime-local]:active,.pure-form input[type=datetime]:active,.pure-form input[type=email]:active,.pure-form input[type=month]:active,.pure-form input[type=number]:active,.pure-form input[type=password]:active,.pure-form input[type=search]:active,.pure-form input[type=tel]:active,.pure-form input[type=text]:active,.pure-form input[type=time]:active,.pure-form input[type=url]:active,.pure-form input[type=week]:active,.pure-form select:active,.pure-form textarea:active{background-color:var(--color-background-input)}input::placeholder,textarea::placeholder{color:var(--color-text-input-placeholder)}.m-d{min-width:100%}@media only screen and (min-width: 761px){.m-d{min-width:80%}}.pure-form-stacked>div:first-child{display:block}.tab-pane-inner{padding:0px}.tab-pane-inner:not(:target){display:none}.tab-pane-inner:target{display:block}.beta-logo{height:50px;right:-3px;top:-3px;position:absolute}#selector-header{padding-bottom:1em}body.full-width .edit-form{width:95%}.edit-form{min-width:70%;max-width:95%}.edit-form .box-wrap{position:relative}.edit-form .inner{background:var(--color-background);padding:20px}.edit-form #actions{display:block;background:var(--color-background)}.edit-form #actions .pure-control-group{display:flex;gap:.625em;flex-wrap:wrap}.edit-form .pure-form-message-inline{padding-left:0;color:var(--color-text-input-description)}.edit-form .pure-form-message-inline code{font-size:.875em}.border-fieldset{border:1px solid #ccc;padding:1rem;border-radius:5px;margin-bottom:1rem}.border-fieldset h3{margin-top:0}.border-fieldset fieldset:last-of-type{padding-bottom:0}.border-fieldset fieldset:last-of-type .pure-control-group{padding-bottom:0}ul{padding-left:1em;padding-top:0px;margin-top:4px}.time-check-widget tr{display:inline}.time-check-widget tr input[type=number]{width:5em}@media only screen and (max-width: 760px){.time-check-widget tbody{display:grid;grid-template-columns:auto 1fr auto 1fr;gap:.625em .3125em;align-items:center}.time-check-widget tr{display:contents}.time-check-widget tr th{text-align:right;padding-right:5px}.time-check-widget tr input[type=number]{width:100%;max-width:5em}}#webdriver_delay{width:5em}#api-key:hover{cursor:pointer}#api-key-copy{color:var(--color-api-key)}.button-green{background-color:var(--color-background-button-green)}.button-red{background-color:var(--color-background-button-red)}.noselect{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}#checkbox-operations{background:var(--color-background-checkbox-operations);padding:1em;border-radius:10px;margin-bottom:1em;display:none}#checkbox-operations button{margin-bottom:3px;margin-top:3px;display:inline-flex;align-items:center}.checkbox-uuid>*{vertical-align:middle}.inline-warning{border:1px solid var(--color-border-warning);padding:.5rem;border-radius:5px;color:var(--color-warning)}.inline-warning>span{display:inline-block;vertical-align:middle}.inline-warning img.inline-warning-icon{display:inline;height:26px;vertical-align:middle}.tracking-ldjson-price-data{background-color:var(--color-background-button-green);color:#000;opacity:.6}.ldjson-price-track-offer{font-weight:bold;font-style:italic}.ldjson-price-track-offer a.pure-button{border-radius:3px;padding:3px;background-color:var(--color-background-button-green)}.price-follow-tag-icon{display:inline-block;height:.8rem;vertical-align:middle}#quick-watch-processor-type ul#processor{color:#fff;padding-left:0px}#quick-watch-processor-type ul#processor li{list-style:none;font-size:.9rem;display:grid;grid-template-columns:auto 1fr;align-items:center;gap:.5rem;margin-bottom:.5rem}#quick-watch-processor-type label,#quick-watch-processor-type input{padding:0;margin:0}.restock-label.in-stock{background-color:var(--color-background-button-green);color:#fff}.restock-label.not-in-stock{background-color:var(--color-background-button-cancel);color:#777}.restock-label.error{background-color:var(--color-background-button-error);color:#fff;opacity:.7}.restock-label svg{vertical-align:middle}#chrome-extension-link{padding:9px;border:1px solid var(--color-grey-800);border-radius:10px;vertical-align:middle}#chrome-extension-link img{height:21px;padding:2px;vertical-align:middle}#realtime-conn-error{position:fixed;bottom:0;left:0;background:var(--color-warning);padding:10px;font-size:.8rem;color:#fff;opacity:.8}#bottom-horizontal-offscreen{position:fixed;bottom:0;left:0;right:0;width:100%;min-height:50px;max-height:50vh;background:hsla(0,0%,100%,.7215686275);border-top:1px solid var(--color-border-table-cell);padding:10px;box-shadow:0 -2px 10px rgba(0,0,0,.2);z-index:100;overflow-y:auto;transition:opacity .3s ease-in-out;scroll-margin-bottom:10px;display:flex;justify-content:center;align-items:center}ul#highlightSnippetActions{list-style:none}ul#highlightSnippetActions li{display:inline-block} From 32149640d9a8f2bda5df30fb73dfa6d08008ab3c Mon Sep 17 00:00:00 2001 From: dgtlmoon <dgtlmoon@gmail.com> Date: Thu, 15 Jan 2026 20:56:53 +0100 Subject: [PATCH 10/11] Selenium fetcher - Small fix for #3748 RGB error on transparent screenshots or similar (#3749) --- changedetectionio/content_fetchers/webdriver_selenium.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/changedetectionio/content_fetchers/webdriver_selenium.py b/changedetectionio/content_fetchers/webdriver_selenium.py index 73c6dad40..eebf10579 100644 --- a/changedetectionio/content_fetchers/webdriver_selenium.py +++ b/changedetectionio/content_fetchers/webdriver_selenium.py @@ -156,6 +156,9 @@ class fetcher(Fetcher): from PIL import Image import io img = Image.open(io.BytesIO(screenshot_png)) + # Convert to RGB if needed (JPEG doesn't support transparency) + if img.mode != 'RGB': + img = img.convert('RGB') jpeg_buffer = io.BytesIO() img.save(jpeg_buffer, format='JPEG', quality=int(os.getenv("SCREENSHOT_QUALITY", 72))) self.screenshot = jpeg_buffer.getvalue() From c86f214fc3349679e4a120bc9d0b0f99ee78086d Mon Sep 17 00:00:00 2001 From: dgtlmoon <dgtlmoon@gmail.com> Date: Thu, 15 Jan 2026 22:28:58 +0100 Subject: [PATCH 11/11] 0.52.6 --- changedetectionio/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changedetectionio/__init__.py b/changedetectionio/__init__.py index 424865eff..b28f6756c 100644 --- a/changedetectionio/__init__.py +++ b/changedetectionio/__init__.py @@ -2,7 +2,7 @@ # Read more https://github.com/dgtlmoon/changedetection.io/wiki # Semver means never use .01, or 00. Should be .1. -__version__ = '0.52.5' +__version__ = '0.52.6' from changedetectionio.strtobool import strtobool from json.decoder import JSONDecodeError