Videos without a playback_url are now filtered out in all contexts: - Realtime event notifications - Scheduled assets (per_album/random mode) - Scheduled assets (combined mode) This prevents sending video entries that cannot be played back. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2042 lines
102 KiB
YAML
2042 lines
102 KiB
YAML
# Immich Album Watcher Blueprint
|
||
# Monitors Immich album changes and sends notifications when assets are added.
|
||
# Designed to be used with the `Immich Album Watcher` integration.
|
||
# See README.md for detailed documentation.
|
||
|
||
blueprint:
|
||
name: "Custom: Immich Album Watcher"
|
||
description: >
|
||
Sends notifications to multiple targets when photos/videos are added to
|
||
specified Immich albums. Monitors Immich album watcher events and filters by album name.
|
||
domain: automation
|
||
|
||
# ===========================================================================
|
||
# INPUT CONFIGURATION
|
||
# ===========================================================================
|
||
input:
|
||
|
||
# -------------------------------------------------------------------------
|
||
# Hub & Album Configuration
|
||
# -------------------------------------------------------------------------
|
||
albums_group:
|
||
name: "Hub & Albums"
|
||
collapsed: false
|
||
input:
|
||
hub_names:
|
||
name: Hub Names to Track
|
||
description: >
|
||
List of Immich hub/instance names to monitor.
|
||
Only events from matching hubs will trigger notifications.
|
||
Leave empty to track all hubs.
|
||
default: []
|
||
selector:
|
||
text:
|
||
multiple: true
|
||
|
||
album_id_entities:
|
||
name: Album ID Entities
|
||
description: >
|
||
List of sensor or input_text entities containing album IDs to monitor.
|
||
Only albums matching these IDs will trigger notifications.
|
||
Leave empty to track all albums.
|
||
Album IDs are stable and won't change if albums get renamed.
|
||
Album names and share URLs are automatically read from the entity's
|
||
`album_name` and `share_url` attributes for periodic summary notifications.
|
||
default: []
|
||
selector:
|
||
entity:
|
||
domain:
|
||
- sensor
|
||
- input_text
|
||
multiple: true
|
||
|
||
track_assets_added:
|
||
name: Track Assets Added
|
||
description: "Send notifications when assets are added to albums"
|
||
default: true
|
||
selector:
|
||
boolean:
|
||
|
||
track_assets_removed:
|
||
name: Track Assets Removed
|
||
description: "Send notifications when assets are removed from albums"
|
||
default: false
|
||
selector:
|
||
boolean:
|
||
|
||
track_images:
|
||
name: Track Images
|
||
description: "Include IMAGE assets in notifications"
|
||
default: true
|
||
selector:
|
||
boolean:
|
||
|
||
track_videos:
|
||
name: Track Videos
|
||
description: "Include VIDEO assets in notifications"
|
||
default: true
|
||
selector:
|
||
boolean:
|
||
|
||
track_album_renamed:
|
||
name: Track Album Renamed
|
||
description: "Send notifications when albums are renamed"
|
||
default: true
|
||
selector:
|
||
boolean:
|
||
|
||
track_album_deleted:
|
||
name: Track Album Deleted
|
||
description: "Send notifications when albums are deleted"
|
||
default: true
|
||
selector:
|
||
boolean:
|
||
|
||
# -------------------------------------------------------------------------
|
||
# Notification Configuration
|
||
# -------------------------------------------------------------------------
|
||
notification_group:
|
||
name: "Notification"
|
||
collapsed: false
|
||
input:
|
||
notify_targets:
|
||
name: Notification Targets
|
||
description: "Notification service entities to send messages to (select one or more)"
|
||
selector:
|
||
entity:
|
||
domain: notify
|
||
multiple: true
|
||
|
||
include_people:
|
||
name: Include People in Notification
|
||
description: "Include list of detected people in the notification message"
|
||
default: true
|
||
selector:
|
||
boolean:
|
||
|
||
include_asset_details:
|
||
name: Include Asset Details
|
||
description: "Include formatted list of added assets in the notification"
|
||
default: false
|
||
selector:
|
||
boolean:
|
||
|
||
max_assets_to_show:
|
||
name: Maximum Assets to Show in Text
|
||
description: >
|
||
Maximum number of assets to list in the text notification message
|
||
(the `{assets}` placeholder). Only applies when "Include Asset Details" is enabled.
|
||
Set to 0 for unlimited. Excess assets show as "...and X more".
|
||
Note: This is separate from "Maximum Media to Send" which controls
|
||
the actual photo/video attachments sent to Telegram.
|
||
default: 5
|
||
selector:
|
||
number:
|
||
min: 0
|
||
max: 50
|
||
mode: slider
|
||
|
||
# -------------------------------------------------------------------------
|
||
# Message Templates
|
||
# -------------------------------------------------------------------------
|
||
messages_group:
|
||
name: "Messages"
|
||
collapsed: true
|
||
input:
|
||
message_assets_added:
|
||
name: "Assets Added Message"
|
||
description: >
|
||
Message sent when assets are added to an album.
|
||
Variables: `{album_name}`, `{album_url}`, `{added_count}`, `{people}`, `{assets}`, `{video_warning}`, `{common_date}`, `{common_location}`
|
||
default: "📷 {added_count} new photo(s) added to album \"{album_name}\"{common_date}{common_location}.{people}{assets}{video_warning}"
|
||
selector:
|
||
text:
|
||
multiline: true
|
||
|
||
message_assets_removed:
|
||
name: "Assets Removed Message"
|
||
description: >
|
||
Message sent when assets are removed from an album.
|
||
Variables: `{album_name}`, `{album_url}`, `{removed_count}`
|
||
default: "🗑️ {removed_count} photo(s) removed from album \"{album_name}\"."
|
||
selector:
|
||
text:
|
||
multiline: true
|
||
|
||
message_album_renamed:
|
||
name: "Album Renamed Message"
|
||
description: >
|
||
Message sent when an album is renamed.
|
||
Variables: `{old_name}`, `{new_name}`, `{album_url}`
|
||
default: "✏️ Album \"{old_name}\" renamed to \"{new_name}\"."
|
||
selector:
|
||
text:
|
||
multiline: true
|
||
|
||
message_album_deleted:
|
||
name: "Album Deleted Message"
|
||
description: >
|
||
Message sent when an album is deleted.
|
||
Variables: `{album_name}`
|
||
default: "🗑️ Album \"{album_name}\" was deleted."
|
||
selector:
|
||
text:
|
||
multiline: true
|
||
|
||
message_people_format:
|
||
name: "People Format"
|
||
description: >
|
||
Format for the people list in notifications.
|
||
Use `{people}` as the placeholder for the comma-separated list.
|
||
Leave empty to just show people names without prefix.
|
||
default: " People: {people}."
|
||
selector:
|
||
text:
|
||
multiline: true
|
||
|
||
message_asset_image:
|
||
name: "Image Asset Template"
|
||
description: >
|
||
Template for IMAGE assets in the list. Also used for Telegram media captions.
|
||
Variables: `{filename}`, `{description}`, `{type}`, `{created}`, `{created_if_unique}`, `{owner}`, `{url}`, `{download_url}`, `{photo_url}`, `{playback_url}`, `{people}`, `{album_name}`, `{is_favorite}`, `{rating}`, `{location}`, `{location_if_unique}`, `{city}`, `{state}`, `{country}`
|
||
default: "\n • 🖼️ {filename}"
|
||
selector:
|
||
text:
|
||
multiline: true
|
||
|
||
message_asset_video:
|
||
name: "Video Asset Template"
|
||
description: >
|
||
Template for VIDEO assets in the list. Also used for Telegram media captions.
|
||
Variables: `{filename}`, `{description}`, `{type}`, `{created}`, `{created_if_unique}`, `{owner}`, `{url}`, `{download_url}`, `{photo_url}`, `{playback_url}`, `{people}`, `{album_name}`, `{is_favorite}`, `{rating}`, `{location}`, `{location_if_unique}`, `{city}`, `{state}`, `{country}`
|
||
default: "\n • 🎬 {filename}"
|
||
selector:
|
||
text:
|
||
multiline: true
|
||
|
||
message_assets_format:
|
||
name: "Assets List Format"
|
||
description: >
|
||
Format wrapper for the assets list.
|
||
Use `{assets}` as placeholder for the formatted asset items.
|
||
Use `{more_count}` for number of additional assets not shown.
|
||
default: "\nAssets:{assets}"
|
||
selector:
|
||
text:
|
||
multiline: true
|
||
|
||
message_assets_more:
|
||
name: "More Assets Message"
|
||
description: >
|
||
Message appended when there are more assets than the maximum shown.
|
||
Use `{more_count}` for the number of additional assets.
|
||
default: "\n • ...and {more_count} more"
|
||
selector:
|
||
text:
|
||
multiline: true
|
||
|
||
date_format:
|
||
name: "Date Format"
|
||
description: >
|
||
Format for displaying asset creation dates.
|
||
Uses Python strftime format codes (e.g., %Y-%m-%d %H:%M).
|
||
Note: Month names (%b, %B) use system locale (typically English).
|
||
Use numeric format (%m) for locale-independent dates.
|
||
default: "%d.%m.%Y, %H:%M UTC"
|
||
selector:
|
||
text:
|
||
|
||
common_date_template:
|
||
name: "Common Date Template"
|
||
description: >
|
||
Template for showing the common date in the header message when all assets share the same date.
|
||
Use `{date}` as the placeholder for the formatted date.
|
||
Leave empty to just show the raw date without wrapper.
|
||
default: " from {date}"
|
||
selector:
|
||
text:
|
||
|
||
date_if_unique_template:
|
||
name: "Date If Unique Template"
|
||
description: >
|
||
Template for showing dates in asset items when assets have different dates.
|
||
Use `{date}` as the placeholder for the formatted date.
|
||
Leave empty to just show the raw date without wrapper.
|
||
default: " ({date})"
|
||
selector:
|
||
text:
|
||
|
||
favorite_indicator_template:
|
||
name: "Favorite Indicator Template"
|
||
description: >
|
||
Template for showing favorite indicator in asset items.
|
||
This will be shown when an asset is marked as favorite.
|
||
Leave empty to not show favorite indicators.
|
||
default: "❤️"
|
||
selector:
|
||
text:
|
||
|
||
common_location_template:
|
||
name: "Common Location Template"
|
||
description: >
|
||
Template for showing the common location in the header message when all assets
|
||
share the same location. Only used when ALL location fields (city, state, country)
|
||
are present for all assets. Use `{location}` as the placeholder.
|
||
Leave empty to not show common location in header.
|
||
default: " in {location}"
|
||
selector:
|
||
text:
|
||
|
||
location_if_unique_template:
|
||
name: "Location If Unique Template"
|
||
description: >
|
||
Template for showing location in asset items when assets have different locations.
|
||
Only used when ALL location fields (city, state, country) are present.
|
||
Use `{location}` as the placeholder.
|
||
Leave empty to not show per-asset locations.
|
||
default: " 📍 {location}"
|
||
selector:
|
||
text:
|
||
|
||
location_format:
|
||
name: "Location Format"
|
||
description: >
|
||
Format for displaying asset locations. Available placeholders:
|
||
`{city}`, `{state}`, `{country}`. Only shown when all three fields are present.
|
||
default: "{city}, {country}"
|
||
selector:
|
||
text:
|
||
|
||
# -------------------------------------------------------------------------
|
||
# Telegram Media Attachments
|
||
# -------------------------------------------------------------------------
|
||
telegram_group:
|
||
name: "Telegram Media"
|
||
description: "Send photos/videos as Telegram attachments (requires public asset URLs)"
|
||
collapsed: true
|
||
input:
|
||
send_telegram_media:
|
||
name: Send Media to Telegram
|
||
description: >
|
||
Send photos/videos as media attachments to Telegram using the
|
||
immich_album_watcher.send_telegram_notification service.
|
||
Media is downloaded from Immich and uploaded to Telegram, bypassing CORS restrictions.
|
||
Large media lists are automatically split into multiple groups.
|
||
default: false
|
||
selector:
|
||
boolean:
|
||
|
||
telegram_notify_targets:
|
||
name: Telegram Notify Targets
|
||
description: >
|
||
Select Telegram notify entities to send media to.
|
||
The chat ID will be extracted from the entity's friendly name.
|
||
Expected format: "Name (123456789)" where the number in parentheses is the chat ID.
|
||
default: []
|
||
selector:
|
||
entity:
|
||
domain: notify
|
||
multiple: true
|
||
|
||
telegram_chat_id_entities:
|
||
name: Telegram Chat ID Entities
|
||
description: >
|
||
List of input_text entities containing Telegram chat IDs to send media to.
|
||
Use this for chat IDs not associated with notify entities,
|
||
or as a fallback if friendly name parsing doesn't work.
|
||
Can be user IDs (positive) or group IDs (negative).
|
||
Chat IDs are read from the entity states.
|
||
default: []
|
||
selector:
|
||
entity:
|
||
domain:
|
||
- input_text
|
||
multiple: true
|
||
|
||
max_media_to_send:
|
||
name: Maximum Media to Send
|
||
description: >
|
||
Maximum number of photos/videos to send as attachments.
|
||
Set to 0 for unlimited.
|
||
default: 50
|
||
selector:
|
||
number:
|
||
min: 0
|
||
max: 50
|
||
mode: slider
|
||
|
||
max_media_per_group:
|
||
name: Maximum Media per Group
|
||
description: >
|
||
Maximum number of items in a single media group (album).
|
||
Telegram allows 2-10 items per group.
|
||
Large media lists are automatically split into multiple groups.
|
||
default: 10
|
||
selector:
|
||
number:
|
||
min: 2
|
||
max: 10
|
||
mode: slider
|
||
|
||
telegram_media_delay:
|
||
name: Delay Between Media Groups (ms)
|
||
description: >
|
||
Delay in milliseconds between sending multiple media groups.
|
||
Helps avoid rate limiting when large media lists are split.
|
||
Set to 0 for no delay.
|
||
default: 500
|
||
selector:
|
||
number:
|
||
min: 0
|
||
max: 60000
|
||
step: 100
|
||
unit_of_measurement: ms
|
||
mode: slider
|
||
|
||
telegram_video_warning:
|
||
name: Video Warning Message
|
||
description: >
|
||
Warning message appended to notifications when videos are present.
|
||
Telegram has a 50 MB file size limit for media sent via URL,
|
||
so large videos may fail to send. Leave empty to disable warning.
|
||
default: "\n\n⚠️ Note: Videos may not be sent due to Telegram's 50 MB file size limit."
|
||
selector:
|
||
text:
|
||
multiline: true
|
||
|
||
telegram_disable_url_preview:
|
||
name: Disable URL Preview
|
||
description: >
|
||
Disable link previews in Telegram text messages.
|
||
When enabled, URLs in the message won't show a preview card.
|
||
default: false
|
||
selector:
|
||
boolean:
|
||
|
||
# -------------------------------------------------------------------------
|
||
# Periodic Summary
|
||
# -------------------------------------------------------------------------
|
||
periodic_group:
|
||
name: "Periodic Summary"
|
||
description: "Send periodic notifications with a summary of tracked albums"
|
||
collapsed: true
|
||
input:
|
||
enable_periodic_summary:
|
||
name: Enable Periodic Summary
|
||
description: >
|
||
Send a summary notification of tracked albums at regular intervals.
|
||
Requires Album Names and Album Share URLs to be configured.
|
||
default: false
|
||
selector:
|
||
boolean:
|
||
|
||
periodic_interval_hours:
|
||
name: Summary Interval (Hours)
|
||
description: "How often to send the summary notification (in hours)"
|
||
default: 24
|
||
selector:
|
||
number:
|
||
min: 1
|
||
max: 168
|
||
unit_of_measurement: hours
|
||
mode: slider
|
||
|
||
periodic_start_hour:
|
||
name: Summary Start Hour
|
||
description: >
|
||
Hour of day (0-23) when the first summary should be sent.
|
||
Subsequent summaries are sent at this hour plus the interval.
|
||
Example: Start hour 12 with 24h interval = daily at 12:00.
|
||
default: 12
|
||
selector:
|
||
number:
|
||
min: 0
|
||
max: 23
|
||
unit_of_measurement: hour
|
||
mode: slider
|
||
|
||
periodic_summary_message:
|
||
name: Summary Message Template
|
||
description: >
|
||
Message template for the periodic summary.
|
||
Variables: `{albums}` (formatted list of albums), `{album_count}` (number of albums)
|
||
default: "📋 Tracked Albums Summary ({album_count} albums):{albums}"
|
||
selector:
|
||
text:
|
||
multiline: true
|
||
|
||
periodic_album_template:
|
||
name: Album Item Template
|
||
description: >
|
||
Template for each album in the summary list.
|
||
Variables: `{album_name}`, `{album_id}`, `{album_url}`
|
||
default: "\n • {album_name}: {album_url}"
|
||
selector:
|
||
text:
|
||
multiline: true
|
||
|
||
# -------------------------------------------------------------------------
|
||
# Scheduled Assets
|
||
# -------------------------------------------------------------------------
|
||
scheduled_assets_group:
|
||
name: "Scheduled Assets"
|
||
description: "Send scheduled notifications with existing assets from tracked albums"
|
||
collapsed: true
|
||
input:
|
||
enable_scheduled_assets:
|
||
name: Enable Scheduled Assets
|
||
description: >
|
||
Send scheduled notifications with assets from tracked albums.
|
||
Uses the immich_album_watcher.get_assets service to fetch assets.
|
||
default: false
|
||
selector:
|
||
boolean:
|
||
|
||
scheduled_assets_interval_hours:
|
||
name: Interval (Hours)
|
||
description: "How often to send scheduled asset notifications (in hours)"
|
||
default: 24
|
||
selector:
|
||
number:
|
||
min: 1
|
||
max: 168
|
||
unit_of_measurement: hours
|
||
mode: slider
|
||
|
||
scheduled_assets_start_hour:
|
||
name: Start Hour
|
||
description: >
|
||
Hour of day (0-23) when the first notification should be sent.
|
||
Example: Start hour 9 with 24h interval = daily at 09:00.
|
||
default: 9
|
||
selector:
|
||
number:
|
||
min: 0
|
||
max: 23
|
||
unit_of_measurement: hour
|
||
mode: slider
|
||
|
||
scheduled_assets_album_mode:
|
||
name: Album Mode
|
||
description: >
|
||
How to handle multiple tracked albums.
|
||
Per Album: Send separate notification for each album.
|
||
Combined: Fetch assets from all albums into one notification.
|
||
Random: Pick one random album each time.
|
||
default: "per_album"
|
||
selector:
|
||
select:
|
||
options:
|
||
- label: "Per Album"
|
||
value: "per_album"
|
||
- label: "Combined"
|
||
value: "combined"
|
||
- label: "Random Album"
|
||
value: "random"
|
||
|
||
scheduled_assets_limit:
|
||
name: Asset Limit
|
||
description: "Maximum number of assets to fetch per album"
|
||
default: 10
|
||
selector:
|
||
number:
|
||
min: 1
|
||
max: 100
|
||
mode: slider
|
||
|
||
scheduled_assets_favorite_only:
|
||
name: Favorites Only
|
||
description: "Only fetch assets marked as favorites"
|
||
default: false
|
||
selector:
|
||
boolean:
|
||
|
||
scheduled_assets_type:
|
||
name: Asset Type
|
||
description: "Filter assets by type"
|
||
default: "all"
|
||
selector:
|
||
select:
|
||
options:
|
||
- label: "All"
|
||
value: "all"
|
||
- label: "Photos Only"
|
||
value: "photo"
|
||
- label: "Videos Only"
|
||
value: "video"
|
||
|
||
scheduled_assets_order_by:
|
||
name: Order By
|
||
description: "How to sort/select assets"
|
||
default: "random"
|
||
selector:
|
||
select:
|
||
options:
|
||
- label: "Random"
|
||
value: "random"
|
||
- label: "Date"
|
||
value: "date"
|
||
- label: "Rating"
|
||
value: "rating"
|
||
- label: "Name"
|
||
value: "name"
|
||
|
||
scheduled_assets_order:
|
||
name: Order Direction
|
||
description: "Sort direction (only applies when Order By is not Random)"
|
||
default: "descending"
|
||
selector:
|
||
select:
|
||
options:
|
||
- label: "Descending (newest/highest first)"
|
||
value: "descending"
|
||
- label: "Ascending (oldest/lowest first)"
|
||
value: "ascending"
|
||
|
||
scheduled_assets_min_rating:
|
||
name: Minimum Rating
|
||
description: >
|
||
Only fetch assets with this rating or higher (1-5 stars).
|
||
Set to 0 to include all assets regardless of rating.
|
||
default: 0
|
||
selector:
|
||
number:
|
||
min: 0
|
||
max: 5
|
||
mode: slider
|
||
|
||
scheduled_assets_min_date:
|
||
name: Minimum Date
|
||
description: >
|
||
Only fetch assets created on or after this date.
|
||
Format: YYYY-MM-DD (e.g., 2024-01-01).
|
||
Leave empty for no minimum date filter.
|
||
default: ""
|
||
selector:
|
||
text:
|
||
|
||
scheduled_assets_max_date:
|
||
name: Maximum Date
|
||
description: >
|
||
Only fetch assets created on or before this date.
|
||
Format: YYYY-MM-DD (e.g., 2024-12-31).
|
||
Leave empty for no maximum date filter.
|
||
default: ""
|
||
selector:
|
||
text:
|
||
|
||
scheduled_assets_message:
|
||
name: Message Template
|
||
description: >
|
||
Message template for scheduled asset notifications.
|
||
Variables: `{album_name}`, `{album_url}`, `{asset_count}`, `{assets}`, `{common_date}`, `{common_location}`.
|
||
`{common_date}` shows the date when all assets share the same date.
|
||
`{common_location}` shows the location when all assets share the same location.
|
||
default: "📸 Here are some photos from album \"{album_name}\":{assets}"
|
||
selector:
|
||
text:
|
||
multiline: true
|
||
|
||
# -------------------------------------------------------------------------
|
||
# Debug
|
||
# -------------------------------------------------------------------------
|
||
debug:
|
||
name: "Debug"
|
||
collapsed: true
|
||
input:
|
||
enable_debug_notifications:
|
||
name: Enable Debug Notifications
|
||
description: >
|
||
Send persistent notifications for debugging automation behavior.
|
||
Shows event data and filtering decisions.
|
||
default: false
|
||
selector:
|
||
boolean:
|
||
|
||
automation_id:
|
||
name: Automation ID
|
||
description: >
|
||
Optional identifier for this automation instance.
|
||
Used to target specific automations when firing test events.
|
||
When firing a test event with `automation_id` in the event data,
|
||
only automations with a matching ID will respond.
|
||
Leave empty to respond to all test events.
|
||
default: ""
|
||
selector:
|
||
text:
|
||
|
||
# =============================================================================
|
||
# AUTOMATION MODE
|
||
# =============================================================================
|
||
# Single mode to process one event at a time
|
||
mode: single
|
||
|
||
# =============================================================================
|
||
# TRIGGERS
|
||
# =============================================================================
|
||
trigger:
|
||
# Monitor Immich album watcher events
|
||
- platform: event
|
||
event_type: immich_album_watcher_assets_added
|
||
id: "assets_added"
|
||
|
||
- platform: event
|
||
event_type: immich_album_watcher_assets_removed
|
||
id: "assets_removed"
|
||
|
||
- platform: event
|
||
event_type: immich_album_watcher_changed
|
||
id: "changed"
|
||
|
||
- platform: event
|
||
event_type: immich_album_watcher_album_renamed
|
||
id: "album_renamed"
|
||
|
||
- platform: event
|
||
event_type: immich_album_watcher_album_deleted
|
||
id: "album_deleted"
|
||
|
||
# Periodic summary trigger (time pattern)
|
||
# Note: Uses template to dynamically set interval, but HA requires static value
|
||
# so we trigger every hour and check interval in conditions
|
||
- platform: time_pattern
|
||
hours: "/1"
|
||
id: "periodic_summary"
|
||
|
||
# Manual trigger for testing periodic summary
|
||
# Fire this event from Developer Tools > Events to test periodic summary immediately
|
||
# Event type: immich_album_watcher_test_periodic_summary
|
||
- platform: event
|
||
event_type: immich_album_watcher_test_periodic_summary
|
||
id: "periodic_summary"
|
||
|
||
# Manual trigger for testing scheduled assets
|
||
# Fire this event from Developer Tools > Events to test scheduled assets immediately
|
||
# Event type: immich_album_watcher_test_scheduled_assets
|
||
- platform: event
|
||
event_type: immich_album_watcher_test_scheduled_assets
|
||
id: "scheduled_assets"
|
||
|
||
# =============================================================================
|
||
# VARIABLES
|
||
# =============================================================================
|
||
variables:
|
||
# ---------------------------------------------------------------------------
|
||
# Input Variables
|
||
# ---------------------------------------------------------------------------
|
||
hub_names: !input hub_names
|
||
album_id_entities: !input album_id_entities
|
||
automation_id: !input automation_id
|
||
|
||
# Read album IDs from entity states
|
||
album_ids: >
|
||
{% set ns = namespace(ids = []) %}
|
||
{% for entity_id in album_id_entities %}
|
||
{% set value = states(entity_id) | default('') | trim %}
|
||
{% if value | length > 0 and value not in ['unknown', 'unavailable'] %}
|
||
{% set ns.ids = ns.ids + [value] %}
|
||
{% endif %}
|
||
{% endfor %}
|
||
{{ ns.ids }}
|
||
|
||
notify_targets: !input notify_targets
|
||
include_people: !input include_people
|
||
include_asset_details: !input include_asset_details
|
||
max_assets_to_show: !input max_assets_to_show
|
||
track_assets_added: !input track_assets_added
|
||
track_assets_removed: !input track_assets_removed
|
||
track_images: !input track_images
|
||
track_videos: !input track_videos
|
||
track_album_renamed: !input track_album_renamed
|
||
track_album_deleted: !input track_album_deleted
|
||
enable_debug_notifications: !input enable_debug_notifications
|
||
|
||
# Telegram Media Settings
|
||
send_telegram_media: !input send_telegram_media
|
||
telegram_notify_targets: !input telegram_notify_targets
|
||
telegram_chat_id_entities: !input telegram_chat_id_entities
|
||
max_media_to_send: !input max_media_to_send
|
||
max_media_per_group: !input max_media_per_group
|
||
telegram_media_delay: !input telegram_media_delay
|
||
telegram_video_warning_template: !input telegram_video_warning
|
||
telegram_disable_url_preview: !input telegram_disable_url_preview
|
||
|
||
# Periodic Summary Settings
|
||
enable_periodic_summary: !input enable_periodic_summary
|
||
periodic_interval_hours: !input periodic_interval_hours
|
||
periodic_start_hour: !input periodic_start_hour
|
||
periodic_summary_message_template: !input periodic_summary_message
|
||
periodic_album_template: !input periodic_album_template
|
||
|
||
# Scheduled Assets Settings
|
||
enable_scheduled_assets: !input enable_scheduled_assets
|
||
scheduled_assets_interval_hours: !input scheduled_assets_interval_hours
|
||
scheduled_assets_start_hour: !input scheduled_assets_start_hour
|
||
scheduled_assets_album_mode: !input scheduled_assets_album_mode
|
||
scheduled_assets_limit: !input scheduled_assets_limit
|
||
scheduled_assets_favorite_only: !input scheduled_assets_favorite_only
|
||
scheduled_assets_type: !input scheduled_assets_type
|
||
scheduled_assets_order_by: !input scheduled_assets_order_by
|
||
scheduled_assets_order: !input scheduled_assets_order
|
||
scheduled_assets_min_rating: !input scheduled_assets_min_rating
|
||
scheduled_assets_min_date: !input scheduled_assets_min_date
|
||
scheduled_assets_max_date: !input scheduled_assets_max_date
|
||
scheduled_assets_message_template: !input scheduled_assets_message
|
||
|
||
# Parse chat IDs from notify entity friendly names (format: "Name (123456789)")
|
||
# and combine with chat IDs from input_text entities
|
||
telegram_chat_ids: >
|
||
{% set ns = namespace(ids = []) %}
|
||
{# Extract chat IDs from notify entity friendly names #}
|
||
{% for entity_id in telegram_notify_targets %}
|
||
{% set friendly_name = state_attr(entity_id, 'friendly_name') | default('') %}
|
||
{# Match number in parentheses at the end: "Diana (350705409)" -> "350705409" #}
|
||
{% set match = friendly_name | regex_findall('\\((-?\\d+)\\)\\s*$') %}
|
||
{% if match | length > 0 %}
|
||
{% set ns.ids = ns.ids + [match[0]] %}
|
||
{% endif %}
|
||
{% endfor %}
|
||
{# Read chat IDs from input_text entity states #}
|
||
{% for entity_id in telegram_chat_id_entities %}
|
||
{% set value = states(entity_id) | default('') | trim %}
|
||
{% if value | length > 0 and value not in ['unknown', 'unavailable'] and value not in ns.ids %}
|
||
{% set ns.ids = ns.ids + [value] %}
|
||
{% endif %}
|
||
{% endfor %}
|
||
{{ ns.ids }}
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# Message Templates
|
||
# ---------------------------------------------------------------------------
|
||
message_assets_added_template: !input message_assets_added
|
||
message_assets_removed_template: !input message_assets_removed
|
||
message_album_renamed_template: !input message_album_renamed
|
||
message_album_deleted_template: !input message_album_deleted
|
||
message_people_format_template: !input message_people_format
|
||
message_asset_image_template: !input message_asset_image
|
||
message_asset_video_template: !input message_asset_video
|
||
message_assets_format_template: !input message_assets_format
|
||
message_assets_more_template: !input message_assets_more
|
||
date_format: !input date_format
|
||
common_date_template: !input common_date_template
|
||
date_if_unique_template: !input date_if_unique_template
|
||
favorite_indicator_template: !input favorite_indicator_template
|
||
common_location_template: !input common_location_template
|
||
location_if_unique_template: !input location_if_unique_template
|
||
location_format: !input location_format
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# Event Data
|
||
# ---------------------------------------------------------------------------
|
||
event_hub_name: "{{ trigger.event.data.hub_name | default('') }}"
|
||
event_album_name: "{{ trigger.event.data.album_name | default('Unknown Album') }}"
|
||
event_album_id: "{{ trigger.event.data.album_id | default('') }}"
|
||
event_album_url: "{{ trigger.event.data.album_url | default('') }}"
|
||
event_change_type: "{{ trigger.event.data.change_type | default(trigger.id) }}"
|
||
event_added_count: "{{ trigger.event.data.added_count | default(0) | int }}"
|
||
event_removed_count: "{{ trigger.event.data.removed_count | default(0) | int }}"
|
||
event_people: "{{ trigger.event.data.people | default([]) }}"
|
||
event_added_assets: "{{ trigger.event.data.added_assets | default([]) }}"
|
||
|
||
# Album renamed event data
|
||
event_old_name: "{{ trigger.event.data.old_name | default('') }}"
|
||
event_new_name: "{{ trigger.event.data.new_name | default('') }}"
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# Computed Values
|
||
# ---------------------------------------------------------------------------
|
||
# Check if this hub should be tracked (empty list = track all)
|
||
is_hub_tracked: >
|
||
{{ hub_names | length == 0 or event_hub_name in hub_names }}
|
||
|
||
# Check if this album should be tracked (empty list = track all)
|
||
is_album_tracked: >
|
||
{{ album_ids | length == 0 or event_album_id in album_ids }}
|
||
|
||
# Format people list for notification
|
||
people_list: >
|
||
{% if include_people and event_people | length > 0 %}
|
||
{% set people_str = event_people | join(', ') %}
|
||
{{ message_people_format_template | replace('{people}', people_str) }}
|
||
{% else %}
|
||
{{ '' }}
|
||
{% endif %}
|
||
|
||
# Filter assets based on track_images/track_videos settings
|
||
# Videos are excluded if they don't have a playback URL
|
||
filtered_assets: >
|
||
{% set ns = namespace(assets = []) %}
|
||
{% for asset in event_added_assets %}
|
||
{% if asset.type == 'IMAGE' and track_images %}
|
||
{% set ns.assets = ns.assets + [asset] %}
|
||
{% elif asset.type == 'VIDEO' and track_videos and (asset.playback_url | default('') | length > 0) %}
|
||
{% set ns.assets = ns.assets + [asset] %}
|
||
{% endif %}
|
||
{% endfor %}
|
||
{{ ns.assets }}
|
||
|
||
# Count of filtered assets (for notifications)
|
||
filtered_added_count: "{{ filtered_assets | length }}"
|
||
|
||
# Compute unique dates from filtered assets
|
||
unique_dates: >
|
||
{% set ns = namespace(dates = []) %}
|
||
{% for asset in filtered_assets %}
|
||
{% set raw_date = asset.created_at | default('', true) %}
|
||
{% set dt = raw_date | as_datetime(none) if raw_date is string and raw_date | length > 0 else none %}
|
||
{% set formatted_date = dt.strftime(date_format) if dt else '' %}
|
||
{% if formatted_date | length > 0 and formatted_date not in ns.dates %}
|
||
{% set ns.dates = ns.dates + [formatted_date] %}
|
||
{% endif %}
|
||
{% endfor %}
|
||
{{ ns.dates }}
|
||
|
||
# Check if all assets share the same date
|
||
all_dates_same: "{{ unique_dates | length == 1 }}"
|
||
|
||
# Compute unique locations from filtered assets (only when all location fields present)
|
||
unique_locations: >
|
||
{% set ns = namespace(locations = []) %}
|
||
{% for asset in filtered_assets %}
|
||
{% set city = asset.city | default('', true) %}
|
||
{% set state = asset.state | default('', true) %}
|
||
{% set country = asset.country | default('', true) %}
|
||
{% if city | length > 0 and state | length > 0 and country | length > 0 %}
|
||
{% set formatted_location = location_format | replace('{city}', city) | replace('{state}', state) | replace('{country}', country) %}
|
||
{% if formatted_location not in ns.locations %}
|
||
{% set ns.locations = ns.locations + [formatted_location] %}
|
||
{% endif %}
|
||
{% endif %}
|
||
{% endfor %}
|
||
{{ ns.locations }}
|
||
|
||
# Check if all assets with location data share the same location
|
||
all_locations_same: "{{ unique_locations | length == 1 }}"
|
||
|
||
# Check if all filtered assets have complete location data
|
||
all_assets_have_location: >
|
||
{% set ns = namespace(count = 0) %}
|
||
{% for asset in filtered_assets %}
|
||
{% set city = asset.city | default('', true) %}
|
||
{% set state = asset.state | default('', true) %}
|
||
{% set country = asset.country | default('', true) %}
|
||
{% if city | length > 0 and state | length > 0 and country | length > 0 %}
|
||
{% set ns.count = ns.count + 1 %}
|
||
{% endif %}
|
||
{% endfor %}
|
||
{{ ns.count == filtered_assets | length and filtered_assets | length > 0 }}
|
||
|
||
# Format assets list for notification
|
||
assets_list: >
|
||
{% if include_asset_details and filtered_assets | length > 0 %}
|
||
{% set ns = namespace(items = '') %}
|
||
{% set max_items = max_assets_to_show if max_assets_to_show > 0 else filtered_assets | length %}
|
||
{% set assets_to_show = filtered_assets[:max_items] %}
|
||
{% for asset in assets_to_show %}
|
||
{% set asset_template = message_asset_video_template if asset.type == 'VIDEO' else message_asset_image_template %}
|
||
{% set raw_date = asset.created_at | default('', true) %}
|
||
{% set dt = raw_date | as_datetime(none) if raw_date is string and raw_date | length > 0 else none %}
|
||
{% set formatted_date = dt.strftime(date_format) if dt else '' %}
|
||
{% set created_if_unique = '' if unique_dates | length == 1 else (date_if_unique_template | replace('{date}', formatted_date)) %}
|
||
{% set is_favorite = favorite_indicator_template if asset.is_favorite | default(false) else '' %}
|
||
{% set rating = asset.rating | default('') | string if asset.rating not in [none, ''] else '' %}
|
||
{% set city = asset.city | default('', true) %}
|
||
{% set state = asset.state | default('', true) %}
|
||
{% set country = asset.country | default('', true) %}
|
||
{% set has_full_location = city | length > 0 and state | length > 0 and country | length > 0 %}
|
||
{% set formatted_location = location_format | replace('{city}', city) | replace('{state}', state) | replace('{country}', country) if has_full_location else '' %}
|
||
{% set location_if_unique = '' if (not has_full_location) or (all_assets_have_location and unique_locations | length == 1) else (location_if_unique_template | replace('{location}', formatted_location)) %}
|
||
{% set item = asset_template
|
||
| replace('{filename}', asset.filename | default('Unknown'))
|
||
| replace('{description}', asset.description | default(''))
|
||
| replace('{type}', asset.type | default('Unknown'))
|
||
| replace('{created}', formatted_date)
|
||
| replace('{created_if_unique}', created_if_unique)
|
||
| replace('{owner}', asset.owner | default('Unknown'))
|
||
| replace('{url}', asset.url | default(''))
|
||
| replace('{download_url}', asset.download_url | default(''))
|
||
| replace('{photo_url}', asset.photo_url | default(''))
|
||
| replace('{playback_url}', asset.playback_url | default(''))
|
||
| replace('{people}', (asset.people | default([])) | join(', '))
|
||
| replace('{album_name}', event_album_name)
|
||
| replace('{is_favorite}', is_favorite)
|
||
| replace('{rating}', rating)
|
||
| replace('{location}', formatted_location)
|
||
| replace('{location_if_unique}', location_if_unique)
|
||
| replace('{city}', city)
|
||
| replace('{state}', state)
|
||
| replace('{country}', country) %}
|
||
{% set ns.items = ns.items ~ item %}
|
||
{% endfor %}
|
||
{% set more_count = filtered_assets | length - max_items %}
|
||
{% if more_count > 0 %}
|
||
{% set ns.items = ns.items ~ message_assets_more_template | replace('{more_count}', more_count | string) %}
|
||
{% endif %}
|
||
{{ message_assets_format_template | replace('{assets}', ns.items) }}
|
||
{% else %}
|
||
{{ '' }}
|
||
{% endif %}
|
||
|
||
# Check if filtered assets contain any videos (for Telegram warning)
|
||
has_videos_in_assets: >
|
||
{{ filtered_assets | selectattr('type', 'equalto', 'VIDEO') | list | length > 0 }}
|
||
|
||
# Video warning text (only populated when Telegram media is enabled and videos are present)
|
||
video_warning_text: >-
|
||
{% if send_telegram_media and has_videos_in_assets and telegram_video_warning_template | length > 0 %}{{ telegram_video_warning_template }}{% else %}{{ '' }}{% endif %}
|
||
|
||
# Filter assets that have valid URLs (for Telegram media)
|
||
# URL preference: playback_url (videos), photo_url (images) > download_url > url (viewer)
|
||
assets_with_urls: >
|
||
{% set ns = namespace(assets = []) %}
|
||
{% for asset in filtered_assets %}
|
||
{% set playback_url = asset.playback_url | default('') %}
|
||
{% set photo_url = asset.photo_url | default('') %}
|
||
{% set download_url = asset.download_url | default('') %}
|
||
{% set view_url = asset.url | default('') %}
|
||
{% if playback_url | length > 0 or photo_url | length > 0 or download_url | length > 0 or view_url | length > 0 %}
|
||
{% set ns.assets = ns.assets + [asset] %}
|
||
{% endif %}
|
||
{% endfor %}
|
||
{{ ns.assets }}
|
||
|
||
# Determine if this event type should trigger a notification
|
||
# For added assets, check filtered count (respects track_images/track_videos)
|
||
should_notify: >
|
||
{% if trigger.id == 'assets_added' and track_assets_added and filtered_added_count | int > 0 %}
|
||
{{ true }}
|
||
{% elif trigger.id == 'assets_removed' and track_assets_removed and event_removed_count > 0 %}
|
||
{{ true }}
|
||
{% elif trigger.id == 'changed' and (track_assets_added or track_assets_removed) %}
|
||
{% if track_assets_added and filtered_added_count | int > 0 %}
|
||
{{ true }}
|
||
{% elif track_assets_removed and event_removed_count > 0 %}
|
||
{{ true }}
|
||
{% else %}
|
||
{{ false }}
|
||
{% endif %}
|
||
{% elif trigger.id == 'album_renamed' and track_album_renamed %}
|
||
{{ true }}
|
||
{% elif trigger.id == 'album_deleted' and track_album_deleted %}
|
||
{{ true }}
|
||
{% else %}
|
||
{{ false }}
|
||
{% endif %}
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# Periodic Summary Variables
|
||
# ---------------------------------------------------------------------------
|
||
# Check if periodic summary should run (every N hours starting from start_hour)
|
||
# Formula: (current_hour - start_hour) % interval == 0
|
||
# Example: start_hour=12, interval=24 → sends at 12:00 daily
|
||
# Example: start_hour=9, interval=12 → sends at 09:00 and 21:00
|
||
# Manual test event (immich_album_watcher_test_periodic_summary) bypasses time check
|
||
# If event data contains automation_id, only matching automations respond
|
||
should_send_periodic_summary: >
|
||
{% if trigger.id == 'periodic_summary' and enable_periodic_summary %}
|
||
{% if trigger.platform == 'event' and trigger.event.event_type == 'immich_album_watcher_test_periodic_summary' %}
|
||
{% set event_automation_id = trigger.event.data.automation_id | default('') %}
|
||
{% if event_automation_id | length > 0 %}
|
||
{{ automation_id == event_automation_id }}
|
||
{% else %}
|
||
{{ true }}
|
||
{% endif %}
|
||
{% else %}
|
||
{% set current_hour = now().hour %}
|
||
{% set start = periodic_start_hour | int %}
|
||
{% set interval = periodic_interval_hours | int %}
|
||
{{ (current_hour - start) % interval == 0 }}
|
||
{% endif %}
|
||
{% else %}
|
||
{{ false }}
|
||
{% endif %}
|
||
|
||
# Format the albums list for periodic summary
|
||
# Reads album name and share URL from album ID entity's attributes
|
||
periodic_albums_list: >
|
||
{% set ns = namespace(items = '') %}
|
||
{% for i in range(album_id_entities | length) %}
|
||
{% set entity_id = album_id_entities[i] %}
|
||
{% set id = states(entity_id) | default('') %}
|
||
{% if id | length > 0 and id not in ['unknown', 'unavailable'] %}
|
||
{% set name_attr = state_attr(entity_id, 'album_name') %}
|
||
{% set name = name_attr if name_attr not in [none, '', 'unknown', 'unavailable'] else id %}
|
||
{% set url_attr = state_attr(entity_id, 'share_url') %}
|
||
{% set url = url_attr if url_attr not in [none, 'unknown', 'unavailable'] else '' %}
|
||
{% set item = periodic_album_template
|
||
| replace('{album_name}', name)
|
||
| replace('{album_id}', id)
|
||
| replace('{album_url}', url) %}
|
||
{% set ns.items = ns.items ~ item %}
|
||
{% endif %}
|
||
{% endfor %}
|
||
{{ ns.items }}
|
||
|
||
# Complete periodic summary message
|
||
periodic_summary_formatted: >
|
||
{{ periodic_summary_message_template
|
||
| replace('{albums}', periodic_albums_list)
|
||
| replace('{album_count}', album_ids | length | string) }}
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# Scheduled Assets Variables
|
||
# ---------------------------------------------------------------------------
|
||
# Check if scheduled assets should run (every N hours starting from start_hour)
|
||
# Manual test event (immich_album_watcher_test_scheduled_assets) bypasses time check
|
||
# If event data contains automation_id, only matching automations respond
|
||
should_send_scheduled_assets: >
|
||
{% if trigger.id == 'scheduled_assets' and enable_scheduled_assets %}
|
||
{% set event_automation_id = trigger.event.data.automation_id | default('') %}
|
||
{% if event_automation_id | length > 0 %}
|
||
{{ automation_id == event_automation_id }}
|
||
{% else %}
|
||
{{ true }}
|
||
{% endif %}
|
||
{% elif trigger.id == 'periodic_summary' and enable_scheduled_assets %}
|
||
{% set current_hour = now().hour %}
|
||
{% set start = scheduled_assets_start_hour | int %}
|
||
{% set interval = scheduled_assets_interval_hours | int %}
|
||
{{ (current_hour - start) % interval == 0 }}
|
||
{% else %}
|
||
{{ false }}
|
||
{% endif %}
|
||
|
||
# Get list of album entities to process based on album mode
|
||
scheduled_assets_album_entities: >
|
||
{% if scheduled_assets_album_mode == 'random' %}
|
||
{{ [album_id_entities | random] if album_id_entities | length > 0 else [] }}
|
||
{% else %}
|
||
{{ album_id_entities }}
|
||
{% endif %}
|
||
|
||
# =============================================================================
|
||
# CONDITIONS
|
||
# =============================================================================
|
||
condition:
|
||
# Allow through if:
|
||
# 1. Periodic summary trigger and should send periodic summary or scheduled assets
|
||
# 2. Scheduled assets trigger
|
||
# 3. Event trigger and passes all event-based checks
|
||
- condition: template
|
||
value_template: >
|
||
{% if trigger.id == 'scheduled_assets' %}
|
||
{{ should_send_scheduled_assets }}
|
||
{% elif trigger.id == 'periodic_summary' %}
|
||
{{ should_send_periodic_summary or should_send_scheduled_assets }}
|
||
{% else %}
|
||
{{ is_hub_tracked and is_album_tracked and should_notify }}
|
||
{% endif %}
|
||
|
||
# =============================================================================
|
||
# ACTIONS
|
||
# =============================================================================
|
||
action:
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# PERIODIC SUMMARY: Send summary of tracked albums (time-based trigger)
|
||
# ---------------------------------------------------------------------------
|
||
- choose:
|
||
- conditions:
|
||
- condition: template
|
||
value_template: "{{ should_send_periodic_summary }}"
|
||
sequence:
|
||
# Send periodic summary to notification targets
|
||
- service: notify.send_message
|
||
target:
|
||
entity_id: "{{ notify_targets }}"
|
||
data:
|
||
message: "{{ periodic_summary_formatted }}"
|
||
|
||
# Also send to Telegram if configured
|
||
- choose:
|
||
- conditions:
|
||
- condition: template
|
||
value_template: "{{ send_telegram_media and telegram_chat_ids | length > 0 and album_id_entities | length > 0 }}"
|
||
sequence:
|
||
- repeat:
|
||
for_each: "{{ telegram_chat_ids }}"
|
||
sequence:
|
||
- service: immich_album_watcher.send_telegram_notification
|
||
response_variable: telegram_periodic_response
|
||
target:
|
||
entity_id: "{{ album_id_entities[0] }}"
|
||
data:
|
||
chat_id: "{{ repeat.item }}"
|
||
caption: "{{ periodic_summary_formatted }}"
|
||
disable_web_page_preview: "{{ telegram_disable_url_preview }}"
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# SCHEDULED ASSETS: Send notifications with assets from tracked albums
|
||
# ---------------------------------------------------------------------------
|
||
- choose:
|
||
- conditions:
|
||
- condition: template
|
||
value_template: "{{ should_send_scheduled_assets }}"
|
||
sequence:
|
||
# Process albums based on album_mode (per_album, combined, random)
|
||
- choose:
|
||
# Per Album Mode: Send separate notification for each album
|
||
- conditions:
|
||
- condition: template
|
||
value_template: "{{ scheduled_assets_album_mode in ['per_album', 'random'] }}"
|
||
sequence:
|
||
- repeat:
|
||
for_each: "{{ scheduled_assets_album_entities }}"
|
||
sequence:
|
||
- variables:
|
||
current_album_entity: "{{ repeat.item }}"
|
||
current_album_name: >
|
||
{% set name_attr = state_attr(current_album_entity, 'album_name') %}
|
||
{{ name_attr if name_attr not in [none, '', 'unknown', 'unavailable'] else states(current_album_entity) }}
|
||
current_album_url: >
|
||
{% set url_attr = state_attr(current_album_entity, 'share_url') %}
|
||
{{ url_attr if url_attr not in [none, 'unknown', 'unavailable'] else '' }}
|
||
|
||
# Build service data dynamically (omit optional params when not set)
|
||
- variables:
|
||
get_assets_data: >
|
||
{% set data = {
|
||
'limit': scheduled_assets_limit | int,
|
||
'favorite_only': scheduled_assets_favorite_only,
|
||
'order_by': scheduled_assets_order_by,
|
||
'order': scheduled_assets_order
|
||
} %}
|
||
{% if scheduled_assets_type != 'all' %}
|
||
{% set data = dict(data, asset_type=scheduled_assets_type) %}
|
||
{% endif %}
|
||
{% if scheduled_assets_min_rating | int > 0 %}
|
||
{% set data = dict(data, filter_min_rating=scheduled_assets_min_rating | int) %}
|
||
{% endif %}
|
||
{% if (scheduled_assets_min_date | default('')) | length > 0 %}
|
||
{% set data = dict(data, min_date=scheduled_assets_min_date) %}
|
||
{% endif %}
|
||
{% if (scheduled_assets_max_date | default('')) | length > 0 %}
|
||
{% set data = dict(data, max_date=scheduled_assets_max_date) %}
|
||
{% endif %}
|
||
{{ data }}
|
||
|
||
# Fetch assets from this album
|
||
- service: immich_album_watcher.get_assets
|
||
response_variable: fetched_assets_response
|
||
target:
|
||
entity_id: "{{ current_album_entity }}"
|
||
data: "{{ get_assets_data }}"
|
||
|
||
# Filter out videos without playback URL
|
||
- variables:
|
||
fetched_assets: >
|
||
{% set raw_assets = fetched_assets_response[current_album_entity].assets | default([]) %}
|
||
{% set ns = namespace(assets = []) %}
|
||
{% for asset in raw_assets %}
|
||
{% if asset.type == 'IMAGE' or (asset.type == 'VIDEO' and (asset.playback_url | default('') | length > 0)) %}
|
||
{% set ns.assets = ns.assets + [asset] %}
|
||
{% endif %}
|
||
{% endfor %}
|
||
{{ ns.assets }}
|
||
fetched_asset_count: "{{ fetched_assets | length }}"
|
||
|
||
# Only send notification if we got assets
|
||
- choose:
|
||
- conditions:
|
||
- condition: template
|
||
value_template: "{{ fetched_asset_count | int > 0 }}"
|
||
sequence:
|
||
# Format assets list using asset templates
|
||
- variables:
|
||
# Compute unique dates from fetched assets
|
||
scheduled_unique_dates: >
|
||
{% set ns = namespace(dates = []) %}
|
||
{% for asset in fetched_assets %}
|
||
{% set raw_date = asset.created_at | default('', true) %}
|
||
{% set dt = raw_date | as_datetime(none) if raw_date is string and raw_date | length > 0 else none %}
|
||
{% set formatted_date = dt.strftime(date_format) if dt else '' %}
|
||
{% if formatted_date | length > 0 and formatted_date not in ns.dates %}
|
||
{% set ns.dates = ns.dates + [formatted_date] %}
|
||
{% endif %}
|
||
{% endfor %}
|
||
{{ ns.dates }}
|
||
# Compute unique locations from fetched assets
|
||
scheduled_unique_locations: >
|
||
{% set ns = namespace(locations = []) %}
|
||
{% for asset in fetched_assets %}
|
||
{% set city = asset.city | default('', true) %}
|
||
{% set state = asset.state | default('', true) %}
|
||
{% set country = asset.country | default('', true) %}
|
||
{% if city | length > 0 and state | length > 0 and country | length > 0 %}
|
||
{% set formatted_location = location_format | replace('{city}', city) | replace('{state}', state) | replace('{country}', country) %}
|
||
{% if formatted_location not in ns.locations %}
|
||
{% set ns.locations = ns.locations + [formatted_location] %}
|
||
{% endif %}
|
||
{% endif %}
|
||
{% endfor %}
|
||
{{ ns.locations }}
|
||
# Check if all fetched assets have complete location data
|
||
scheduled_all_assets_have_location: >
|
||
{% set ns = namespace(count = 0) %}
|
||
{% for asset in fetched_assets %}
|
||
{% set city = asset.city | default('', true) %}
|
||
{% set state = asset.state | default('', true) %}
|
||
{% set country = asset.country | default('', true) %}
|
||
{% if city | length > 0 and state | length > 0 and country | length > 0 %}
|
||
{% set ns.count = ns.count + 1 %}
|
||
{% endif %}
|
||
{% endfor %}
|
||
{{ ns.count == fetched_assets | length and fetched_assets | length > 0 }}
|
||
scheduled_assets_list: >
|
||
{% set ns = namespace(items = '') %}
|
||
{% for asset in fetched_assets %}
|
||
{% set asset_template = message_asset_video_template if asset.type == 'VIDEO' else message_asset_image_template %}
|
||
{% set raw_date = asset.created_at | default('', true) %}
|
||
{% set dt = raw_date | as_datetime(none) if raw_date is string and raw_date | length > 0 else none %}
|
||
{% set formatted_date = dt.strftime(date_format) if dt else '' %}
|
||
{% set created_if_unique = '' if scheduled_unique_dates | length == 1 else (date_if_unique_template | replace('{date}', formatted_date) if formatted_date | length > 0 else '') %}
|
||
{% set is_favorite = favorite_indicator_template if asset.is_favorite | default(false) else '' %}
|
||
{% set rating = asset.rating | default('') | string if asset.rating not in [none, ''] else '' %}
|
||
{% set city = asset.city | default('', true) %}
|
||
{% set state = asset.state | default('', true) %}
|
||
{% set country = asset.country | default('', true) %}
|
||
{% set has_full_location = city | length > 0 and state | length > 0 and country | length > 0 %}
|
||
{% set formatted_location = location_format | replace('{city}', city) | replace('{state}', state) | replace('{country}', country) if has_full_location else '' %}
|
||
{% set location_if_unique = '' if (not has_full_location) or (scheduled_all_assets_have_location and scheduled_unique_locations | length == 1) else (location_if_unique_template | replace('{location}', formatted_location)) %}
|
||
{% set item = asset_template
|
||
| replace('{filename}', asset.filename | default('Unknown'))
|
||
| replace('{description}', asset.description | default(''))
|
||
| replace('{type}', asset.type | default('Unknown'))
|
||
| replace('{created}', formatted_date)
|
||
| replace('{created_if_unique}', created_if_unique)
|
||
| replace('{owner}', asset.owner | default('Unknown'))
|
||
| replace('{url}', asset.url | default(''))
|
||
| replace('{download_url}', asset.download_url | default(''))
|
||
| replace('{photo_url}', asset.photo_url | default(''))
|
||
| replace('{playback_url}', asset.playback_url | default(''))
|
||
| replace('{people}', (asset.people | default([])) | join(', '))
|
||
| replace('{album_name}', current_album_name)
|
||
| replace('{is_favorite}', is_favorite)
|
||
| replace('{rating}', rating)
|
||
| replace('{location}', formatted_location)
|
||
| replace('{location_if_unique}', location_if_unique)
|
||
| replace('{city}', city)
|
||
| replace('{state}', state)
|
||
| replace('{country}', country) %}
|
||
{% set ns.items = ns.items ~ item %}
|
||
{% endfor %}
|
||
{{ ns.items }}
|
||
scheduled_message: >-
|
||
{%- set sched_common_date = (common_date_template | replace('{date}', scheduled_unique_dates[0])) if scheduled_unique_dates | length == 1 else '' -%}
|
||
{%- set sched_common_location = (common_location_template | replace('{location}', scheduled_unique_locations[0])) if scheduled_all_assets_have_location and scheduled_unique_locations | length == 1 else '' -%}
|
||
{{ scheduled_assets_message_template
|
||
| replace('{album_name}', current_album_name)
|
||
| replace('{album_url}', current_album_url)
|
||
| replace('{asset_count}', fetched_asset_count | string)
|
||
| replace('{common_date}', sched_common_date)
|
||
| replace('{common_location}', sched_common_location)
|
||
| replace('{assets}', scheduled_assets_list) }}
|
||
|
||
# Send to notification targets
|
||
- service: notify.send_message
|
||
target:
|
||
entity_id: "{{ notify_targets }}"
|
||
data:
|
||
message: "{{ scheduled_message }}"
|
||
|
||
# Send to Telegram with media if configured
|
||
- choose:
|
||
- conditions:
|
||
- condition: template
|
||
value_template: "{{ send_telegram_media and telegram_chat_ids | length > 0 }}"
|
||
sequence:
|
||
# Build media URLs for Telegram
|
||
- variables:
|
||
scheduled_media_urls: >
|
||
{% set ns = namespace(items = []) %}
|
||
{% for asset in fetched_assets %}
|
||
{% set asset_type = asset.type | default('IMAGE') %}
|
||
{% set playback_url = asset.playback_url | default('') %}
|
||
{% set photo_url = asset.photo_url | default('') %}
|
||
{% set download_url = asset.download_url | default('') %}
|
||
{% set view_url = asset.url | default('') %}
|
||
{% if asset_type == 'VIDEO' and playback_url | length > 0 %}
|
||
{% set media_url = playback_url %}
|
||
{% elif asset_type == 'IMAGE' and photo_url | length > 0 %}
|
||
{% set media_url = photo_url %}
|
||
{% elif download_url | length > 0 %}
|
||
{% set media_url = download_url %}
|
||
{% else %}
|
||
{% set media_url = view_url %}
|
||
{% endif %}
|
||
{% if media_url | length > 0 %}
|
||
{% set media_type = 'video' if asset_type == 'VIDEO' else 'photo' %}
|
||
{% set item = {'url': media_url, 'type': media_type} %}
|
||
{% set ns.items = ns.items + [item] %}
|
||
{% endif %}
|
||
{% endfor %}
|
||
{{ ns.items }}
|
||
|
||
# Send to each Telegram chat
|
||
- repeat:
|
||
for_each: "{{ telegram_chat_ids }}"
|
||
sequence:
|
||
# First send text message
|
||
- service: immich_album_watcher.send_telegram_notification
|
||
response_variable: telegram_scheduled_text_response
|
||
target:
|
||
entity_id: "{{ current_album_entity }}"
|
||
data:
|
||
chat_id: "{{ repeat.item }}"
|
||
caption: "{{ scheduled_message }}"
|
||
disable_web_page_preview: "{{ telegram_disable_url_preview }}"
|
||
|
||
# Extract message ID for reply
|
||
- variables:
|
||
scheduled_reply_to_id: "{{ telegram_scheduled_text_response[current_album_entity].message_id | default(0) | int }}"
|
||
|
||
# Send media if we have URLs
|
||
- choose:
|
||
- conditions:
|
||
- condition: template
|
||
value_template: "{{ scheduled_media_urls | length > 0 }}"
|
||
sequence:
|
||
- service: immich_album_watcher.send_telegram_notification
|
||
response_variable: telegram_scheduled_media_response
|
||
continue_on_error: true
|
||
target:
|
||
entity_id: "{{ current_album_entity }}"
|
||
data:
|
||
chat_id: "{{ repeat.item }}"
|
||
urls: "{{ scheduled_media_urls }}"
|
||
reply_to_message_id: "{{ scheduled_reply_to_id }}"
|
||
max_group_size: "{{ max_media_per_group }}"
|
||
chunk_delay: "{{ telegram_media_delay }}"
|
||
wait_for_response: false
|
||
|
||
# Combined Mode: Fetch from all albums and combine into one notification
|
||
# Distributes the limit evenly across albums (e.g., limit=10 with 2 albums = 5 each)
|
||
- conditions:
|
||
- condition: template
|
||
value_template: "{{ scheduled_assets_album_mode == 'combined' }}"
|
||
sequence:
|
||
- variables:
|
||
all_fetched_assets: []
|
||
# Calculate per-album limit (use floor division for even distribution, minimum 1)
|
||
album_count: "{{ album_id_entities | length }}"
|
||
per_album_limit: "{{ [((scheduled_assets_limit | int) // (album_count | int)), 1] | max if album_count | int > 0 else scheduled_assets_limit | int }}"
|
||
|
||
# Fetch assets from each album with distributed limit
|
||
- repeat:
|
||
for_each: "{{ album_id_entities }}"
|
||
sequence:
|
||
# Build service data dynamically (omit optional params when not set)
|
||
- variables:
|
||
combined_get_assets_data: >
|
||
{% set data = {
|
||
'limit': per_album_limit | int,
|
||
'favorite_only': scheduled_assets_favorite_only,
|
||
'order_by': scheduled_assets_order_by,
|
||
'order': scheduled_assets_order
|
||
} %}
|
||
{% if scheduled_assets_type != 'all' %}
|
||
{% set data = dict(data, asset_type=scheduled_assets_type) %}
|
||
{% endif %}
|
||
{% if scheduled_assets_min_rating | int > 0 %}
|
||
{% set data = dict(data, filter_min_rating=scheduled_assets_min_rating | int) %}
|
||
{% endif %}
|
||
{% if (scheduled_assets_min_date | default('')) | length > 0 %}
|
||
{% set data = dict(data, min_date=scheduled_assets_min_date) %}
|
||
{% endif %}
|
||
{% if (scheduled_assets_max_date | default('')) | length > 0 %}
|
||
{% set data = dict(data, max_date=scheduled_assets_max_date) %}
|
||
{% endif %}
|
||
{{ data }}
|
||
|
||
- service: immich_album_watcher.get_assets
|
||
response_variable: combined_fetch_response
|
||
target:
|
||
entity_id: "{{ repeat.item }}"
|
||
data: "{{ combined_get_assets_data }}"
|
||
|
||
# Filter out videos without playback URL
|
||
- variables:
|
||
album_assets: >
|
||
{% set raw_assets = combined_fetch_response[repeat.item].assets | default([]) %}
|
||
{% set ns = namespace(assets = []) %}
|
||
{% for asset in raw_assets %}
|
||
{% if asset.type == 'IMAGE' or (asset.type == 'VIDEO' and (asset.playback_url | default('') | length > 0)) %}
|
||
{% set ns.assets = ns.assets + [asset] %}
|
||
{% endif %}
|
||
{% endfor %}
|
||
{{ ns.assets }}
|
||
all_fetched_assets: "{{ all_fetched_assets + album_assets }}"
|
||
|
||
- variables:
|
||
# Trim to the actual limit after combining from all albums
|
||
all_fetched_assets: "{{ all_fetched_assets[:scheduled_assets_limit | int] }}"
|
||
combined_asset_count: "{{ all_fetched_assets | length }}"
|
||
# Build combined album names from all tracked albums
|
||
combined_album_names: >
|
||
{% set ns = namespace(names = []) %}
|
||
{% for entity_id in album_id_entities %}
|
||
{% set name_attr = state_attr(entity_id, 'album_name') %}
|
||
{% set name = name_attr if name_attr not in [none, '', 'unknown', 'unavailable'] else states(entity_id) %}
|
||
{% if name | length > 0 and name not in ['unknown', 'unavailable'] %}
|
||
{% set ns.names = ns.names + [name] %}
|
||
{% endif %}
|
||
{% endfor %}
|
||
{{ ns.names | join(', ') }}
|
||
|
||
# Only send if we got assets
|
||
- choose:
|
||
- conditions:
|
||
- condition: template
|
||
value_template: "{{ combined_asset_count | int > 0 }}"
|
||
sequence:
|
||
# Format combined assets list
|
||
- variables:
|
||
# Compute unique dates from all fetched assets
|
||
combined_unique_dates: >
|
||
{% set ns = namespace(dates = []) %}
|
||
{% for asset in all_fetched_assets %}
|
||
{% set raw_date = asset.created_at | default('', true) %}
|
||
{% set dt = raw_date | as_datetime(none) if raw_date is string and raw_date | length > 0 else none %}
|
||
{% set formatted_date = dt.strftime(date_format) if dt else '' %}
|
||
{% if formatted_date | length > 0 and formatted_date not in ns.dates %}
|
||
{% set ns.dates = ns.dates + [formatted_date] %}
|
||
{% endif %}
|
||
{% endfor %}
|
||
{{ ns.dates }}
|
||
# Compute unique locations from all fetched assets
|
||
combined_unique_locations: >
|
||
{% set ns = namespace(locations = []) %}
|
||
{% for asset in all_fetched_assets %}
|
||
{% set city = asset.city | default('', true) %}
|
||
{% set state = asset.state | default('', true) %}
|
||
{% set country = asset.country | default('', true) %}
|
||
{% if city | length > 0 and state | length > 0 and country | length > 0 %}
|
||
{% set formatted_location = location_format | replace('{city}', city) | replace('{state}', state) | replace('{country}', country) %}
|
||
{% if formatted_location not in ns.locations %}
|
||
{% set ns.locations = ns.locations + [formatted_location] %}
|
||
{% endif %}
|
||
{% endif %}
|
||
{% endfor %}
|
||
{{ ns.locations }}
|
||
# Check if all fetched assets have complete location data
|
||
combined_all_assets_have_location: >
|
||
{% set ns = namespace(count = 0) %}
|
||
{% for asset in all_fetched_assets %}
|
||
{% set city = asset.city | default('', true) %}
|
||
{% set state = asset.state | default('', true) %}
|
||
{% set country = asset.country | default('', true) %}
|
||
{% if city | length > 0 and state | length > 0 and country | length > 0 %}
|
||
{% set ns.count = ns.count + 1 %}
|
||
{% endif %}
|
||
{% endfor %}
|
||
{{ ns.count == all_fetched_assets | length and all_fetched_assets | length > 0 }}
|
||
combined_assets_list: >
|
||
{% set ns = namespace(items = '') %}
|
||
{% for asset in all_fetched_assets %}
|
||
{% set asset_template = message_asset_video_template if asset.type == 'VIDEO' else message_asset_image_template %}
|
||
{% set raw_date = asset.created_at | default('', true) %}
|
||
{% set dt = raw_date | as_datetime(none) if raw_date is string and raw_date | length > 0 else none %}
|
||
{% set formatted_date = dt.strftime(date_format) if dt else '' %}
|
||
{% set created_if_unique = '' if combined_unique_dates | length == 1 else (date_if_unique_template | replace('{date}', formatted_date) if formatted_date | length > 0 else '') %}
|
||
{% set is_favorite = favorite_indicator_template if asset.is_favorite | default(false) else '' %}
|
||
{% set rating = asset.rating | default('') | string if asset.rating not in [none, ''] else '' %}
|
||
{% set city = asset.city | default('', true) %}
|
||
{% set state = asset.state | default('', true) %}
|
||
{% set country = asset.country | default('', true) %}
|
||
{% set has_full_location = city | length > 0 and state | length > 0 and country | length > 0 %}
|
||
{% set formatted_location = location_format | replace('{city}', city) | replace('{state}', state) | replace('{country}', country) if has_full_location else '' %}
|
||
{% set location_if_unique = '' if (not has_full_location) or (combined_all_assets_have_location and combined_unique_locations | length == 1) else (location_if_unique_template | replace('{location}', formatted_location)) %}
|
||
{% set item = asset_template
|
||
| replace('{filename}', asset.filename | default('Unknown'))
|
||
| replace('{description}', asset.description | default(''))
|
||
| replace('{type}', asset.type | default('Unknown'))
|
||
| replace('{created}', formatted_date)
|
||
| replace('{created_if_unique}', created_if_unique)
|
||
| replace('{owner}', asset.owner | default('Unknown'))
|
||
| replace('{url}', asset.url | default(''))
|
||
| replace('{download_url}', asset.download_url | default(''))
|
||
| replace('{photo_url}', asset.photo_url | default(''))
|
||
| replace('{playback_url}', asset.playback_url | default(''))
|
||
| replace('{people}', (asset.people | default([])) | join(', '))
|
||
| replace('{album_name}', combined_album_names)
|
||
| replace('{is_favorite}', is_favorite)
|
||
| replace('{rating}', rating)
|
||
| replace('{location}', formatted_location)
|
||
| replace('{location_if_unique}', location_if_unique)
|
||
| replace('{city}', city)
|
||
| replace('{state}', state)
|
||
| replace('{country}', country) %}
|
||
{% set ns.items = ns.items ~ item %}
|
||
{% endfor %}
|
||
{{ ns.items }}
|
||
combined_message: >-
|
||
{%- set comb_common_date = (common_date_template | replace('{date}', combined_unique_dates[0])) if combined_unique_dates | length == 1 else '' -%}
|
||
{%- set comb_common_location = (common_location_template | replace('{location}', combined_unique_locations[0])) if combined_all_assets_have_location and combined_unique_locations | length == 1 else '' -%}
|
||
{{ scheduled_assets_message_template
|
||
| replace('{album_name}', combined_album_names)
|
||
| replace('{album_url}', '')
|
||
| replace('{asset_count}', combined_asset_count | string)
|
||
| replace('{common_date}', comb_common_date)
|
||
| replace('{common_location}', comb_common_location)
|
||
| replace('{assets}', combined_assets_list) }}
|
||
|
||
# Send to notification targets
|
||
- service: notify.send_message
|
||
target:
|
||
entity_id: "{{ notify_targets }}"
|
||
data:
|
||
message: "{{ combined_message }}"
|
||
|
||
# Send to Telegram with media if configured
|
||
- choose:
|
||
- conditions:
|
||
- condition: template
|
||
value_template: "{{ send_telegram_media and telegram_chat_ids | length > 0 and album_id_entities | length > 0 }}"
|
||
sequence:
|
||
# Build combined media URLs
|
||
- variables:
|
||
combined_media_urls: >
|
||
{% set ns = namespace(items = []) %}
|
||
{% for asset in all_fetched_assets %}
|
||
{% set asset_type = asset.type | default('IMAGE') %}
|
||
{% set playback_url = asset.playback_url | default('') %}
|
||
{% set photo_url = asset.photo_url | default('') %}
|
||
{% set download_url = asset.download_url | default('') %}
|
||
{% set view_url = asset.url | default('') %}
|
||
{% if asset_type == 'VIDEO' and playback_url | length > 0 %}
|
||
{% set media_url = playback_url %}
|
||
{% elif asset_type == 'IMAGE' and photo_url | length > 0 %}
|
||
{% set media_url = photo_url %}
|
||
{% elif download_url | length > 0 %}
|
||
{% set media_url = download_url %}
|
||
{% else %}
|
||
{% set media_url = view_url %}
|
||
{% endif %}
|
||
{% if media_url | length > 0 %}
|
||
{% set media_type = 'video' if asset_type == 'VIDEO' else 'photo' %}
|
||
{% set item = {'url': media_url, 'type': media_type} %}
|
||
{% set ns.items = ns.items + [item] %}
|
||
{% endif %}
|
||
{% endfor %}
|
||
{{ ns.items }}
|
||
|
||
# Send to each Telegram chat
|
||
- repeat:
|
||
for_each: "{{ telegram_chat_ids }}"
|
||
sequence:
|
||
- service: immich_album_watcher.send_telegram_notification
|
||
response_variable: telegram_combined_text_response
|
||
target:
|
||
entity_id: "{{ album_id_entities[0] }}"
|
||
data:
|
||
chat_id: "{{ repeat.item }}"
|
||
caption: "{{ combined_message }}"
|
||
disable_web_page_preview: "{{ telegram_disable_url_preview }}"
|
||
|
||
- variables:
|
||
combined_reply_to_id: "{{ telegram_combined_text_response[album_id_entities[0]].message_id | default(0) | int }}"
|
||
|
||
- choose:
|
||
- conditions:
|
||
- condition: template
|
||
value_template: "{{ combined_media_urls | length > 0 }}"
|
||
sequence:
|
||
- service: immich_album_watcher.send_telegram_notification
|
||
response_variable: telegram_combined_media_response
|
||
continue_on_error: true
|
||
target:
|
||
entity_id: "{{ album_id_entities[0] }}"
|
||
data:
|
||
chat_id: "{{ repeat.item }}"
|
||
urls: "{{ combined_media_urls }}"
|
||
reply_to_message_id: "{{ combined_reply_to_id }}"
|
||
max_group_size: "{{ max_media_per_group }}"
|
||
chunk_delay: "{{ telegram_media_delay }}"
|
||
wait_for_response: false
|
||
|
||
# Stop here if this was a scheduled trigger - don't continue to event-based actions
|
||
- choose:
|
||
- conditions:
|
||
- condition: template
|
||
value_template: "{{ trigger.id in ['periodic_summary', 'scheduled_assets'] }}"
|
||
sequence:
|
||
- stop: "Scheduled notification sent"
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# DEBUG: Log event data (enabled via Debug input section)
|
||
# ---------------------------------------------------------------------------
|
||
- choose:
|
||
- conditions:
|
||
- condition: template
|
||
value_template: "{{ enable_debug_notifications }}"
|
||
sequence:
|
||
- service: persistent_notification.create
|
||
data:
|
||
title: "Immich Album Watcher Debug"
|
||
message: >
|
||
**Event Data:**
|
||
- Trigger ID: {{ trigger.id }}
|
||
- Hub: {{ event_hub_name }}
|
||
- Album: {{ event_album_name }}
|
||
- Album ID: {{ event_album_id }}
|
||
- Album URL: {{ event_album_url }}
|
||
- Change Type: {{ event_change_type }}
|
||
|
||
**Asset Counts:**
|
||
- Added Count (raw): {{ event_added_count }}
|
||
- Added Count (filtered): {{ filtered_added_count }}
|
||
- Removed Count: {{ event_removed_count }}
|
||
- Added Assets: {{ event_added_assets | length }}
|
||
|
||
**People:**
|
||
- {{ event_people | join(', ') if event_people | length > 0 else '(none)' }}
|
||
|
||
**Filtering:**
|
||
- Is Hub Tracked: {{ is_hub_tracked }}
|
||
- Is Album Tracked: {{ is_album_tracked }}
|
||
- Should Notify: {{ should_notify }}
|
||
- Track Images: {{ track_images }}
|
||
- Track Videos: {{ track_videos }}
|
||
- Include Asset Details: {{ include_asset_details }}
|
||
|
||
**Telegram:**
|
||
- Enabled: {{ send_telegram_media }}
|
||
- Chat IDs: {{ telegram_chat_ids | join(', ') if telegram_chat_ids | length > 0 else '(none)' }}
|
||
- Album Shared: {{ 'Yes' if event_album_url | length > 0 else 'No (media cannot be sent)' }}
|
||
- Assets with URLs: {{ assets_with_urls | length }}
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# Send Notification Based on Event Type
|
||
# ---------------------------------------------------------------------------
|
||
- choose:
|
||
# ---------------------------------------------------------------------
|
||
# CASE 1: Assets Added
|
||
# ---------------------------------------------------------------------
|
||
- conditions:
|
||
- condition: template
|
||
value_template: "{{ trigger.id == 'assets_added' and track_assets_added and filtered_added_count | int > 0 }}"
|
||
sequence:
|
||
- variables:
|
||
message: >-
|
||
{%- set tpl = message_assets_added_template -%}
|
||
{%- set msg_common_date = (common_date_template | replace('{date}', unique_dates[0])) if unique_dates | length == 1 else '' -%}
|
||
{%- set msg_common_location = (common_location_template | replace('{location}', unique_locations[0])) if all_assets_have_location and unique_locations | length == 1 else '' -%}
|
||
{{ tpl | replace('{album_name}', event_album_name)
|
||
| replace('{album_url}', event_album_url)
|
||
| replace('{added_count}', filtered_added_count | string)
|
||
| replace('{people}', people_list)
|
||
| replace('{assets}', assets_list)
|
||
| replace('{video_warning}', video_warning_text)
|
||
| replace('{common_date}', msg_common_date)
|
||
| replace('{common_location}', msg_common_location) }}
|
||
|
||
- service: notify.send_message
|
||
target:
|
||
entity_id: "{{ notify_targets }}"
|
||
data:
|
||
message: "{{ message }}"
|
||
|
||
# ---------------------------------------------------------------------
|
||
# CASE 2: Assets Removed
|
||
# ---------------------------------------------------------------------
|
||
- conditions:
|
||
- condition: template
|
||
value_template: "{{ trigger.id == 'assets_removed' and track_assets_removed and event_removed_count > 0 }}"
|
||
sequence:
|
||
- variables:
|
||
message: >
|
||
{% set tpl = message_assets_removed_template %}
|
||
{{ tpl | replace('{album_name}', event_album_name)
|
||
| replace('{album_url}', event_album_url)
|
||
| replace('{removed_count}', event_removed_count | string) }}
|
||
|
||
- service: notify.send_message
|
||
target:
|
||
entity_id: "{{ notify_targets }}"
|
||
data:
|
||
message: "{{ message }}"
|
||
|
||
# ---------------------------------------------------------------------
|
||
# CASE 3: Changed (handles both added and removed in one event)
|
||
# ---------------------------------------------------------------------
|
||
- conditions:
|
||
- condition: template
|
||
value_template: "{{ trigger.id == 'changed' }}"
|
||
sequence:
|
||
# Send added notification if applicable
|
||
- choose:
|
||
- conditions:
|
||
- condition: template
|
||
value_template: "{{ track_assets_added and filtered_added_count | int > 0 }}"
|
||
sequence:
|
||
- variables:
|
||
message: >-
|
||
{%- set tpl = message_assets_added_template -%}
|
||
{%- set chg_common_date = (common_date_template | replace('{date}', unique_dates[0])) if unique_dates | length == 1 else '' -%}
|
||
{%- set chg_common_location = (common_location_template | replace('{location}', unique_locations[0])) if all_assets_have_location and unique_locations | length == 1 else '' -%}
|
||
{{ tpl | replace('{album_name}', event_album_name)
|
||
| replace('{album_url}', event_album_url)
|
||
| replace('{added_count}', filtered_added_count | string)
|
||
| replace('{people}', people_list)
|
||
| replace('{assets}', assets_list)
|
||
| replace('{video_warning}', video_warning_text)
|
||
| replace('{common_date}', chg_common_date)
|
||
| replace('{common_location}', chg_common_location) }}
|
||
|
||
- service: notify.send_message
|
||
target:
|
||
entity_id: "{{ notify_targets }}"
|
||
data:
|
||
message: "{{ message }}"
|
||
|
||
# Send removed notification if applicable
|
||
- choose:
|
||
- conditions:
|
||
- condition: template
|
||
value_template: "{{ track_assets_removed and event_removed_count > 0 }}"
|
||
sequence:
|
||
- variables:
|
||
message: >
|
||
{% set tpl = message_assets_removed_template %}
|
||
{{ tpl | replace('{album_name}', event_album_name)
|
||
| replace('{album_url}', event_album_url)
|
||
| replace('{removed_count}', event_removed_count | string) }}
|
||
|
||
- service: notify.send_message
|
||
target:
|
||
entity_id: "{{ notify_targets }}"
|
||
data:
|
||
message: "{{ message }}"
|
||
|
||
# ---------------------------------------------------------------------
|
||
# CASE 4: Album Renamed
|
||
# ---------------------------------------------------------------------
|
||
- conditions:
|
||
- condition: template
|
||
value_template: "{{ trigger.id == 'album_renamed' and track_album_renamed }}"
|
||
sequence:
|
||
- variables:
|
||
message: >
|
||
{% set tpl = message_album_renamed_template %}
|
||
{{ tpl | replace('{old_name}', event_old_name)
|
||
| replace('{new_name}', event_new_name)
|
||
| replace('{album_url}', event_album_url) }}
|
||
|
||
- service: notify.send_message
|
||
target:
|
||
entity_id: "{{ notify_targets }}"
|
||
data:
|
||
message: "{{ message }}"
|
||
|
||
# Also send to Telegram if configured
|
||
- choose:
|
||
- conditions:
|
||
- condition: template
|
||
value_template: "{{ send_telegram_media and telegram_chat_ids | length > 0 and album_id_entities | length > 0 }}"
|
||
sequence:
|
||
- repeat:
|
||
for_each: "{{ telegram_chat_ids }}"
|
||
sequence:
|
||
- service: immich_album_watcher.send_telegram_notification
|
||
response_variable: telegram_renamed_response
|
||
target:
|
||
entity_id: "{{ album_id_entities[0] }}"
|
||
data:
|
||
chat_id: "{{ repeat.item }}"
|
||
caption: "{{ message }}"
|
||
disable_web_page_preview: "{{ telegram_disable_url_preview }}"
|
||
|
||
# ---------------------------------------------------------------------
|
||
# CASE 5: Album Deleted
|
||
# ---------------------------------------------------------------------
|
||
- conditions:
|
||
- condition: template
|
||
value_template: "{{ trigger.id == 'album_deleted' and track_album_deleted }}"
|
||
sequence:
|
||
- variables:
|
||
message: >
|
||
{% set tpl = message_album_deleted_template %}
|
||
{{ tpl | replace('{album_name}', event_album_name) }}
|
||
|
||
- service: notify.send_message
|
||
target:
|
||
entity_id: "{{ notify_targets }}"
|
||
data:
|
||
message: "{{ message }}"
|
||
|
||
# Also send to Telegram if configured
|
||
- choose:
|
||
- conditions:
|
||
- condition: template
|
||
value_template: "{{ send_telegram_media and telegram_chat_ids | length > 0 and album_id_entities | length > 0 }}"
|
||
sequence:
|
||
- repeat:
|
||
for_each: "{{ telegram_chat_ids }}"
|
||
sequence:
|
||
- service: immich_album_watcher.send_telegram_notification
|
||
response_variable: telegram_deleted_response
|
||
target:
|
||
entity_id: "{{ album_id_entities[0] }}"
|
||
data:
|
||
chat_id: "{{ repeat.item }}"
|
||
caption: "{{ message }}"
|
||
disable_web_page_preview: "{{ telegram_disable_url_preview }}"
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# Send Media to Telegram (if enabled)
|
||
# ---------------------------------------------------------------------------
|
||
# Sends photos/videos to Telegram using telegram_bot integration.
|
||
# Two modes available:
|
||
# 1. Individual messages (default) - uses telegram_bot.send_photo/send_video
|
||
# 2. Media group (album) - uses rest_command to call Telegram API directly
|
||
- choose:
|
||
- conditions:
|
||
- condition: template
|
||
value_template: >
|
||
{{ send_telegram_media and
|
||
telegram_chat_ids | length > 0 and
|
||
assets_with_urls | length > 0 and
|
||
(trigger.id == 'assets_added' or (trigger.id == 'changed' and filtered_added_count | int > 0)) }}
|
||
sequence:
|
||
- variables:
|
||
# Calculate how many media items to send
|
||
media_limit: >
|
||
{% if max_media_to_send > 0 %}
|
||
{{ max_media_to_send }}
|
||
{% else %}
|
||
{{ assets_with_urls | length }}
|
||
{% endif %}
|
||
media_to_send: "{{ assets_with_urls[:media_limit | int] }}"
|
||
|
||
# Debug logging for Telegram media
|
||
- choose:
|
||
- conditions:
|
||
- condition: template
|
||
value_template: "{{ enable_debug_notifications }}"
|
||
sequence:
|
||
- service: persistent_notification.create
|
||
data:
|
||
title: "Immich Album Watcher - Telegram Media Debug"
|
||
message: >
|
||
**Telegram Configuration:**
|
||
- Chat IDs: {{ telegram_chat_ids | join(', ') }}
|
||
- Max items per group: {{ max_media_per_group }}
|
||
|
||
**Media to Send ({{ media_to_send | length }} items):**
|
||
{% for asset in media_to_send %}
|
||
{% set playback_url = asset.playback_url | default('') %}
|
||
{% set photo_url = asset.photo_url | default('') %}
|
||
{% set download_url = asset.download_url | default('') %}
|
||
{% set view_url = asset.url | default('') %}
|
||
{% if asset.type == 'VIDEO' %}
|
||
{% set used_url = playback_url if playback_url | length > 0 else (download_url if download_url | length > 0 else view_url) %}
|
||
{% else %}
|
||
{% set used_url = photo_url if photo_url | length > 0 else (download_url if download_url | length > 0 else view_url) %}
|
||
{% endif %}
|
||
|
||
**{{ loop.index }}. {{ asset.type }}: {{ asset.filename | default('unknown') }}**
|
||
- Playback URL: {{ playback_url if playback_url | length > 0 else '(not available)' }}
|
||
- Photo URL: {{ photo_url if photo_url | length > 0 else '(not available)' }}
|
||
- Download URL: {{ download_url if download_url | length > 0 else '(not available)' }}
|
||
- View URL: {{ view_url if view_url | length > 0 else '(not available)' }}
|
||
- **Using: {{ used_url if used_url | length > 0 else '(no URL!)' }}**
|
||
{% endfor %}
|
||
|
||
---
|
||
**Note:** Media is sent via immich_album_watcher.send_telegram_notification service.
|
||
Large lists are automatically split into multiple groups.
|
||
|
||
# Build the notification message for Telegram
|
||
# Uses {video_warning} placeholder which is populated when videos are present
|
||
- variables:
|
||
telegram_message: >-
|
||
{%- set tpl = message_assets_added_template -%}
|
||
{%- set tg_common_date = (common_date_template | replace('{date}', unique_dates[0])) if unique_dates | length == 1 else '' -%}
|
||
{%- set tg_common_location = (common_location_template | replace('{location}', unique_locations[0])) if all_assets_have_location and unique_locations | length == 1 else '' -%}
|
||
{{ tpl | replace('{album_name}', event_album_name)
|
||
| replace('{album_url}', event_album_url)
|
||
| replace('{added_count}', filtered_added_count | string)
|
||
| replace('{people}', people_list)
|
||
| replace('{assets}', assets_list)
|
||
| replace('{video_warning}', video_warning_text)
|
||
| replace('{common_date}', tg_common_date)
|
||
| replace('{common_location}', tg_common_location) }}
|
||
|
||
# Build URLs list for media
|
||
# URL preference: playback_url (videos), photo_url (images) > download_url > url
|
||
media_urls: >
|
||
{% set ns = namespace(items = []) %}
|
||
{% for asset in media_to_send %}
|
||
{% set asset_type = asset.type | default('IMAGE') %}
|
||
{% set playback_url = asset.playback_url | default('') %}
|
||
{% set photo_url = asset.photo_url | default('') %}
|
||
{% set download_url = asset.download_url | default('') %}
|
||
{% set view_url = asset.url | default('') %}
|
||
{% if asset_type == 'VIDEO' and playback_url | length > 0 %}
|
||
{% set media_url = playback_url %}
|
||
{% elif asset_type == 'IMAGE' and photo_url | length > 0 %}
|
||
{% set media_url = photo_url %}
|
||
{% elif download_url | length > 0 %}
|
||
{% set media_url = download_url %}
|
||
{% else %}
|
||
{% set media_url = view_url %}
|
||
{% endif %}
|
||
{% set media_type = 'video' if asset_type == 'VIDEO' else 'photo' %}
|
||
{% set item = {'url': media_url, 'type': media_type} %}
|
||
{% set ns.items = ns.items + [item] %}
|
||
{% endfor %}
|
||
{{ ns.items }}
|
||
|
||
# Loop through each chat ID and send notifications
|
||
- repeat:
|
||
for_each: "{{ telegram_chat_ids }}"
|
||
sequence:
|
||
- variables:
|
||
current_chat_id: "{{ repeat.item }}"
|
||
|
||
# First send the text notification message to this chat
|
||
- service: immich_album_watcher.send_telegram_notification
|
||
response_variable: telegram_text_response
|
||
target:
|
||
entity_id: "{{ album_id_entities[0] if album_id_entities | length > 0 else '' }}"
|
||
data:
|
||
chat_id: "{{ current_chat_id }}"
|
||
caption: "{{ telegram_message }}"
|
||
disable_web_page_preview: "{{ telegram_disable_url_preview }}"
|
||
|
||
# Extract message ID for replies
|
||
- variables:
|
||
reply_to_message_id: "{{ telegram_text_response[album_id_entities[0]].message_id | default(0) | int }}"
|
||
|
||
# Send media if we have URLs
|
||
- choose:
|
||
- conditions:
|
||
- condition: template
|
||
value_template: "{{ media_urls | length > 0 }}"
|
||
sequence:
|
||
# Debug: Log reply_to_message_id value
|
||
- choose:
|
||
- conditions:
|
||
- condition: template
|
||
value_template: "{{ enable_debug_notifications }}"
|
||
sequence:
|
||
- service: persistent_notification.create
|
||
data:
|
||
title: "Immich Album Watcher - Reply To Debug"
|
||
message: >
|
||
**Reply To Message Debug:**
|
||
- Value: {{ telegram_text_response }}
|
||
|
||
- service: immich_album_watcher.send_telegram_notification
|
||
response_variable: telegram_media_response
|
||
continue_on_error: true
|
||
target:
|
||
entity_id: "{{ album_id_entities[0] if album_id_entities | length > 0 else '' }}"
|
||
data:
|
||
chat_id: "{{ current_chat_id }}"
|
||
urls: "{{ media_urls }}"
|
||
reply_to_message_id: "{{ reply_to_message_id }}"
|
||
max_group_size: "{{ max_media_per_group }}"
|
||
chunk_delay: "{{ telegram_media_delay }}"
|
||
wait_for_response: false
|