diff --git a/Common/Immich Album Watcher/README.md b/Common/Immich Album Watcher/README.md index 9ddd506..d875345 100644 --- a/Common/Immich Album Watcher/README.md +++ b/Common/Immich Album Watcher/README.md @@ -7,6 +7,8 @@ This blueprint monitors Immich album changes and sends notifications when assets - Filter by hub/instance name (for multi-hub setups) - Monitor specific albums by name (whitelist) - Filter by asset type (track images only, videos only, or both) +- Filter by favorites only (only notify about favorite assets) +- Sort assets by date, rating, name, or keep original order - Send notifications to multiple targets simultaneously - Customizable notification messages with template variables - Separate templates for image and video assets @@ -15,6 +17,7 @@ This blueprint monitors Immich album changes and sends notifications when assets - Support for multiple change types (assets added, removed, changed) - Optional: send photos/videos as Telegram media attachments - Optional: periodic summary notifications with album list and share URLs +- Optional: memory mode (On This Day) for photos from today's date in previous years ## Event Data from Immich diff --git a/Common/Immich Album Watcher/blueprint.yaml b/Common/Immich Album Watcher/blueprint.yaml index f44e7b5..51be02a 100644 --- a/Common/Immich Album Watcher/blueprint.yaml +++ b/Common/Immich Album Watcher/blueprint.yaml @@ -136,6 +136,46 @@ blueprint: max: 50 mode: slider + assets_order_by: + name: Sort Assets By + description: > + How to sort assets in the notification list and media attachments. + Only applies to "assets added" notifications. + default: "none" + selector: + select: + options: + - label: "Original Order" + value: "none" + - label: "Date" + value: "date" + - label: "Rating" + value: "rating" + - label: "Name" + value: "name" + + assets_order: + name: Sort Direction + description: "Sort direction for assets (only applies when Sort Assets By is not Original Order)" + default: "descending" + selector: + select: + options: + - label: "Descending (newest/highest first)" + value: "descending" + - label: "Ascending (oldest/lowest first)" + value: "ascending" + + notify_favorites_only: + name: Notify Favorites Only + description: > + Only send notifications for assets marked as favorites. + Non-favorite assets will be filtered out from both the notification + text and any media attachments. + default: false + selector: + boolean: + # ------------------------------------------------------------------------- # Message Templates # ------------------------------------------------------------------------- @@ -864,6 +904,9 @@ variables: include_people: !input include_people include_asset_details: !input include_asset_details max_assets_to_show: !input max_assets_to_show + assets_order_by: !input assets_order_by + assets_order: !input assets_order + notify_favorites_only: !input notify_favorites_only track_assets_added: !input track_assets_added track_assets_removed: !input track_assets_removed track_images: !input track_images @@ -1021,26 +1064,61 @@ variables: {{ '' }} {% endif %} - # Filter assets based on track_images/track_videos settings + # Filter assets based on track_images/track_videos and notify_favorites_only 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] %} + {% set is_favorite = asset.is_favorite | default(false) %} + {% set passes_favorite_filter = (not notify_favorites_only) or is_favorite %} + {% if passes_favorite_filter %} + {% 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 %} {% endif %} {% endfor %} {{ ns.assets }} - # Count of filtered assets (for notifications) - filtered_added_count: "{{ filtered_assets | length }}" + # Sort filtered assets based on user settings + # Note: Rating sort handles null values by placing unrated assets last (descending) or first (ascending) + sorted_assets: > + {% if assets_order_by == 'none' %} + {{ filtered_assets }} + {% elif assets_order_by == 'date' %} + {% set reverse = assets_order == 'descending' %} + {{ filtered_assets | sort(attribute='created_at', reverse=reverse) | list }} + {% elif assets_order_by == 'rating' %} + {% set reverse = assets_order == 'descending' %} + {% set ns = namespace(rated = [], unrated = []) %} + {% for asset in filtered_assets %} + {% if asset.rating is not none and asset.rating | int > 0 %} + {% set ns.rated = ns.rated + [asset] %} + {% else %} + {% set ns.unrated = ns.unrated + [asset] %} + {% endif %} + {% endfor %} + {% set sorted_rated = ns.rated | sort(attribute='rating', reverse=reverse) | list %} + {% if reverse %} + {{ sorted_rated + ns.unrated }} + {% else %} + {{ ns.unrated + sorted_rated }} + {% endif %} + {% elif assets_order_by == 'name' %} + {% set reverse = assets_order == 'descending' %} + {{ filtered_assets | sort(attribute='filename', reverse=reverse) | list }} + {% else %} + {{ filtered_assets }} + {% endif %} - # Compute unique dates from filtered assets + # Count of filtered assets (for notifications) + filtered_added_count: "{{ sorted_assets | length }}" + + # Compute unique dates from sorted assets unique_dates: > {% set ns = namespace(dates = []) %} - {% for asset in filtered_assets %} + {% for asset in sorted_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 '' %} @@ -1053,10 +1131,10 @@ variables: # 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) + # Compute unique locations from sorted assets (only when all location fields present) unique_locations: > {% set ns = namespace(locations = []) %} - {% for asset in filtered_assets %} + {% for asset in sorted_assets %} {% set city = asset.city | default('', true) %} {% set state = asset.state | default('', true) %} {% set country = asset.country | default('', true) %} @@ -1072,10 +1150,10 @@ variables: # 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 + # Check if all sorted assets have complete location data all_assets_have_location: > {% set ns = namespace(count = 0) %} - {% for asset in filtered_assets %} + {% for asset in sorted_assets %} {% set city = asset.city | default('', true) %} {% set state = asset.state | default('', true) %} {% set country = asset.country | default('', true) %} @@ -1083,14 +1161,14 @@ variables: {% set ns.count = ns.count + 1 %} {% endif %} {% endfor %} - {{ ns.count == filtered_assets | length and filtered_assets | length > 0 }} + {{ ns.count == sorted_assets | length and sorted_assets | length > 0 }} # Format assets list for notification assets_list: > - {% if include_asset_details and filtered_assets | length > 0 %} + {% if include_asset_details and sorted_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] %} + {% set max_items = max_assets_to_show if max_assets_to_show > 0 else sorted_assets | length %} + {% set assets_to_show = sorted_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) %} @@ -1129,7 +1207,7 @@ variables: | replace('{country}', country) %} {% set ns.items = ns.items ~ item %} {% endfor %} - {% set more_count = filtered_assets | length - max_items %} + {% set more_count = sorted_assets | length - max_items %} {% if more_count > 0 %} {% set ns.items = ns.items ~ message_assets_more_template | replace('{more_count}', more_count | string) %} {% endif %} @@ -1138,15 +1216,15 @@ variables: {{ '' }} {% endif %} - # Check if filtered assets contain any videos (for Telegram warning) + # Check if sorted assets contain any videos (for Telegram warning) has_videos_in_assets: > - {{ filtered_assets | selectattr('type', 'equalto', 'VIDEO') | list | length > 0 }} + {{ sorted_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 %} + {% for asset in sorted_assets %} {% set playback_url = asset.playback_url | default('') %} {% set photo_url = asset.photo_url | default('') %} {% set download_url = asset.download_url | default('') %} diff --git a/manifest.json b/manifest.json index 61f204c..2bdd973 100644 --- a/manifest.json +++ b/manifest.json @@ -1,3 +1,3 @@ { - "version": "1.25.0" + "version": "1.26.0" }