mirror of
https://github.com/dgtlmoon/changedetection.io.git
synced 2025-12-01 13:52:34 +00:00
116 lines
4.9 KiB
Python
116 lines
4.9 KiB
Python
|
|
|
|
def construct_single_watch_routes(rss_blueprint, datastore):
|
|
"""
|
|
Construct RSS feed routes for single watches.
|
|
|
|
Args:
|
|
rss_blueprint: The Flask blueprint to add routes to
|
|
datastore: The ChangeDetectionStore instance
|
|
"""
|
|
|
|
@rss_blueprint.route("/watch/<string:uuid>", methods=['GET'])
|
|
def rss_single_watch(uuid):
|
|
import time
|
|
|
|
from flask import make_response, request
|
|
from feedgen.feed import FeedGenerator
|
|
from loguru import logger
|
|
|
|
from . import RSS_TEMPLATE_HTML_DEFAULT, RSS_TEMPLATE_PLAINTEXT_DEFAULT
|
|
from ._util import (validate_rss_token, get_rss_template, get_watch_label,
|
|
build_notification_context, render_notification,
|
|
populate_feed_entry, add_watch_categories)
|
|
from ...notification_service import NotificationService
|
|
|
|
"""
|
|
Display the most recent changes for a single watch as RSS feed.
|
|
Returns RSS XML with multiple entries showing diffs between consecutive snapshots.
|
|
The number of entries is controlled by the rss_diff_length setting.
|
|
"""
|
|
now = time.time()
|
|
|
|
# Validate token
|
|
is_valid, error = validate_rss_token(datastore, request)
|
|
if not is_valid:
|
|
return error
|
|
|
|
rss_content_format = datastore.data['settings']['application'].get('rss_content_format')
|
|
|
|
# Get the watch by UUID
|
|
watch = datastore.data['watching'].get(uuid)
|
|
if not watch:
|
|
return f"Watch with UUID {uuid} not found", 404
|
|
|
|
# Check if watch has at least 2 history snapshots
|
|
dates = list(watch.history.keys())
|
|
if len(dates) < 2:
|
|
return f"Watch {uuid} does not have enough history snapshots to show changes (need at least 2)", 400
|
|
|
|
# Add uuid to watch for proper functioning
|
|
watch['uuid'] = uuid
|
|
|
|
# Get the number of diffs to include (default: 5)
|
|
rss_diff_length = datastore.data['settings']['application'].get('rss_diff_length', 5)
|
|
|
|
# Calculate how many diffs we can actually show (limited by available history)
|
|
# We need at least 2 snapshots to create 1 diff
|
|
max_possible_diffs = len(dates) - 1
|
|
num_diffs = min(rss_diff_length, max_possible_diffs) if rss_diff_length > 0 else max_possible_diffs
|
|
|
|
# Create RSS feed
|
|
fg = FeedGenerator()
|
|
|
|
# Set title: use "label (url)" if label differs from url, otherwise just url
|
|
watch_url = watch.get('url', '')
|
|
watch_label = get_watch_label(datastore, watch)
|
|
|
|
if watch_label != watch_url:
|
|
feed_title = f'changedetection.io - {watch_label} ({watch_url})'
|
|
else:
|
|
feed_title = f'changedetection.io - {watch_url}'
|
|
|
|
fg.title(feed_title)
|
|
fg.description('Changes')
|
|
fg.link(href='https://changedetection.io')
|
|
|
|
# Loop through history and create RSS entries for each diff
|
|
# Add entries in reverse order because feedgen reverses them
|
|
# This way, the newest change appears first in the final RSS
|
|
|
|
notification_service = NotificationService(datastore=datastore, notification_q=False)
|
|
for i in range(num_diffs - 1, -1, -1):
|
|
# Calculate indices for this diff (working backwards from newest)
|
|
# i=0: compare dates[-2] to dates[-1] (most recent change)
|
|
# i=1: compare dates[-3] to dates[-2] (previous change)
|
|
# etc.
|
|
date_index_to = -(i + 1)
|
|
date_index_from = -(i + 2)
|
|
timestamp_to = dates[date_index_to]
|
|
timestamp_from = dates[date_index_from]
|
|
|
|
# Get template and build notification context
|
|
n_body_template = get_rss_template(datastore, watch, rss_content_format,
|
|
RSS_TEMPLATE_HTML_DEFAULT, RSS_TEMPLATE_PLAINTEXT_DEFAULT)
|
|
|
|
n_object = build_notification_context(watch, timestamp_from, timestamp_to,
|
|
watch_label, n_body_template, rss_content_format)
|
|
|
|
# Render notification with date indices
|
|
res = render_notification(n_object, notification_service, watch, datastore,
|
|
date_index_from, date_index_to)
|
|
|
|
# Create and populate feed entry
|
|
guid = f"{watch['uuid']}/{timestamp_to}"
|
|
fe = fg.add_entry()
|
|
title_suffix = f"Change @ {res['original_context']['change_datetime']}"
|
|
populate_feed_entry(fe, watch, res.get('body', ''), guid, timestamp_to,
|
|
link={'href': watch.get('url')}, title_suffix=title_suffix)
|
|
add_watch_categories(fe, watch, datastore)
|
|
|
|
response = make_response(fg.rss_str())
|
|
response.headers.set('Content-Type', 'application/rss+xml;charset=utf-8')
|
|
logger.debug(f"RSS Single watch built in {time.time()-now:.2f}s")
|
|
|
|
return response
|