fix: persist short URLs in alert history, regenerate on expiry

Store shortened URLs in the results DB at poll time alongside the
original URL. History output uses the stored short URL directly,
only regenerating (and persisting) when no short URL exists yet.
Original URL always preserved for re-shortening if needed.
This commit is contained in:
user
2026-02-16 23:24:26 +01:00
parent c92fdbfc30
commit 3c505dd825

View File

@@ -109,9 +109,13 @@ def _db() -> sqlite3.Connection:
short_id TEXT NOT NULL DEFAULT '' short_id TEXT NOT NULL DEFAULT ''
) )
""") """)
for col, default in [
("short_id", "''"),
("short_url", "''"),
]:
try: try:
_conn.execute( _conn.execute(
"ALTER TABLE results ADD COLUMN short_id TEXT NOT NULL DEFAULT ''" f"ALTER TABLE results ADD COLUMN {col} TEXT NOT NULL DEFAULT {default}"
) )
except sqlite3.OperationalError: except sqlite3.OperationalError:
pass # column already exists pass # column already exists
@@ -133,14 +137,16 @@ def _db() -> sqlite3.Connection:
return _conn return _conn
def _save_result(channel: str, alert: str, backend: str, item: dict) -> str: def _save_result(channel: str, alert: str, backend: str, item: dict,
short_url: str = "") -> str:
"""Persist a matched result to the history database. Returns short_id.""" """Persist a matched result to the history database. Returns short_id."""
short_id = _make_short_id(backend, item.get("id", "")) short_id = _make_short_id(backend, item.get("id", ""))
db = _db() db = _db()
db.execute( db.execute(
"INSERT INTO results" "INSERT INTO results"
" (channel, alert, backend, item_id, title, url, date, found_at, short_id)" " (channel, alert, backend, item_id, title, url, date, found_at,"
" VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", " short_id, short_url)"
" VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
( (
channel, channel,
alert, alert,
@@ -151,6 +157,7 @@ def _save_result(channel: str, alert: str, backend: str, item: dict) -> str:
item.get("date", ""), item.get("date", ""),
datetime.now(timezone.utc).isoformat(), datetime.now(timezone.utc).isoformat(),
short_id, short_id,
short_url,
), ),
) )
db.commit() db.commit()
@@ -1755,23 +1762,31 @@ async def _poll_once(bot, key: str, announce: bool = True) -> None:
name = data["name"] name = data["name"]
fp = bot.registry._modules.get("flaskpaste") fp = bot.registry._modules.get("flaskpaste")
for item in matched: for item in matched:
short_id = _save_result(channel, name, tag, item)
title = _truncate(item["title"]) if item["title"] else "(no title)"
url = item["url"] url = item["url"]
display_url = url
short_url = ""
if fp and url: if fp and url:
try: try:
url = await loop.run_in_executor( short_url = await loop.run_in_executor(
None, fp.shorten_url, bot, url, None, fp.shorten_url, bot, url,
) )
if short_url != url:
display_url = short_url
else:
short_url = ""
except Exception: except Exception:
pass pass
short_id = _save_result(
channel, name, tag, item, short_url=short_url,
)
title = _truncate(item["title"]) if item["title"] else "(no title)"
date = item.get("date", "") date = item.get("date", "")
line = f"[{name}/{tag}/{short_id}]" line = f"[{name}/{tag}/{short_id}]"
if date: if date:
line += f" ({date})" line += f" ({date})"
line += f" {title}" line += f" {title}"
if url: if display_url:
line += f" -- {url}" line += f" -- {display_url}"
await bot.send(channel, line) await bot.send(channel, line)
for item in new_items: for item in new_items:
@@ -1937,7 +1952,8 @@ async def cmd_alert(bot, message):
limit = 5 limit = 5
db = _db() db = _db()
rows = db.execute( rows = db.execute(
"SELECT backend, title, url, date, found_at, short_id FROM results" "SELECT id, backend, title, url, date, found_at, short_id,"
" short_url FROM results"
" WHERE channel = ? AND alert = ? ORDER BY id DESC LIMIT ?", " WHERE channel = ? AND alert = ? ORDER BY id DESC LIMIT ?",
(channel, name, limit), (channel, name, limit),
).fetchall() ).fetchall()
@@ -1946,19 +1962,27 @@ async def cmd_alert(bot, message):
return return
loop = asyncio.get_running_loop() loop = asyncio.get_running_loop()
fp = bot.registry._modules.get("flaskpaste") fp = bot.registry._modules.get("flaskpaste")
for backend, title, url, date, found_at, short_id in reversed(rows): for row_id, backend, title, url, date, found_at, short_id, short_url in reversed(rows):
ts = found_at[:10] ts = found_at[:10]
title = _truncate(title) if title else "(no title)" title = _truncate(title) if title else "(no title)"
if fp and url: display_url = short_url or url
if fp and url and not short_url:
try: try:
url = await loop.run_in_executor( new_short = await loop.run_in_executor(
None, fp.shorten_url, bot, url, None, fp.shorten_url, bot, url,
) )
if new_short != url:
display_url = new_short
db.execute(
"UPDATE results SET short_url = ? WHERE id = ?",
(new_short, row_id),
)
db.commit()
except Exception: except Exception:
pass pass
line = f"[{name}/{backend}/{short_id}] ({date or ts}) {title}" line = f"[{name}/{backend}/{short_id}] ({date or ts}) {title}"
if url: if display_url:
line += f" -- {url}" line += f" -- {display_url}"
await bot.reply(message, line) await bot.reply(message, line)
return return