feat: wire tracking-config display filters + per-tracker adaptive polling
Display filters (Immich tracking config): - favorites_only drops events with no favorited new assets, or filters added_assets to favorites only - assets_order_by/assets_order sort the rendered list (date / name / rating / random / none) - max_assets_to_show caps rendered+attached media (default 5 -> 10) - include_tags strips people from event extras and tags from each asset - include_asset_details strips city/country/state/lat/lon/is_favorite/ rating/description; load-bearing fields (thumbhash, file_size, playback_size, cache keys) preserved - New apply_tracking_display_filters helper in dispatch_helpers; wired into watcher, webhooks, scheduled/periodic/memory, and manual test-dispatch - Targets sharing a TrackingConfig dispatch together; targets with different TCs each see their own shaped event Adaptive polling: - Replace NotificationTracker.batch_duration with adaptive_max_skip - Per-tracker opt-in: NULL/0 disables back-off (every tick runs); positive N caps the skip factor at (N-1)-in-N after long idle - Scheduler caches the cap in module state for the tick fast-path - Migration adds the new column; API schemas/responses, frontend types, i18n, and the tracker form updated to match
This commit is contained in:
@@ -42,6 +42,7 @@ from ..database.models import (
|
||||
TrackingConfig,
|
||||
)
|
||||
from .dispatch_helpers import (
|
||||
apply_tracking_display_filters,
|
||||
event_allowed_by_config,
|
||||
get_app_timezone,
|
||||
load_link_data,
|
||||
@@ -251,7 +252,9 @@ async def dispatch_scheduled_for_tracker(
|
||||
# event_allowed_by_config, which inspects event timestamp. Per-event
|
||||
# rebuilding also lets a per-link override disable one kind while
|
||||
# keeping others live.
|
||||
target_configs: list[TargetConfig] = []
|
||||
# Group target configs by TrackingConfig identity so each unique TC
|
||||
# gets its own ``apply_tracking_display_filters`` pass before dispatch.
|
||||
groups: dict[int, tuple[TrackingConfig | None, list[TargetConfig]]] = {}
|
||||
async with AsyncSession(engine) as session:
|
||||
for ld in link_data:
|
||||
tc = ld["tracking_config"] or default_tc
|
||||
@@ -275,7 +278,7 @@ async def dispatch_scheduled_for_tracker(
|
||||
locale_map = {s.locale: s.template for s in slot_rows}
|
||||
template_slots = {EventType.SCHEDULED_MESSAGE.value: locale_map}
|
||||
|
||||
target_configs.append(TargetConfig(
|
||||
target_cfg = TargetConfig(
|
||||
type=ld["target_type"],
|
||||
config=ld["target_config"],
|
||||
template_slots=template_slots,
|
||||
@@ -287,20 +290,36 @@ async def dispatch_scheduled_for_tracker(
|
||||
provider_internal_url=provider_config.get("url", ""),
|
||||
provider_external_url=provider_config.get("external_domain", ""),
|
||||
receivers=ld["receivers"],
|
||||
))
|
||||
)
|
||||
key = id(tc) if tc is not None else 0
|
||||
if key not in groups:
|
||||
groups[key] = (tc, [])
|
||||
groups[key][1].append(target_cfg)
|
||||
|
||||
if not target_configs:
|
||||
if not groups:
|
||||
_LOGGER.info(
|
||||
"Scheduled %s for tracker %d (collection=%r): no targets after filtering",
|
||||
kind, tracker_id, event.collection_name,
|
||||
)
|
||||
continue
|
||||
|
||||
total_targets = sum(len(tg[1]) for tg in groups.values())
|
||||
_LOGGER.info(
|
||||
"Dispatching scheduled %s for tracker %d (collection=%r) to %d link(s)",
|
||||
kind, tracker_id, event.collection_name, len(target_configs),
|
||||
"Dispatching scheduled %s for tracker %d (collection=%r) to %d link(s) across %d group(s)",
|
||||
kind, tracker_id, event.collection_name, total_targets, len(groups),
|
||||
)
|
||||
results = await dispatcher.dispatch(event, target_configs)
|
||||
results: list = []
|
||||
dispatched_any = False
|
||||
for tc, target_configs in groups.values():
|
||||
if not target_configs:
|
||||
continue
|
||||
shaped_event = apply_tracking_display_filters(event, tc)
|
||||
if shaped_event is None:
|
||||
continue
|
||||
results.extend(await dispatcher.dispatch(shaped_event, target_configs))
|
||||
dispatched_any = True
|
||||
if not dispatched_any:
|
||||
continue
|
||||
any_sent = True
|
||||
|
||||
successes = sum(1 for r in results if isinstance(r, dict) and r.get("success"))
|
||||
@@ -322,7 +341,7 @@ async def dispatch_scheduled_for_tracker(
|
||||
"timezone": app_tz,
|
||||
"collection_mode": collection_mode,
|
||||
"status": "sent",
|
||||
"targets_dispatched": len(target_configs),
|
||||
"targets_dispatched": total_targets,
|
||||
"targets_succeeded": successes,
|
||||
},
|
||||
))
|
||||
|
||||
Reference in New Issue
Block a user