Replace the previous memory order_by option with a dedicated Memory Mode feature that has its own enable toggle, schedule (interval/start hour), and settings. Users can now run both Scheduled Assets and Memory Mode independently at different times. Memory Mode fetches photos taken on today's date in previous years using the memory_date parameter, sorted by date ascending (oldest first). Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2756 lines
150 KiB
YAML
2756 lines
150 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}`, `{album_created}`, `{album_updated}`, `{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}`, `{album_created}`, `{album_updated}`, `{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}`, `{album_created}`, `{album_updated}`, `{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}`, `{album_created}`, `{album_updated}`, `{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}`, `{album_created}`, `{album_updated}`
|
||
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}`, `{album_created}`, `{album_updated}`, `{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.
|
||
`{album_created}` and `{album_updated}` are empty in combined mode.
|
||
default: "📸 Here are some photos from album \"{album_name}\":{assets}"
|
||
selector:
|
||
text:
|
||
multiline: true
|
||
|
||
# -------------------------------------------------------------------------
|
||
# Memory Mode (On This Day)
|
||
# -------------------------------------------------------------------------
|
||
memory_mode_group:
|
||
name: "Memory Mode (On This Day)"
|
||
description: "Send scheduled notifications with photos from today's date in previous years"
|
||
collapsed: true
|
||
input:
|
||
enable_memory_mode:
|
||
name: Enable Memory Mode
|
||
description: >
|
||
Send scheduled notifications with photos taken on today's date in previous years.
|
||
Similar to "On This Day" or "Memories" features in photo apps.
|
||
default: false
|
||
selector:
|
||
boolean:
|
||
|
||
memory_mode_interval_hours:
|
||
name: Interval (Hours)
|
||
description: "How often to send memory notifications (in hours)"
|
||
default: 24
|
||
selector:
|
||
number:
|
||
min: 1
|
||
max: 168
|
||
unit_of_measurement: hours
|
||
mode: slider
|
||
|
||
memory_mode_start_hour:
|
||
name: Start Hour
|
||
description: >
|
||
Hour of day (0-23) when the first memory 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
|
||
|
||
memory_mode_album_mode:
|
||
name: Album Mode
|
||
description: >
|
||
How to handle multiple tracked albums.
|
||
Per Album: Send separate notification for each album.
|
||
Combined: Fetch memories from all albums into one notification.
|
||
Random: Pick one random album each time.
|
||
default: "combined"
|
||
selector:
|
||
select:
|
||
options:
|
||
- label: "Per Album"
|
||
value: "per_album"
|
||
- label: "Combined"
|
||
value: "combined"
|
||
- label: "Random Album"
|
||
value: "random"
|
||
|
||
memory_mode_limit:
|
||
name: Asset Limit
|
||
description: "Maximum number of memory assets to fetch"
|
||
default: 10
|
||
selector:
|
||
number:
|
||
min: 1
|
||
max: 100
|
||
mode: slider
|
||
|
||
memory_mode_favorite_only:
|
||
name: Favorites Only
|
||
description: "Only fetch memory assets marked as favorites"
|
||
default: false
|
||
selector:
|
||
boolean:
|
||
|
||
memory_mode_type:
|
||
name: Asset Type
|
||
description: "Filter memory assets by type"
|
||
default: "all"
|
||
selector:
|
||
select:
|
||
options:
|
||
- label: "All"
|
||
value: "all"
|
||
- label: "Photos Only"
|
||
value: "photo"
|
||
- label: "Videos Only"
|
||
value: "video"
|
||
|
||
memory_mode_min_rating:
|
||
name: Minimum Rating
|
||
description: >
|
||
Only fetch memory 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
|
||
|
||
memory_mode_message:
|
||
name: Message Template
|
||
description: >
|
||
Message template for memory notifications.
|
||
Variables: `{album_name}`, `{album_url}`, `{album_created}`, `{album_updated}`, `{asset_count}`, `{assets}`, `{common_date}`, `{common_location}`.
|
||
`{album_created}` and `{album_updated}` are empty in combined mode.
|
||
default: "📅 On this day:{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"
|
||
|
||
# Hourly timer trigger for periodic summary and scheduled assets
|
||
# 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: "hourly_timer"
|
||
|
||
# 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"
|
||
|
||
# Manual trigger for testing memory mode
|
||
# Fire this event from Developer Tools > Events to test memory mode immediately
|
||
# Event type: immich_album_watcher_test_memory_mode
|
||
- platform: event
|
||
event_type: immich_album_watcher_test_memory_mode
|
||
id: "memory_mode"
|
||
|
||
# =============================================================================
|
||
# 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
|
||
|
||
# Memory Mode Settings
|
||
enable_memory_mode: !input enable_memory_mode
|
||
memory_mode_interval_hours: !input memory_mode_interval_hours
|
||
memory_mode_start_hour: !input memory_mode_start_hour
|
||
memory_mode_album_mode: !input memory_mode_album_mode
|
||
memory_mode_limit: !input memory_mode_limit
|
||
memory_mode_favorite_only: !input memory_mode_favorite_only
|
||
memory_mode_type: !input memory_mode_type
|
||
memory_mode_min_rating: !input memory_mode_min_rating
|
||
memory_mode_message_template: !input memory_mode_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 (only available for event triggers, safe defaults for time triggers)
|
||
# ---------------------------------------------------------------------------
|
||
event_hub_name: "{{ trigger.event.data.hub_name | default('') if trigger.event is defined else '' }}"
|
||
event_album_name: "{{ trigger.event.data.album_name | default('Unknown Album') if trigger.event is defined else '' }}"
|
||
event_album_id: "{{ trigger.event.data.album_id | default('') if trigger.event is defined else '' }}"
|
||
event_album_url: "{{ trigger.event.data.album_url | default('') if trigger.event is defined else '' }}"
|
||
event_change_type: "{{ trigger.event.data.change_type | default(trigger.id) if trigger.event is defined else trigger.id }}"
|
||
event_added_count: "{{ (trigger.event.data.added_count | default(0) | int) if trigger.event is defined else 0 }}"
|
||
event_removed_count: "{{ (trigger.event.data.removed_count | default(0) | int) if trigger.event is defined else 0 }}"
|
||
event_people: "{{ trigger.event.data.people | default([]) if trigger.event is defined else [] }}"
|
||
event_added_assets: "{{ trigger.event.data.added_assets | default([]) if trigger.event is defined else [] }}"
|
||
|
||
# Album renamed event data
|
||
event_old_name: "{{ trigger.event.data.old_name | default('') if trigger.event is defined else '' }}"
|
||
event_new_name: "{{ trigger.event.data.new_name | default('') if trigger.event is defined else '' }}"
|
||
|
||
# Album dates (look up from entity using event_album_id)
|
||
# Find the entity that has this album ID and get its created_at/last_updated_at attributes
|
||
event_album_entity: >
|
||
{% if trigger.event is defined %}
|
||
{% for entity_id in album_id_entities %}
|
||
{% if states(entity_id) == event_album_id %}
|
||
{{ entity_id }}
|
||
{% endif %}
|
||
{% endfor %}
|
||
{% endif %}
|
||
event_album_created: >
|
||
{% if event_album_entity | length > 0 %}
|
||
{% set created_attr = state_attr(event_album_entity | trim, 'created_at') | default('', true) %}
|
||
{% set created_dt = created_attr | as_datetime(none) if created_attr is string and created_attr | length > 0 else none %}
|
||
{{ created_dt.strftime(date_format) if created_dt else '' }}
|
||
{% else %}
|
||
{{ '' }}
|
||
{% endif %}
|
||
event_album_updated: >
|
||
{% if event_album_entity | length > 0 %}
|
||
{% set updated_attr = state_attr(event_album_entity | trim, 'last_updated_at') | default('', true) %}
|
||
{% set updated_dt = updated_attr | as_datetime(none) if updated_attr is string and updated_attr | length > 0 else none %}
|
||
{{ updated_dt.strftime(date_format) if updated_dt else '' }}
|
||
{% else %}
|
||
{{ '' }}
|
||
{% endif %}
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# 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('{album_created}', event_album_created)
|
||
| replace('{album_updated}', event_album_updated)
|
||
| 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 }}
|
||
|
||
# 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 in ['hourly_timer', '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 %}
|
||
|
||
# Complete periodic summary message
|
||
# Note: periodic_albums_list is computed inline to avoid whitespace issues
|
||
periodic_summary_formatted: >
|
||
{%- 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 created_attr = state_attr(entity_id, 'created_at') | default('', true) -%}
|
||
{%- set created_dt = created_attr | as_datetime(none) if created_attr is string and created_attr | length > 0 else none -%}
|
||
{%- set album_created = created_dt.strftime(date_format) if created_dt else '' -%}
|
||
{%- set updated_attr = state_attr(entity_id, 'last_updated_at') | default('', true) -%}
|
||
{%- set updated_dt = updated_attr | as_datetime(none) if updated_attr is string and updated_attr | length > 0 else none -%}
|
||
{%- set album_updated = updated_dt.strftime(date_format) if updated_dt else '' -%}
|
||
{%- set item = periodic_album_template
|
||
| replace('{album_name}', name)
|
||
| replace('{album_id}', id)
|
||
| replace('{album_url}', url)
|
||
| replace('{album_created}', album_created)
|
||
| replace('{album_updated}', album_updated) -%}
|
||
{%- set ns.items = ns.items ~ item -%}
|
||
{%- endif -%}
|
||
{%- endfor -%}
|
||
{{ periodic_summary_message_template
|
||
| replace('{albums}', ns.items)
|
||
| 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 == 'hourly_timer' 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 %}
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# Memory Mode Variables
|
||
# ---------------------------------------------------------------------------
|
||
# Check if memory mode should run (every N hours starting from start_hour)
|
||
# Manual test event (immich_album_watcher_test_memory_mode) bypasses time check
|
||
# If event data contains automation_id, only matching automations respond
|
||
should_send_memory_mode: >
|
||
{% if trigger.id == 'memory_mode' and enable_memory_mode %}
|
||
{% 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 == 'hourly_timer' and enable_memory_mode %}
|
||
{% set current_hour = now().hour %}
|
||
{% set start = memory_mode_start_hour | int %}
|
||
{% set interval = memory_mode_interval_hours | int %}
|
||
{{ (current_hour - start) % interval == 0 }}
|
||
{% else %}
|
||
{{ false }}
|
||
{% endif %}
|
||
|
||
# Get list of album entities to process based on memory mode album mode
|
||
memory_mode_album_entities: >
|
||
{% if memory_mode_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. Hourly timer or periodic summary trigger and should send periodic summary, scheduled assets, or memory mode
|
||
# 2. Scheduled assets trigger (manual test)
|
||
# 3. Memory mode trigger (manual test)
|
||
# 4. Event trigger and passes all event-based checks
|
||
- condition: template
|
||
value_template: >
|
||
{% if trigger.id == 'scheduled_assets' %}
|
||
{{ should_send_scheduled_assets }}
|
||
{% elif trigger.id == 'memory_mode' %}
|
||
{{ should_send_memory_mode }}
|
||
{% elif trigger.id in ['hourly_timer', 'periodic_summary'] %}
|
||
{{ should_send_periodic_summary or should_send_scheduled_assets or should_send_memory_mode }}
|
||
{% 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 '' }}
|
||
current_album_created: >
|
||
{% set created_attr = state_attr(current_album_entity, 'created_at') | default('', true) %}
|
||
{% set created_dt = created_attr | as_datetime(none) if created_attr is string and created_attr | length > 0 else none %}
|
||
{{ created_dt.strftime(date_format) if created_dt else '' }}
|
||
current_album_updated: >
|
||
{% set updated_attr = state_attr(current_album_entity, 'last_updated_at') | default('', true) %}
|
||
{% set updated_dt = updated_attr | as_datetime(none) if updated_attr is string and updated_attr | length > 0 else none %}
|
||
{{ updated_dt.strftime(date_format) if updated_dt 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('{album_created}', current_album_created)
|
||
| replace('{album_updated}', current_album_updated)
|
||
| 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('{album_created}', current_album_created)
|
||
| replace('{album_updated}', current_album_updated)
|
||
| 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('{album_created}', '')
|
||
| replace('{album_updated}', '')
|
||
| 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('{album_created}', '')
|
||
| replace('{album_updated}', '')
|
||
| 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
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# MEMORY MODE: Send "On This Day" memories from tracked albums
|
||
# ---------------------------------------------------------------------------
|
||
- choose:
|
||
- conditions:
|
||
- condition: template
|
||
value_template: "{{ should_send_memory_mode }}"
|
||
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: "{{ memory_mode_album_mode in ['per_album', 'random'] }}"
|
||
sequence:
|
||
- repeat:
|
||
for_each: "{{ memory_mode_album_entities }}"
|
||
sequence:
|
||
- variables:
|
||
memory_current_album_entity: "{{ repeat.item }}"
|
||
memory_current_album_name: >
|
||
{% set name_attr = state_attr(memory_current_album_entity, 'album_name') %}
|
||
{{ name_attr if name_attr not in [none, '', 'unknown', 'unavailable'] else states(memory_current_album_entity) }}
|
||
memory_current_album_url: >
|
||
{% set url_attr = state_attr(memory_current_album_entity, 'share_url') %}
|
||
{{ url_attr if url_attr not in [none, 'unknown', 'unavailable'] else '' }}
|
||
memory_current_album_created: >
|
||
{% set created_attr = state_attr(memory_current_album_entity, 'created_at') | default('', true) %}
|
||
{% set created_dt = created_attr | as_datetime(none) if created_attr is string and created_attr | length > 0 else none %}
|
||
{{ created_dt.strftime(date_format) if created_dt else '' }}
|
||
memory_current_album_updated: >
|
||
{% set updated_attr = state_attr(memory_current_album_entity, 'last_updated_at') | default('', true) %}
|
||
{% set updated_dt = updated_attr | as_datetime(none) if updated_attr is string and updated_attr | length > 0 else none %}
|
||
{{ updated_dt.strftime(date_format) if updated_dt else '' }}
|
||
|
||
# Build service data with memory_date parameter
|
||
- variables:
|
||
memory_get_assets_data: >
|
||
{% set data = {
|
||
'limit': memory_mode_limit | int,
|
||
'favorite_only': memory_mode_favorite_only,
|
||
'order_by': 'date',
|
||
'order': 'ascending',
|
||
'memory_date': now().strftime('%Y-%m-%d')
|
||
} %}
|
||
{% if memory_mode_type != 'all' %}
|
||
{% set data = dict(data, asset_type=memory_mode_type) %}
|
||
{% endif %}
|
||
{% if memory_mode_min_rating | int > 0 %}
|
||
{% set data = dict(data, filter_min_rating=memory_mode_min_rating | int) %}
|
||
{% endif %}
|
||
{{ data }}
|
||
|
||
# Fetch memory assets from this album
|
||
- service: immich_album_watcher.get_assets
|
||
response_variable: memory_fetched_response
|
||
target:
|
||
entity_id: "{{ memory_current_album_entity }}"
|
||
data: "{{ memory_get_assets_data }}"
|
||
|
||
# Filter out videos without playback URL
|
||
- variables:
|
||
memory_fetched_assets: >
|
||
{% set raw_assets = memory_fetched_response[memory_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 }}
|
||
memory_fetched_count: "{{ memory_fetched_assets | length }}"
|
||
|
||
# Only send notification if we got assets
|
||
- choose:
|
||
- conditions:
|
||
- condition: template
|
||
value_template: "{{ memory_fetched_count | int > 0 }}"
|
||
sequence:
|
||
# Format assets list using asset templates
|
||
- variables:
|
||
# Compute unique dates from fetched assets
|
||
memory_unique_dates: >
|
||
{% set ns = namespace(dates = []) %}
|
||
{% for asset in memory_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
|
||
memory_unique_locations: >
|
||
{% set ns = namespace(locations = []) %}
|
||
{% for asset in memory_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
|
||
memory_all_assets_have_location: >
|
||
{% set ns = namespace(count = 0) %}
|
||
{% for asset in memory_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 == memory_fetched_assets | length and memory_fetched_assets | length > 0 }}
|
||
memory_assets_list: >
|
||
{% set ns = namespace(items = '') %}
|
||
{% for asset in memory_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 memory_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 (memory_all_assets_have_location and memory_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}', memory_current_album_name)
|
||
| replace('{album_created}', memory_current_album_created)
|
||
| replace('{album_updated}', memory_current_album_updated)
|
||
| 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 }}
|
||
memory_message: >-
|
||
{%- set mem_common_date = (common_date_template | replace('{date}', memory_unique_dates[0])) if memory_unique_dates | length == 1 else '' -%}
|
||
{%- set mem_common_location = (common_location_template | replace('{location}', memory_unique_locations[0])) if memory_all_assets_have_location and memory_unique_locations | length == 1 else '' -%}
|
||
{{ memory_mode_message_template
|
||
| replace('{album_name}', memory_current_album_name)
|
||
| replace('{album_url}', memory_current_album_url)
|
||
| replace('{album_created}', memory_current_album_created)
|
||
| replace('{album_updated}', memory_current_album_updated)
|
||
| replace('{asset_count}', memory_fetched_count | string)
|
||
| replace('{common_date}', mem_common_date)
|
||
| replace('{common_location}', mem_common_location)
|
||
| replace('{assets}', memory_assets_list) }}
|
||
|
||
# Send to notification targets
|
||
- service: notify.send_message
|
||
target:
|
||
entity_id: "{{ notify_targets }}"
|
||
data:
|
||
message: "{{ memory_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:
|
||
memory_media_urls: >
|
||
{% set ns = namespace(items = []) %}
|
||
{% for asset in memory_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_memory_text_response
|
||
target:
|
||
entity_id: "{{ memory_current_album_entity }}"
|
||
data:
|
||
chat_id: "{{ repeat.item }}"
|
||
caption: "{{ memory_message }}"
|
||
disable_web_page_preview: "{{ telegram_disable_url_preview }}"
|
||
|
||
# Extract message ID for reply
|
||
- variables:
|
||
memory_reply_to_id: "{{ telegram_memory_text_response[memory_current_album_entity].message_id | default(0) | int }}"
|
||
|
||
# Send media if we have URLs
|
||
- choose:
|
||
- conditions:
|
||
- condition: template
|
||
value_template: "{{ memory_media_urls | length > 0 }}"
|
||
sequence:
|
||
- service: immich_album_watcher.send_telegram_notification
|
||
response_variable: telegram_memory_media_response
|
||
continue_on_error: true
|
||
target:
|
||
entity_id: "{{ memory_current_album_entity }}"
|
||
data:
|
||
chat_id: "{{ repeat.item }}"
|
||
urls: "{{ memory_media_urls }}"
|
||
reply_to_message_id: "{{ memory_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
|
||
- conditions:
|
||
- condition: template
|
||
value_template: "{{ memory_mode_album_mode == 'combined' }}"
|
||
sequence:
|
||
- variables:
|
||
memory_all_fetched_assets: []
|
||
# Calculate per-album limit
|
||
memory_album_count: "{{ album_id_entities | length }}"
|
||
memory_per_album_limit: "{{ [((memory_mode_limit | int) // (memory_album_count | int)), 1] | max if memory_album_count | int > 0 else memory_mode_limit | int }}"
|
||
|
||
# Fetch assets from each album
|
||
- repeat:
|
||
for_each: "{{ album_id_entities }}"
|
||
sequence:
|
||
- variables:
|
||
memory_combined_data: >
|
||
{% set data = {
|
||
'limit': memory_per_album_limit | int,
|
||
'favorite_only': memory_mode_favorite_only,
|
||
'order_by': 'date',
|
||
'order': 'ascending',
|
||
'memory_date': now().strftime('%Y-%m-%d')
|
||
} %}
|
||
{% if memory_mode_type != 'all' %}
|
||
{% set data = dict(data, asset_type=memory_mode_type) %}
|
||
{% endif %}
|
||
{% if memory_mode_min_rating | int > 0 %}
|
||
{% set data = dict(data, filter_min_rating=memory_mode_min_rating | int) %}
|
||
{% endif %}
|
||
{{ data }}
|
||
|
||
- service: immich_album_watcher.get_assets
|
||
response_variable: memory_combined_response
|
||
target:
|
||
entity_id: "{{ repeat.item }}"
|
||
data: "{{ memory_combined_data }}"
|
||
|
||
# Filter out videos without playback URL
|
||
- variables:
|
||
memory_album_assets: >
|
||
{% set raw_assets = memory_combined_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 }}
|
||
memory_all_fetched_assets: "{{ memory_all_fetched_assets + memory_album_assets }}"
|
||
|
||
- variables:
|
||
# Trim to the actual limit
|
||
memory_all_fetched_assets: "{{ memory_all_fetched_assets[:memory_mode_limit | int] }}"
|
||
memory_combined_count: "{{ memory_all_fetched_assets | length }}"
|
||
# Build combined album names
|
||
memory_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: "{{ memory_combined_count | int > 0 }}"
|
||
sequence:
|
||
# Format combined assets list
|
||
- variables:
|
||
memory_comb_unique_dates: >
|
||
{% set ns = namespace(dates = []) %}
|
||
{% for asset in memory_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 }}
|
||
memory_comb_unique_locations: >
|
||
{% set ns = namespace(locations = []) %}
|
||
{% for asset in memory_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 }}
|
||
memory_comb_all_have_location: >
|
||
{% set ns = namespace(count = 0) %}
|
||
{% for asset in memory_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 == memory_all_fetched_assets | length and memory_all_fetched_assets | length > 0 }}
|
||
memory_comb_assets_list: >
|
||
{% set ns = namespace(items = '') %}
|
||
{% for asset in memory_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 memory_comb_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 (memory_comb_all_have_location and memory_comb_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}', memory_combined_album_names)
|
||
| replace('{album_created}', '')
|
||
| replace('{album_updated}', '')
|
||
| 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 }}
|
||
memory_comb_message: >-
|
||
{%- set mcomb_common_date = (common_date_template | replace('{date}', memory_comb_unique_dates[0])) if memory_comb_unique_dates | length == 1 else '' -%}
|
||
{%- set mcomb_common_location = (common_location_template | replace('{location}', memory_comb_unique_locations[0])) if memory_comb_all_have_location and memory_comb_unique_locations | length == 1 else '' -%}
|
||
{{ memory_mode_message_template
|
||
| replace('{album_name}', memory_combined_album_names)
|
||
| replace('{album_url}', '')
|
||
| replace('{album_created}', '')
|
||
| replace('{album_updated}', '')
|
||
| replace('{asset_count}', memory_combined_count | string)
|
||
| replace('{common_date}', mcomb_common_date)
|
||
| replace('{common_location}', mcomb_common_location)
|
||
| replace('{assets}', memory_comb_assets_list) }}
|
||
|
||
# Send to notification targets
|
||
- service: notify.send_message
|
||
target:
|
||
entity_id: "{{ notify_targets }}"
|
||
data:
|
||
message: "{{ memory_comb_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:
|
||
memory_comb_media_urls: >
|
||
{% set ns = namespace(items = []) %}
|
||
{% for asset in memory_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_memory_comb_text_response
|
||
target:
|
||
entity_id: "{{ album_id_entities[0] }}"
|
||
data:
|
||
chat_id: "{{ repeat.item }}"
|
||
caption: "{{ memory_comb_message }}"
|
||
disable_web_page_preview: "{{ telegram_disable_url_preview }}"
|
||
|
||
- variables:
|
||
memory_comb_reply_to_id: "{{ telegram_memory_comb_text_response[album_id_entities[0]].message_id | default(0) | int }}"
|
||
|
||
- choose:
|
||
- conditions:
|
||
- condition: template
|
||
value_template: "{{ memory_comb_media_urls | length > 0 }}"
|
||
sequence:
|
||
- service: immich_album_watcher.send_telegram_notification
|
||
response_variable: telegram_memory_comb_media_response
|
||
continue_on_error: true
|
||
target:
|
||
entity_id: "{{ album_id_entities[0] }}"
|
||
data:
|
||
chat_id: "{{ repeat.item }}"
|
||
urls: "{{ memory_comb_media_urls }}"
|
||
reply_to_message_id: "{{ memory_comb_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', 'memory_mode'] }}"
|
||
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 '' -%}
|
||
{%- set msg_video_warning = telegram_video_warning_template if (send_telegram_media and has_videos_in_assets and telegram_video_warning_template | length > 0) else '' -%}
|
||
{{ tpl | replace('{album_name}', event_album_name)
|
||
| replace('{album_url}', event_album_url)
|
||
| replace('{album_created}', event_album_created)
|
||
| replace('{album_updated}', event_album_updated)
|
||
| replace('{added_count}', filtered_added_count | string)
|
||
| replace('{people}', people_list)
|
||
| replace('{assets}', assets_list)
|
||
| replace('{video_warning}', msg_video_warning)
|
||
| 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('{album_created}', event_album_created)
|
||
| replace('{album_updated}', event_album_updated)
|
||
| 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 '' -%}
|
||
{%- set chg_video_warning = telegram_video_warning_template if (send_telegram_media and has_videos_in_assets and telegram_video_warning_template | length > 0) else '' -%}
|
||
{{ tpl | replace('{album_name}', event_album_name)
|
||
| replace('{album_url}', event_album_url)
|
||
| replace('{album_created}', event_album_created)
|
||
| replace('{album_updated}', event_album_updated)
|
||
| replace('{added_count}', filtered_added_count | string)
|
||
| replace('{people}', people_list)
|
||
| replace('{assets}', assets_list)
|
||
| replace('{video_warning}', chg_video_warning)
|
||
| 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('{album_created}', event_album_created)
|
||
| replace('{album_updated}', event_album_updated)
|
||
| 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 '' -%}
|
||
{%- set tg_video_warning = telegram_video_warning_template if (send_telegram_media and has_videos_in_assets and telegram_video_warning_template | length > 0) else '' -%}
|
||
{{ tpl | replace('{album_name}', event_album_name)
|
||
| replace('{album_url}', event_album_url)
|
||
| replace('{album_created}', event_album_created)
|
||
| replace('{album_updated}', event_album_updated)
|
||
| replace('{added_count}', filtered_added_count | string)
|
||
| replace('{people}', people_list)
|
||
| replace('{assets}', assets_list)
|
||
| replace('{video_warning}', tg_video_warning)
|
||
| 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
|