diff --git a/README.md b/README.md index bad3f79..5a5c58d 100644 --- a/README.md +++ b/README.md @@ -10,12 +10,15 @@ A Home Assistant custom integration that monitors [Immich](https://immich.app/) - **Album Monitoring** - Watch selected Immich albums for asset additions and removals - **Rich Sensor Data** - Multiple sensors per album: - - Album ID (with share URL attribute) - - Asset count (with detected people list) - - Photo count - - Video count - - Last updated timestamp - - Creation date + - Album ID (with album name and share URL attributes) + - Asset Count (total assets with detected people list) + - Photo Count (number of photos) + - Video Count (number of videos) + - Last Updated (last modification timestamp) + - Created (album creation date) + - Public URL (public share link) + - Protected URL (password-protected share link) + - Protected Password (password for protected link) - **Camera Entity** - Album thumbnail displayed as a camera entity for dashboards - **Binary Sensor** - "New Assets" indicator that turns on when assets are added - **Face Recognition** - Detects and lists people recognized in album photos @@ -40,6 +43,9 @@ A Home Assistant custom integration that monitors [Immich](https://immich.app/) - Create/delete password-protected share links - Edit protected link passwords via Text entity - **Configurable Polling** - Adjustable scan interval (10-3600 seconds) +- **Localization** - Available in multiple languages: + - English + - Russian (Русский) ## Installation @@ -110,26 +116,37 @@ Get assets from a specific album with optional filtering and ordering (returns r ```yaml service: immich_album_watcher.get_assets target: - entity_id: sensor.album_name_asset_count + entity_id: sensor.album_name_asset_limit data: - count: 10 # Maximum number of assets (1-100) - filter: "favorite" # Options: "none", "favorite", "rating" - filter_min_rating: 4 # Min rating (1-5), used when filter="rating" + limit: 10 # Maximum number of assets (1-100) + favorite_only: false # true = favorites only, false = all assets + filter_min_rating: 4 # Min rating (1-5) + order_by: "date" # Options: "date", "rating", "name" order: "descending" # Options: "ascending", "descending", "random" + asset_type: "all" # Options: "all", "photo", "video" + min_date: "2024-01-01" # Optional: assets created on or after this date + max_date: "2024-12-31" # Optional: assets created on or before this date ``` **Parameters:** -- `count` (optional, default: 10): Maximum number of assets to return (1-100) -- `filter` (optional, default: "none"): Filter type - - `"none"`: No filtering, return all assets - - `"favorite"`: Return only favorite assets - - `"rating"`: Return assets with rating >= `filter_min_rating` -- `filter_min_rating` (optional, default: 1): Minimum rating (1-5 stars), used when `filter="rating"` -- `order` (optional, default: "descending"): Sort order by creation date - - `"ascending"`: Oldest first - - `"descending"`: Newest first - - `"random"`: Random order +- `limit` (optional, default: 10): Maximum number of assets to return (1-100) +- `favorite_only` (optional, default: false): Filter to show only favorite assets +- `filter_min_rating` (optional, default: 1): Minimum rating for assets (1-5 stars). Applied independently of `favorite_only` +- `order_by` (optional, default: "date"): Field to sort assets by + - `"date"`: Sort by creation date + - `"rating"`: Sort by rating (assets without rating are placed last) + - `"name"`: Sort by filename +- `order` (optional, default: "descending"): Sort direction + - `"ascending"`: Ascending order + - `"descending"`: Descending order + - `"random"`: Random order (ignores `order_by`) +- `asset_type` (optional, default: "all"): Filter by asset type + - `"all"`: No type filtering, return both photos and videos + - `"photo"`: Return only photos + - `"video"`: Return only videos +- `min_date` (optional): Filter assets created on or after this date. Use ISO 8601 format (e.g., `"2024-01-01"` or `"2024-01-01T10:30:00"`) +- `max_date` (optional): Filter assets created on or before this date. Use ISO 8601 format (e.g., `"2024-12-31"` or `"2024-12-31T23:59:59"`) **Examples:** @@ -138,10 +155,11 @@ Get 5 most recent favorite assets: ```yaml service: immich_album_watcher.get_assets target: - entity_id: sensor.album_name_asset_count + entity_id: sensor.album_name_asset_limit data: - count: 5 - filter: "favorite" + limit: 5 + favorite_only: true + order_by: "date" order: "descending" ``` @@ -150,14 +168,68 @@ Get 10 random assets rated 3 stars or higher: ```yaml service: immich_album_watcher.get_assets target: - entity_id: sensor.album_name_asset_count + entity_id: sensor.album_name_asset_limit data: - count: 10 - filter: "rating" + limit: 10 filter_min_rating: 3 order: "random" ``` +Get 20 most recent photos only: + +```yaml +service: immich_album_watcher.get_assets +target: + entity_id: sensor.album_name_asset_limit +data: + limit: 20 + asset_type: "photo" + order_by: "date" + order: "descending" +``` + +Get top 10 highest rated favorite videos: + +```yaml +service: immich_album_watcher.get_assets +target: + entity_id: sensor.album_name_asset_limit +data: + limit: 10 + favorite_only: true + asset_type: "video" + order_by: "rating" + order: "descending" +``` + +Get photos sorted alphabetically by name: + +```yaml +service: immich_album_watcher.get_assets +target: + entity_id: sensor.album_name_asset_limit +data: + limit: 20 + asset_type: "photo" + order_by: "name" + order: "ascending" +``` + +Get photos from a specific date range: + +```yaml +service: immich_album_watcher.get_assets +target: + entity_id: sensor.album_name_asset_limit +data: + limit: 50 + asset_type: "photo" + min_date: "2024-06-01" + max_date: "2024-06-30" + order_by: "date" + order: "descending" +``` + ### Send Telegram Notification Send notifications to Telegram. Supports multiple formats: @@ -176,7 +248,7 @@ Text message: ```yaml service: immich_album_watcher.send_telegram_notification target: - entity_id: sensor.album_name_asset_count + entity_id: sensor.album_name_asset_limit data: chat_id: "-1001234567890" caption: "Check out the new album!" @@ -188,7 +260,7 @@ Single photo: ```yaml service: immich_album_watcher.send_telegram_notification target: - entity_id: sensor.album_name_asset_count + entity_id: sensor.album_name_asset_limit data: chat_id: "-1001234567890" urls: @@ -202,7 +274,7 @@ Media group: ```yaml service: immich_album_watcher.send_telegram_notification target: - entity_id: sensor.album_name_asset_count + entity_id: sensor.album_name_asset_limit data: chat_id: "-1001234567890" urls: @@ -219,7 +291,7 @@ HTML formatting: ```yaml service: immich_album_watcher.send_telegram_notification target: - entity_id: sensor.album_name_asset_count + entity_id: sensor.album_name_asset_limit data: chat_id: "-1001234567890" caption: | @@ -234,7 +306,7 @@ Non-blocking mode (fire-and-forget): ```yaml service: immich_album_watcher.send_telegram_notification target: - entity_id: sensor.album_name_asset_count + entity_id: sensor.album_name_asset_limit data: chat_id: "-1001234567890" urls: @@ -288,7 +360,7 @@ automation: - service: notify.mobile_app data: title: "New Photos" - message: "{{ trigger.event.data.added_count }} new photos in {{ trigger.event.data.album_name }}" + message: "{{ trigger.event.data.added_limit }} new photos in {{ trigger.event.data.album_name }}" - alias: "Album renamed" trigger: @@ -321,8 +393,8 @@ automation: | `album_url` | Public URL to view the album (only present if album has a shared link) | All events except `album_deleted` | | `change_type` | Type of change (assets_added, assets_removed, album_renamed, album_sharing_changed, changed) | All events except `album_deleted` | | `shared` | Current sharing status of the album | All events except `album_deleted` | -| `added_count` | Number of assets added | `album_changed`, `assets_added` | -| `removed_count` | Number of assets removed | `album_changed`, `assets_removed` | +| `added_limit` | Number of assets added | `album_changed`, `assets_added` | +| `removed_limit` | Number of assets removed | `album_changed`, `assets_removed` | | `added_assets` | List of added assets with details (see below) | `album_changed`, `assets_added` | | `removed_assets` | List of removed asset IDs | `album_changed`, `assets_removed` | | `people` | List of all people detected in the album | All events except `album_deleted` | @@ -368,7 +440,7 @@ automation: title: "New Photos" message: > {{ trigger.event.data.added_assets[0].owner }} added - {{ trigger.event.data.added_count }} photos to {{ trigger.event.data.album_name }} + {{ trigger.event.data.added_limit }} photos to {{ trigger.event.data.album_name }} ``` ## Requirements diff --git a/custom_components/immich_album_watcher/coordinator.py b/custom_components/immich_album_watcher/coordinator.py index bc993f6..eb28c00 100644 --- a/custom_components/immich_album_watcher/coordinator.py +++ b/custom_components/immich_album_watcher/coordinator.py @@ -362,18 +362,26 @@ class ImmichAlbumWatcherCoordinator(DataUpdateCoordinator[AlbumData | None]): async def async_get_assets( self, - count: int = 10, - filter: str = "none", + limit: int = 10, + favorite_only: bool = False, filter_min_rating: int = 1, + order_by: str = "date", order: str = "descending", + asset_type: str = "all", + min_date: str | None = None, + max_date: str | None = None, ) -> list[dict[str, Any]]: """Get assets from the album with optional filtering and ordering. Args: - count: Maximum number of assets to return (1-100) - filter: Filter type - 'none', 'favorite', or 'rating' - filter_min_rating: Minimum rating for assets (1-5), used when filter='rating' - order: Sort order - 'ascending', 'descending', or 'random' + limit: Maximum number of assets to return (1-100) + favorite_only: Filter to show only favorite assets + filter_min_rating: Minimum rating for assets (1-5) + order_by: Field to sort by - 'date', 'rating', or 'name' + order: Sort direction - 'ascending', 'descending', or 'random' + asset_type: Asset type filter - 'all', 'photo', or 'video' + min_date: Filter assets created on or after this date (ISO 8601 format) + max_date: Filter assets created on or before this date (ISO 8601 format) Returns: List of asset data dictionaries @@ -384,23 +392,54 @@ class ImmichAlbumWatcherCoordinator(DataUpdateCoordinator[AlbumData | None]): # Start with all processed assets only assets = [a for a in self.data.assets.values() if a.is_processed] - # Apply filtering - if filter == "favorite": + # Apply favorite filter + if favorite_only: assets = [a for a in assets if a.is_favorite] - elif filter == "rating": + + # Apply rating filter + if filter_min_rating > 1: assets = [a for a in assets if a.rating is not None and a.rating >= filter_min_rating] + # Apply asset type filtering + if asset_type == "photo": + assets = [a for a in assets if a.type == ASSET_TYPE_IMAGE] + elif asset_type == "video": + assets = [a for a in assets if a.type == ASSET_TYPE_VIDEO] + + # Apply date filtering + if min_date: + assets = [a for a in assets if a.created_at >= min_date] + if max_date: + assets = [a for a in assets if a.created_at <= max_date] + # Apply ordering if order == "random": import random random.shuffle(assets) - elif order == "ascending": - assets = sorted(assets, key=lambda a: a.created_at, reverse=False) - else: # descending (default) - assets = sorted(assets, key=lambda a: a.created_at, reverse=True) + else: + # Determine sort key based on order_by + if order_by == "rating": + # Sort by rating, putting None values last + assets = sorted( + assets, + key=lambda a: (a.rating is None, a.rating if a.rating is not None else 0), + reverse=(order == "descending") + ) + elif order_by == "name": + assets = sorted( + assets, + key=lambda a: a.filename.lower(), + reverse=(order == "descending") + ) + else: # date (default) + assets = sorted( + assets, + key=lambda a: a.created_at, + reverse=(order == "descending") + ) - # Limit count - assets = assets[:count] + # Limit results + assets = assets[:limit] # Build result with all available asset data (matching event data) result = [] diff --git a/custom_components/immich_album_watcher/manifest.json b/custom_components/immich_album_watcher/manifest.json index a8ea28e..6e1a2b4 100644 --- a/custom_components/immich_album_watcher/manifest.json +++ b/custom_components/immich_album_watcher/manifest.json @@ -8,5 +8,5 @@ "iot_class": "cloud_polling", "issue_tracker": "https://github.com/DolgolyovAlexei/haos-hacs-immich-album-watcher/issues", "requirements": [], - "version": "2.1.0" + "version": "2.2.0" } diff --git a/custom_components/immich_album_watcher/sensor.py b/custom_components/immich_album_watcher/sensor.py index fa84c69..31875e4 100644 --- a/custom_components/immich_album_watcher/sensor.py +++ b/custom_components/immich_album_watcher/sensor.py @@ -182,17 +182,25 @@ class ImmichAlbumBaseSensor(CoordinatorEntity[ImmichAlbumWatcherCoordinator], Se async def async_get_assets( self, - count: int = 10, - filter: str = "none", + limit: int = 10, + favorite_only: bool = False, filter_min_rating: int = 1, + order_by: str = "date", order: str = "descending", + asset_type: str = "all", + min_date: str | None = None, + max_date: str | None = None, ) -> ServiceResponse: """Get assets for this album with optional filtering and ordering.""" assets = await self.coordinator.async_get_assets( - count=count, - filter=filter, + limit=limit, + favorite_only=favorite_only, filter_min_rating=filter_min_rating, + order_by=order_by, order=order, + asset_type=asset_type, + min_date=min_date, + max_date=max_date, ) return {"assets": assets} diff --git a/custom_components/immich_album_watcher/services.yaml b/custom_components/immich_album_watcher/services.yaml index 6232612..bd53df9 100644 --- a/custom_components/immich_album_watcher/services.yaml +++ b/custom_components/immich_album_watcher/services.yaml @@ -14,8 +14,8 @@ get_assets: integration: immich_album_watcher domain: sensor fields: - count: - name: Count + limit: + name: Limit description: Maximum number of assets to return (1-100). required: false default: 10 @@ -24,23 +24,16 @@ get_assets: min: 1 max: 100 mode: slider - filter: - name: Filter - description: Filter assets by type (none, favorite, or rating-based). + favorite_only: + name: Favorite Only + description: Filter to show only favorite assets. required: false - default: "none" + default: false selector: - select: - options: - - label: "None (no filtering)" - value: "none" - - label: "Favorites only" - value: "favorite" - - label: "By minimum rating" - value: "rating" + boolean: filter_min_rating: name: Minimum Rating - description: Minimum rating for assets (1-5). Only used when filter is set to 'rating'. + description: Minimum rating for assets (1-5). Set to filter by rating. required: false default: 1 selector: @@ -48,20 +41,60 @@ get_assets: min: 1 max: 5 mode: slider + order_by: + name: Order By + description: Field to sort assets by. + required: false + default: "date" + selector: + select: + options: + - label: "Date" + value: "date" + - label: "Rating" + value: "rating" + - label: "Name" + value: "name" order: name: Order - description: Sort order for assets by creation date. + description: Sort direction. required: false default: "descending" selector: select: options: - - label: "Ascending (oldest first)" + - label: "Ascending" value: "ascending" - - label: "Descending (newest first)" + - label: "Descending" value: "descending" - label: "Random" value: "random" + asset_type: + name: Asset Type + description: Filter assets by type (all, photo, or video). + required: false + default: "all" + selector: + select: + options: + - label: "All (no type filtering)" + value: "all" + - label: "Photos only" + value: "photo" + - label: "Videos only" + value: "video" + min_date: + name: Minimum Date + description: Filter assets created on or after this date (ISO 8601 format, e.g., 2024-01-01 or 2024-01-01T10:30:00). + required: false + selector: + text: + max_date: + name: Maximum Date + description: Filter assets created on or before this date (ISO 8601 format, e.g., 2024-12-31 or 2024-12-31T23:59:59). + required: false + selector: + text: send_telegram_notification: name: Send Telegram Notification diff --git a/custom_components/immich_album_watcher/translations/en.json b/custom_components/immich_album_watcher/translations/en.json index a9fae48..6d01d81 100644 --- a/custom_components/immich_album_watcher/translations/en.json +++ b/custom_components/immich_album_watcher/translations/en.json @@ -137,21 +137,37 @@ "name": "Get Assets", "description": "Get assets from the targeted album with optional filtering and ordering.", "fields": { - "count": { - "name": "Count", + "limit": { + "name": "Limit", "description": "Maximum number of assets to return (1-100)." }, - "filter": { - "name": "Filter", - "description": "Filter assets by type (none, favorite, or rating-based)." + "favorite_only": { + "name": "Favorite Only", + "description": "Filter to show only favorite assets." }, "filter_min_rating": { "name": "Minimum Rating", - "description": "Minimum rating for assets (1-5). Only used when filter is set to 'rating'." + "description": "Minimum rating for assets (1-5)." + }, + "order_by": { + "name": "Order By", + "description": "Field to sort assets by (date, rating, or name)." }, "order": { "name": "Order", - "description": "Sort order for assets by creation date." + "description": "Sort direction (ascending, descending, or random)." + }, + "asset_type": { + "name": "Asset Type", + "description": "Filter assets by type (all, photo, or video)." + }, + "min_date": { + "name": "Minimum Date", + "description": "Filter assets created on or after this date (ISO 8601 format)." + }, + "max_date": { + "name": "Maximum Date", + "description": "Filter assets created on or before this date (ISO 8601 format)." } } }, diff --git a/custom_components/immich_album_watcher/translations/ru.json b/custom_components/immich_album_watcher/translations/ru.json index 848ead7..b13abad 100644 --- a/custom_components/immich_album_watcher/translations/ru.json +++ b/custom_components/immich_album_watcher/translations/ru.json @@ -137,21 +137,37 @@ "name": "Получить файлы", "description": "Получить файлы из выбранного альбома с возможностью фильтрации и сортировки.", "fields": { - "count": { - "name": "Количество", + "limit": { + "name": "Лимит", "description": "Максимальное количество возвращаемых файлов (1-100)." }, - "filter": { - "name": "Фильтр", - "description": "Фильтровать файлы по типу (none - без фильтра, favorite - только избранные, rating - по рейтингу)." + "favorite_only": { + "name": "Только избранные", + "description": "Фильтр для отображения только избранных файлов." }, "filter_min_rating": { "name": "Минимальный рейтинг", - "description": "Минимальный рейтинг для файлов (1-5). Используется только при filter='rating'." + "description": "Минимальный рейтинг для файлов (1-5)." + }, + "order_by": { + "name": "Сортировать по", + "description": "Поле для сортировки файлов (date - дата, rating - рейтинг, name - имя)." }, "order": { "name": "Порядок", - "description": "Порядок сортировки файлов по дате создания." + "description": "Направление сортировки (ascending - по возрастанию, descending - по убыванию, random - случайный)." + }, + "asset_type": { + "name": "Тип файла", + "description": "Фильтровать файлы по типу (all - все, photo - только фото, video - только видео)." + }, + "min_date": { + "name": "Минимальная дата", + "description": "Фильтровать файлы, созданные в эту дату или после (формат ISO 8601)." + }, + "max_date": { + "name": "Максимальная дата", + "description": "Фильтровать файлы, созданные в эту дату или до (формат ISO 8601)." } } },