From 155d25edf98349609b2485e564de8eaf9b2ed208 Mon Sep 17 00:00:00 2001 From: "alexei.dolgolyov" Date: Wed, 22 Apr 2026 18:59:15 +0300 Subject: [PATCH] chore: release v0.3.0 --- RELEASE_NOTES.md | 32 +++++++++++++++++++++++++------- frontend/package.json | 2 +- packages/core/pyproject.toml | 2 +- packages/server/pyproject.toml | 2 +- 4 files changed, 28 insertions(+), 10 deletions(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 84865cd..a1c3b42 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,18 +1,36 @@ -# v0.2.8 (2026-04-22) +# v0.3.0 (2026-04-22) -Follow-up fix to v0.2.7's Telegram-send unification. The shared factory was -in place, but commands and notifications were still writing into different -cache-key namespaces — so in practice the caches never actually shared entries. +Major polling perf overhaul for large Immich libraries plus a UX fix for +slow bot commands. Combined impact on idle albums: per-tick cost drops +from ~150 MB fetched to a few hundred bytes; active albums now fetch +O(changes) instead of O(library). Tested against a ~200k-asset library. -## Bug Fixes +**Schema change:** adds a `meta_fingerprint` JSON column to +`notification_tracker_state` — applied automatically by the startup +migration, no manual step required. -- **Commands and notifications now share one `file_id` cache namespace** — `common._format_assets` was passing `cache_key=`, while the notification dispatcher writes keys as `:` (derived from the URL by `extract_asset_id_from_url`). The two paths populated different keys for the same asset, so neither could hit the other's cached `file_id` and the Settings → cache-stats card only ever reflected the notification side. Dropped the explicit `cache_key` — `TelegramClient` now derives `:` from the URL on both paths, so one `file_id` cached by any dispatch or `/random` / `/latest` reply is reused by every later send. ([7dae68f](https://git.dolgolyov-family.by/alexei.dolgolyov/notify-bridge/commit/7dae68f)) +## Performance + +- **Skip full album fetch on idle ticks** — new `ImmichAlbumMeta` + `get_album_meta()` probe using `?withoutAssets=true` as a cheap change-detection fingerprint. When the fingerprint matches and no pending assets are outstanding, `poll()` short-circuits and does no asset fetch at all. ([fe38d20](https://git.dolgolyov-family.by/alexei.dolgolyov/notify-bridge/commit/fe38d20)) +- **Delta-fetch active albums** — when the fingerprint changes, poll with `updatedAfter` instead of refetching the whole album; falls back to a full fetch only on count decrease or mixed add+remove that delta can't reconcile. ([fe38d20](https://git.dolgolyov-family.by/alexei.dolgolyov/notify-bridge/commit/fe38d20)) +- **Parallel meta probes** — `asyncio.gather` over album meta probes so a 20-album tracker pays one round-trip of latency instead of 20. ([fe38d20](https://git.dolgolyov-family.by/alexei.dolgolyov/notify-bridge/commit/fe38d20)) +- **Tick-scoped shared-links cache** — new `get_all_shared_links_by_album()` coalesces to one `/api/shared-links` request per tick instead of one per changed album. ([fe38d20](https://git.dolgolyov-family.by/alexei.dolgolyov/notify-bridge/commit/fe38d20)) +- **Module-level users cache** — 1 h TTL, sha256-keyed, shared across providers that target the same Immich server. ([fe38d20](https://git.dolgolyov-family.by/alexei.dolgolyov/notify-bridge/commit/fe38d20)) +- **Skip `asset_ids` DB rewrite on idle ticks** — watcher no longer rewrites the (potentially ~8 MB for huge albums) JSON column when the fingerprint didn't change. ([fe38d20](https://git.dolgolyov-family.by/alexei.dolgolyov/notify-bridge/commit/fe38d20)) +- **Adaptive polling** — after 10 empty ticks the scheduler skips 1-in-2, after 30 empty ticks skips 1-in-4; resets on the first detected change or any schedule edit. ([fe38d20](https://git.dolgolyov-family.by/alexei.dolgolyov/notify-bridge/commit/fe38d20)) +- **APScheduler jitter** — `interval/4`, capped at 30 s, to smooth thundering-herd bursts when many trackers share the same `scan_interval`. ([fe38d20](https://git.dolgolyov-family.by/alexei.dolgolyov/notify-bridge/commit/fe38d20)) +- **Event payload cap** — 50 added / 200 removed assets per event so a bulk import can't explode a Jinja template or exceed Telegram message limits. ([fe38d20](https://git.dolgolyov-family.by/alexei.dolgolyov/notify-bridge/commit/fe38d20)) + +## Features + +- **Chat-action hint stays alive during slow command fetches** — Telegram chat actions expire after ~5 s, so slow bot commands (`/latest`, `/random`, `/favorites`, `/memory`, `/search`, `/find`, `/person`, `/place`, `/summary`) previously showed a hint that vanished long before the media arrived and users saw nothing happening. New `telegram_chat_action` async context manager starts a keep-alive task that re-posts the action every 4 s until it exits; `classify_command_chat_action` maps each command to the right action (`upload_photo` for media-returning commands, `typing` for `/summary`, none for fast DB-only commands like `/status` / `/events`). Wired into both the webhook and long-poll paths. ([69711bb](https://git.dolgolyov-family.by/alexei.dolgolyov/notify-bridge/commit/69711bb)) ---
All Commits -- [7dae68f](https://git.dolgolyov-family.by/alexei.dolgolyov/notify-bridge/commit/7dae68f) — fix(commands): match notification cache-key format so writes share one namespace *(alexei.dolgolyov)* +- [69711bb](https://git.dolgolyov-family.by/alexei.dolgolyov/notify-bridge/commit/69711bb) — feat(commands): keep chat-action hint alive during slow command fetches *(alexei.dolgolyov)* +- [fe38d20](https://git.dolgolyov-family.by/alexei.dolgolyov/notify-bridge/commit/fe38d20) — perf(immich): skip full album fetch on idle ticks; delta-fetch for active ones *(alexei.dolgolyov)*
diff --git a/frontend/package.json b/frontend/package.json index 856da1f..25ae7e1 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,7 +1,7 @@ { "name": "notify-bridge-frontend", "private": true, - "version": "0.2.8", + "version": "0.3.0", "type": "module", "scripts": { "dev": "vite dev", diff --git a/packages/core/pyproject.toml b/packages/core/pyproject.toml index a4737bc..86913a3 100644 --- a/packages/core/pyproject.toml +++ b/packages/core/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "notify-bridge-core" -version = "0.2.8" +version = "0.3.0" description = "Core library for Notify Bridge — service provider abstractions, models, notifications, and templates" requires-python = ">=3.12" dependencies = [ diff --git a/packages/server/pyproject.toml b/packages/server/pyproject.toml index 369a3c1..5a7350a 100644 --- a/packages/server/pyproject.toml +++ b/packages/server/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "notify-bridge-server" -version = "0.2.8" +version = "0.3.0" description = "Standalone Notify Bridge server — FastAPI REST API with SQLite database" requires-python = ">=3.12" dependencies = [