{# A single watch list , extracted from watch-overview.html so the same markup can be re-rendered on its own and pushed over Socket.IO (realtime row resync) - one renderer, so the row can never drift from the server-rendered list. Rendered via {% include %} from the watch list loop, which inherits the full context: watch, loop, is_checking_now(), queued_uuids, has_proxies, datastore, active_tag_uuid, system_default_fetcher, ui_settings, favicons_enabled, fetcher_status_icons, processor_descriptions, get_all_tags_for_watch(), any_has_restock_price_processor #} {%- set checking_now = is_checking_now(watch) -%} {%- set history_n = watch.history_n -%} {%- set favicon = watch.get_favicon_filename() -%} {%- set error_texts = watch.compile_error_texts(has_proxies=has_proxies) -%} {%- set system_use_url_watchlist = datastore.data['settings']['application']['ui'].get('use_page_title_in_list') -%} {# Class settings mirrored in changedetectionio/static/js/realtime.js for the frontend #} {# loop.cycle('pure-table-odd', 'pure-table-even'),#} {%- set row_classes = [ 'processor-' ~ watch['processor'], 'has-error' if error_texts|length > 2 else '', 'paused' if watch.paused is defined and watch.paused != False else '', 'unviewed' if watch.has_unviewed else '', 'has-restock-info' if watch.has_restock_info else 'no-restock-info', 'has-favicon' if favicon else '', 'in-stock' if watch.has_restock_info and watch['restock']['in_stock'] else '', 'not-in-stock' if watch.has_restock_info and not watch['restock']['in_stock'] else '', 'queued' if watch.uuid in queued_uuids else '', 'checking-now' if checking_now else '', 'notification_muted' if watch.notification_muted else '', 'single-history' if history_n == 1 else '', 'multiple-history' if history_n >= 2 else '', 'use-html-title' if system_use_url_watchlist else 'no-html-title', ] -%}
{# {{ loop.index+pagination.skip }}#}
{% if 'favicons_enabled' not in ui_settings or ui_settings['favicons_enabled'] %}
{# Intersection Observer lazy loading: store real URL in data-src, load only when visible in viewport #} Favicon thumbnail
{% endif %}
{%- if watch['processor'] and watch['processor'] in processor_badge_texts -%} {{ processor_badge_texts[watch['processor']] }} {%- endif -%} {% if system_use_url_watchlist or watch.get('use_page_title_in_list') %} {{ watch.label }} {% else %} {{ watch.get('title') or watch.link }} {% endif %}   {%- for watch_tag_uuid, watch_tag in datastore.get_all_tags_for_watch(watch['uuid']).items() -%} {{ watch_tag.title }} {%- endfor -%} {%- if watch['processor'] == 'text_json_diff' -%} {%- if watch['has_ldjson_price_data'] and not watch['track_ldjson_price_data'] -%}
Switch to Restock & Price watch mode? Yes No
{%- endif -%} {%- endif -%}
{%- set effective_fetcher = watch.get_fetch_backend if watch.get_fetch_backend != "system" else system_default_fetcher -%} {%- if effective_fetcher and ("html_webdriver" in effective_fetcher or "html_" in effective_fetcher or "extra_browser_" in effective_fetcher) -%} {{ effective_fetcher|fetcher_status_icons }} {%- endif -%} {%- if watch.is_pdf -%}Converting PDF to text{%- endif -%} {%- if watch.has_browser_steps -%}Browser Steps is enabled{%- endif -%}
{%- if watch['processor'] == 'restock_diff' -%} {#- @todo - this could be injected somehow watch.extra_row_info or something -#}
{%- if watch.has_restock_info -%} {%- if watch['restock']['in_stock']-%} {{ _('In stock') }} {%- else-%} {{ _('Not in stock') }} {%- endif -%} {%- endif -%} {%- if watch.get('restock') and watch['restock'].get('price') -%} {%- set restock = watch['restock'] -%} {%- set price = restock.get('price') -%} {%- set currency = restock.get('currency') if restock.get('currency','') else '' -%} {%- if price is not none and (price|string)|regex_search('\d') -%} {# @todo: make parse_currency/parse_decimal aware of the locale of the actual web page and use that instead changedetectionio/processors/restock_diff/__init__.py #} {%- if price is number -%}{# It's a number so we can convert it to their locale' #} {{ price|format_number_locale }} {{ currency }} {%- else -%}{# It's totally fine if it arrives as something else, the website might be something weird in this field #} {{ price }} {{ currency }} {%- endif -%} {%- set price_change_pct = restock.get_price_change_percent() -%} {%- if price_change_pct is not none -%} {%- set prev_price = restock.get('last_price') -%} {%- set prev_disp = (prev_price|format_number_locale ~ ' ' ~ currency) if prev_price is number else prev_price -%} {%- if price_change_pct < 0 -%} ▼ {{ '%g'|format(price_change_pct) }}% {%- else -%} ▲ +{{ '%g'|format(price_change_pct) }}% {%- endif -%} {%- endif -%} {%- endif -%} {%- elif not watch.has_restock_info -%} {{ _('No information') }} {%- endif -%}
{%- endif -%}
{# {%- if any_has_restock_price_processor -%} {%- endif -%} #} {#last_checked becomes fetch-start-time#} {{watch|format_last_checked_time|safe}} {%- if watch.history_n >=2 and watch.last_changed >0 -%} {{watch.last_changed|format_timestamp_timeago}} {%- else -%} {{ _('Not yet') }} {%- endif -%}
{%- set target_attr = ' target="' ~ watch.uuid ~ '"' if datastore.data['settings']['application']['ui'].get('open_diff_in_new_tab') else '' -%} {{ _('Recheck') }} {{ _('Edit') }}