From 40da078ba59ede34132c03f8cbcc37b584c82074 Mon Sep 17 00:00:00 2001 From: "alexei.dolgolyov" Date: Sat, 31 Jan 2026 14:48:27 +0300 Subject: [PATCH] Attempt to use update API of immich album watcher integration to send telegram notifications --- Common/Immich Album Watcher.yaml | 327 ++++++++----------------------- manifest.json | 2 +- 2 files changed, 86 insertions(+), 243 deletions(-) diff --git a/Common/Immich Album Watcher.yaml b/Common/Immich Album Watcher.yaml index 5e7c0e0..492d90b 100644 --- a/Common/Immich Album Watcher.yaml +++ b/Common/Immich Album Watcher.yaml @@ -67,35 +67,26 @@ # # Telegram Media Attachments: # When enabled, photos/videos are sent as media attachments to Telegram -# using Home Assistant's telegram_bot integration. +# using the immich_album_watcher.send_telegram_notification service. # # Supports multiple recipients via two methods: # 1. Notify Entities: Select Telegram notify entities. Chat ID is extracted # from the friendly name. Format: "Name (123456789)" -# 2. Raw Chat IDs: Enter chat IDs directly for groups/channels. +# 2. Input Text Entities: Select input_text entities containing chat IDs for groups/channels. # # Requirements: -# - Telegram Bot integration must be configured in Home Assistant +# - Immich Album Watcher integration must be configured with Telegram bot token # - Immich album must have a shared link (to generate public asset URLs) -# - If you have multiple Telegram bots, specify the config_entry_id -# (find it in: Settings → Devices & Services → Telegram Bot → your bot → URL) # # Behavior: # - First sends a text notification message to each Telegram chat -# - Then sends photos/videos as replies to that notification message -# - By default, media is sent as individual messages -# - Optional: Send as media group (album) using Telegram API directly -# -# Media Group Mode (Album): -# - Sends multiple photos/videos grouped together as a Telegram album -# - Uses the immich_album_watcher.send_telegram_media_group service -# - Requires Telegram bot token to be configured in the Immich Album Watcher integration -# - Media groups support 2-10 items (Telegram limit) +# - Then sends photos/videos as media groups (albums) as replies to that message +# - Media is downloaded from Immich and uploaded to Telegram (bypasses CORS) +# - Large media lists are automatically split into multiple groups (2-10 items per group) # # Limitations: # - Only assets with valid public URLs will be sent -# - Telegram has a 50 MB file size limit for media sent via URL -# (large videos will fail with "Request Entity Too Large" error) +# - Telegram has a 50 MB file size limit for media # - Optional video warning can be shown when videos are present # - Media captions use the Image/Video Asset Templates # @@ -335,27 +326,14 @@ blueprint: send_telegram_media: name: Send Media to Telegram description: > - Send photos/videos as media attachments to Telegram. - IMPORTANT: This requires assets to have public URLs, meaning the - Immich album must have a shared link enabled. - Note: Due to Home Assistant limitations, media is sent as individual - messages rather than grouped albums. + 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_config_entry_id: - name: Telegram Bot Config Entry ID - description: > - Required if you have multiple Telegram bots configured. - Find this in Home Assistant: Settings → Devices & Services → Telegram Bot - → Click on your bot → look at the URL, the ID is after /config_entry/ - Example: "01JKXXXXXXXXXXXXXXXXXXX" - Leave empty if you only have one Telegram bot. - default: "" - selector: - text: - telegram_notify_targets: name: Telegram Notify Targets description: > @@ -368,16 +346,19 @@ blueprint: domain: notify multiple: true - telegram_chat_ids: - name: Additional Telegram Chat IDs + telegram_chat_id_entities: + name: Telegram Chat ID Entities description: > - Additional raw chat IDs to send media to (one per line). + 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: - text: + entity: + domain: + - input_text multiple: true max_media_to_send: @@ -396,9 +377,8 @@ blueprint: name: Maximum Media per Group description: > Maximum number of items in a single media group (album). - Only applies when "Send as Media Group" is enabled. Telegram allows 2-10 items per group. - If more media is available, multiple groups will be sent. + Large media lists are automatically split into multiple groups. default: 10 selector: number: @@ -407,16 +387,16 @@ blueprint: mode: slider telegram_media_delay: - name: Delay Between Media (ms) + name: Delay Between Media Groups (ms) description: > - Delay in milliseconds between sending each media item. - Helps avoid rate limiting and spaces out media messages. + 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: 5000 + max: 60000 step: 100 unit_of_measurement: ms mode: slider @@ -435,23 +415,12 @@ blueprint: telegram_disable_url_preview: name: Disable URL Preview description: > - Disable link previews in Telegram messages. + Disable link previews in Telegram text messages. When enabled, URLs in the message won't show a preview card. default: false selector: boolean: - telegram_send_as_media_group: - name: Send as Media Group (Album) - description: > - Send multiple photos/videos as a grouped album instead of individual messages. - Uses the immich_album_watcher.send_telegram_media_group service. - REQUIRES: Telegram bot token configured in the Immich Album Watcher integration options. - Telegram limits media groups to 2-10 items. - default: false - selector: - boolean: - # ------------------------------------------------------------------------- # Periodic Summary # ------------------------------------------------------------------------- @@ -593,15 +562,13 @@ variables: # Telegram Media Settings send_telegram_media: !input send_telegram_media - telegram_config_entry_id: !input telegram_config_entry_id telegram_notify_targets: !input telegram_notify_targets - telegram_chat_ids_raw: !input telegram_chat_ids + 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 - telegram_send_as_media_group: !input telegram_send_as_media_group # Periodic Summary Settings enable_periodic_summary: !input enable_periodic_summary @@ -611,7 +578,7 @@ variables: periodic_album_template: !input periodic_album_template # Parse chat IDs from notify entity friendly names (format: "Name (123456789)") - # and combine with raw chat IDs + # and combine with chat IDs from input_text entities telegram_chat_ids: > {% set ns = namespace(ids = []) %} {# Extract chat IDs from notify entity friendly names #} @@ -623,11 +590,11 @@ variables: {% set ns.ids = ns.ids + [match[0]] %} {% endif %} {% endfor %} - {# Add raw chat IDs #} - {% for chat_id in telegram_chat_ids_raw %} - {% set clean_id = chat_id | trim %} - {% if clean_id | length > 0 and clean_id not in ns.ids %} - {% set ns.ids = ns.ids + [clean_id] %} + {# 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 }} @@ -845,18 +812,18 @@ action: - choose: - conditions: - condition: template - value_template: "{{ send_telegram_media and telegram_chat_ids | length > 0 }}" + 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: telegram_bot.send_message + - service: immich_album_watcher.send_telegram_notification + target: + entity_id: "{{ album_id_entities[0] }}" data: - target: "{{ repeat.item }}" - message: "{{ periodic_summary_formatted }}" + chat_id: "{{ repeat.item }}" + caption: "{{ periodic_summary_formatted }}" disable_web_page_preview: "{{ telegram_disable_url_preview }}" - config_entry_id: > - {{ telegram_config_entry_id if telegram_config_entry_id | length > 0 else omit }} # Stop here for periodic summary - don't continue to event-based actions - stop: "Periodic summary sent" @@ -1023,8 +990,8 @@ action: title: "Immich Album Watcher - Telegram Media Debug" message: > **Telegram Configuration:** - - Config Entry ID: {{ telegram_config_entry_id if telegram_config_entry_id | length > 0 else '(not set)' }} - 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 %} @@ -1043,15 +1010,8 @@ action: **Using: {{ used_url if used_url | length > 0 else '(no URL!)' }}** {% endfor %} - **Tip:** For videos, playback URLs (asset_playback_url) are preferred. - For images, download URLs (asset_download_url) are preferred. - View URLs may return 404. - - **Media Group Mode:** - - Enabled: {{ telegram_send_as_media_group }} - - Max items per group: {{ max_media_per_group }} - - Will use media group: {{ telegram_send_as_media_group and media_to_send | length >= 2 }} - - Number of groups: {{ ((media_to_send | length) / (max_media_per_group | int)) | round(0, 'ceil') | int if telegram_send_as_media_group else 'N/A' }} + **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 @@ -1065,7 +1025,29 @@ action: | replace('{assets}', assets_list) | replace('{video_warning}', video_warning_text) }} - # Loop through each chat ID + # Build URLs list for media + # URL preference: playback_url (videos) > download_url > asset_url + media_urls: > + {% set ns = namespace(items = []) %} + {% for asset in media_to_send %} + {% set asset_type = asset.asset_type | default('IMAGE') %} + {% set playback_url = asset.asset_playback_url | default('') %} + {% set download_url = asset.asset_download_url | default('') %} + {% set view_url = asset.asset_url | default('') %} + {% if asset_type == 'VIDEO' and playback_url | length > 0 %} + {% set media_url = playback_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: @@ -1073,173 +1055,34 @@ action: current_chat_id: "{{ repeat.item }}" # First send the text notification message to this chat - - service: telegram_bot.send_message - response_variable: telegram_response + - 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: - target: "{{ current_chat_id }}" - message: "{{ telegram_message }}" + chat_id: "{{ current_chat_id }}" + caption: "{{ telegram_message }}" disable_web_page_preview: "{{ telegram_disable_url_preview }}" - config_entry_id: > - {{ telegram_config_entry_id if telegram_config_entry_id | length > 0 else omit }} - # Extract message ID for replies from response.chats[0].message_id + # Extract message ID for replies - variables: - reply_to_message_id: "{{ telegram_response.chats[0].message_id | default(0) | int }}" + reply_to_message_id: "{{ telegram_text_response.message_id | default(0) | int }}" - # Choose between media group (album) or individual messages + # Send media if we have URLs - choose: - # --------------------------------------------------------- - # OPTION 1: Send as Media Group (Album) via Immich integration - # --------------------------------------------------------- - # Uses immich_album_watcher.send_telegram_media_group service - # Telegram limits: 2-10 media items per group - conditions: - condition: template - value_template: > - {{ telegram_send_as_media_group and - media_to_send | length >= 2 }} + value_template: "{{ media_urls | length > 0 }}" sequence: - # Calculate number of groups needed - - variables: - group_size: "{{ max_media_per_group | int }}" - total_items: "{{ media_to_send | length }}" - num_groups: "{{ ((total_items | int) / (group_size | int)) | round(0, 'ceil') | int }}" - - # Send each media group - - repeat: - count: "{{ num_groups }}" - sequence: - - variables: - group_index: "{{ repeat.index - 1 }}" - start_idx: "{{ (group_index | int) * (group_size | int) }}" - end_idx: "{{ [(start_idx | int) + (group_size | int), total_items | int] | min }}" - # Build urls list for this group - media_group_urls: > - {% set ns = namespace(items = []) %} - {% set items_to_send = media_to_send[start_idx | int:end_idx | int] %} - {% for asset in items_to_send %} - {% set asset_type = asset.asset_type | default('IMAGE') %} - {% set playback_url = asset.asset_playback_url | default('') %} - {% set download_url = asset.asset_download_url | default('') %} - {% set view_url = asset.asset_url | default('') %} - {% if asset_type == 'VIDEO' and playback_url | length > 0 %} - {% set media_url = playback_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 }} - - # Only send if group has at least 2 items (Telegram requirement) - - choose: - - conditions: - - condition: template - value_template: "{{ (end_idx | int) - (start_idx | int) >= 2 }}" - sequence: - - service: immich_album_watcher.send_telegram_media_group - continue_on_error: true - response_variable: media_group_response - target: - entity_id: "{{ album_id_entities[0] if album_id_entities | length > 0 else '' }}" - data: - chat_id: "{{ current_chat_id | string }}" - urls: "{{ media_group_urls }}" - reply_to_message_id: "{{ reply_to_message_id if reply_to_message_id > 0 else omit }}" - - # Small delay between groups to avoid rate limiting - - choose: - - conditions: - - condition: template - value_template: "{{ repeat.index < num_groups | int and telegram_media_delay > 0 }}" - sequence: - - delay: - milliseconds: "{{ telegram_media_delay }}" - - # --------------------------------------------------------- - # OPTION 2: Send as Individual Messages (Default) - # --------------------------------------------------------- - default: - # Send each media item to this chat as reply to the notification - - repeat: - count: "{{ media_to_send | length }}" - sequence: - # Delay before each media item (acts as delay after notification for first item) - - choose: - - conditions: - - condition: template - value_template: "{{ telegram_media_delay > 0 }}" - sequence: - - delay: - milliseconds: "{{ telegram_media_delay }}" - - - variables: - current_asset: "{{ media_to_send[repeat.index - 1] }}" - asset_type: "{{ current_asset.asset_type | default('IMAGE') }}" - # URL preference: playback_url (videos) > download_url > asset_url - asset_url: > - {% set playback_url = current_asset.asset_playback_url | default('') %} - {% set download_url = current_asset.asset_download_url | default('') %} - {% set view_url = current_asset.asset_url | default('') %} - {% if asset_type == 'VIDEO' and playback_url | length > 0 %} - {{ playback_url }} - {% elif download_url | length > 0 %} - {{ download_url }} - {% else %} - {{ view_url }} - {% endif %} - # Use image/video asset templates for captions - caption: > - {% set tpl = message_asset_video_template if asset_type == 'VIDEO' else message_asset_image_template %} - {% set raw_date = current_asset.asset_created | default('') %} - {% set dt = raw_date | as_datetime(none) if raw_date | length > 0 else none %} - {% set formatted_date = dt.strftime(date_format) if dt else '' %} - {{ tpl | replace('{filename}', current_asset.asset_filename | default('')) - | replace('{description}', current_asset.asset_description | default('')) - | replace('{type}', current_asset.asset_type | default('')) - | replace('{created}', formatted_date) - | replace('{owner}', current_asset.asset_owner | default('')) - | replace('{url}', current_asset.asset_url | default('')) - | replace('{people}', (current_asset.people | default([])) | join(', ')) - | replace('{album_name}', event_album_name) }} - - # Send photo or video based on asset type - - choose: - # Send as photo for IMAGE assets - - conditions: - - condition: template - value_template: "{{ asset_type == 'IMAGE' }}" - sequence: - - service: telegram_bot.send_photo - # Continue on error so one failed photo doesn't stop other media - continue_on_error: true - data: - target: "{{ current_chat_id }}" - url: "{{ asset_url }}" - caption: "{{ caption }}" - reply_to_message_id: > - {{ reply_to_message_id if reply_to_message_id > 0 else omit }} - config_entry_id: > - {{ telegram_config_entry_id if telegram_config_entry_id | length > 0 else omit }} - - # Send as video for VIDEO assets - - conditions: - - condition: template - value_template: "{{ asset_type == 'VIDEO' }}" - sequence: - - service: telegram_bot.send_video - # Continue on error so one large video doesn't stop other media - # Note: Telegram has 50 MB limit for videos sent via URL - continue_on_error: true - data: - target: "{{ current_chat_id }}" - url: "{{ asset_url }}" - caption: "{{ caption }}" - reply_to_message_id: > - {{ reply_to_message_id if reply_to_message_id > 0 else omit }} - config_entry_id: > - {{ telegram_config_entry_id if telegram_config_entry_id | length > 0 else omit }} + - service: immich_album_watcher.send_telegram_notification + 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 }}" + caption: "{{ event_album_name }}" + reply_to_message_id: > + {{ reply_to_message_id if reply_to_message_id > 0 else omit }} + max_group_size: "{{ max_media_per_group }}" + chunk_delay: "{{ telegram_media_delay }}" diff --git a/manifest.json b/manifest.json index 97afddb..a21904c 100644 --- a/manifest.json +++ b/manifest.json @@ -1,3 +1,3 @@ { - "version": "1.11.2" + "version": "1.13.0" }