From 60200ff7642270e78c8f58f72fe1038633d78dd3 Mon Sep 17 00:00:00 2001 From: "alexei.dolgolyov" Date: Thu, 29 Jan 2026 20:37:57 +0300 Subject: [PATCH] Added proper russian locale --- .gitignore | 46 ++++++++++++++ README.md | 73 ++++++++++++++++++++++ immich_album_watcher/icon.png | Bin 0 -> 6606 bytes immich_album_watcher/sensor.py | 11 ++-- immich_album_watcher/strings.json | 7 +++ immich_album_watcher/translations/en.json | 7 +++ immich_album_watcher/translations/ru.json | 60 ++++++++++++++++++ 7 files changed, 199 insertions(+), 5 deletions(-) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 immich_album_watcher/icon.png create mode 100644 immich_album_watcher/translations/ru.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e7e32ab --- /dev/null +++ b/.gitignore @@ -0,0 +1,46 @@ +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# Virtual environments +venv/ +ENV/ +env/ +.venv/ + +# IDE +.idea/ +.vscode/ +*.swp +*.swo +*~ + +# OS +.DS_Store +Thumbs.db + +# Testing +.pytest_cache/ +.coverage +htmlcov/ + +# Claude Code +.claude/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..56ca577 --- /dev/null +++ b/README.md @@ -0,0 +1,73 @@ +# HAOS Integrations + +A collection of custom Home Assistant integrations. + +## Integrations + +### Immich Album Watcher + +Immich + +Monitors [Immich](https://immich.app/) photo/video library albums for changes and exposes them as Home Assistant sensors with event-firing capabilities. + +#### Features + +- **Album Monitoring** - Watch selected Immich albums for asset additions and removals +- **Sensor Integration** - Creates Home Assistant sensors showing current asset count per album +- **Event Firing** - Fires Home Assistant events when albums change: + - `immich_album_watcher_album_changed` - General album changes + - `immich_album_watcher_assets_added` - When new assets are added + - `immich_album_watcher_assets_removed` - When assets are removed +- **Configurable Polling** - Adjustable scan interval (10-3600 seconds) +- **Rich Metadata** - Provides detailed album info including: + - Album name and ID + - Asset count + - Owner information + - Shared status + - Thumbnail URL + - Last updated timestamp + +#### Installation + +1. Copy the `immich_album_watcher` folder to your Home Assistant `custom_components` directory +2. Restart Home Assistant +3. Go to **Settings** → **Devices & Services** → **Add Integration** +4. Search for "Immich Album Watcher" +5. Enter your Immich server URL and API key +6. Select the albums you want to monitor + +#### Configuration + +| Option | Description | Default | +|--------|-------------|---------| +| Server URL | Your Immich server URL (e.g., `https://immich.example.com`) | Required | +| API Key | Your Immich API key | Required | +| Albums | Albums to monitor | Required | +| Scan Interval | How often to check for changes (seconds) | 60 | + +#### Events + +Use these events in your automations: + +```yaml +automation: + - alias: "New photos added to album" + trigger: + - platform: event + event_type: immich_album_watcher_assets_added + action: + - service: notify.mobile_app + data: + title: "New Photos" + message: "{{ trigger.event.data.added_count }} new photos in {{ trigger.event.data.album_name }}" +``` + +#### Requirements + +- Home Assistant 2024.1.0 or newer +- Immich server with API access +- Valid Immich API key + +## License + +This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. diff --git a/immich_album_watcher/icon.png b/immich_album_watcher/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..8216d3f6151a72c29c498d3cd696696a533b408f GIT binary patch literal 6606 zcma)>=Q|tz_r{Zm5Mr;`n_3k$iwa6(tD+RG7^SsmZAog6)@spGqZCEaf!MoBl@vwo zU88nvl3zc+zu{uMjF zG8X`V^QFFymPPR7-x-QzN-Ng5J@cuf8$pV$Zc}xh^;%40p4L-!Z)0me6x97Fn7saZ zX6n^sXf=K(qHWo>r;n8Hdh6e&|6P%E!;AhVr!ni{4`9->cXO&NZ0(A+n%XS83iVc| z3)zsOl6J&B%N|c*oIA(|=B}9(>NurE$M8W!}N#bsQ=U5SY+%g&1&T-Hi z(n7e=0<&sdr!`);Un?pna8Ghm=G$i(2(k3HQDCRSlS1B$F`3pA5s+qa#LBecji1JC9tIJ^mqoNNdOak?@Y93A`H~=|cN%|}8mXmd3H7qX zmuE(5u^L`qB$tjr#Hkahk@_}1;IlBMCrkyVc?Uy_B|{`PEDwoCMM7E0$Zjd*|o6`%yX(vT{V8A7PNt(`Zka1-n%7vlNx{o>+5rkAYx+U z=uOfv_1a#Z$`BycF?Y}ydFD=0P(CU{`R%@E=)@c+AV!?>+nXE>vNB3j*cS@)`<2I8 z8U?)lUYsVi;)wrbhXFeoWb!FOj?rhNSB)EJc`#&4lbWM&JZ+ADJhMmr2nF<8V$WRv z3b>Ldr0LZRI}dmW2*?67yzdXTu!3j~K~uTwgK3twv}0PuHNB>Z%#i7ql0ZLm+vewc zPfCw;BtbqDg#23X_cW;)3gip(rkG1L4FA$r?oSid^evqwdu&u z`oY?Rm+NZDXHrLlK-Ki{q^=;(u%c}~(R=@_Jawy4QeM_>s;*Z)#(AvHQ~nujWF~4l zXh$uirK_skq{s*JC%lv)>)_Yiv1%9tfLUMeU`n?u%RmXf+4J^HjC}J~(8lxE+{Slr zRo}_oM;AiQx^DD62WT%-_`rFnz86BcS*YFu|BUQdmUaD#xS�$%+hmH%F5SmX!{( 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 Y(&qu#Ma7?8Rs1Br2fssI20 literal 0 HcmV?d00001 diff --git a/immich_album_watcher/sensor.py b/immich_album_watcher/sensor.py index 162760e..288eb4d 100644 --- a/immich_album_watcher/sensor.py +++ b/immich_album_watcher/sensor.py @@ -51,9 +51,10 @@ class ImmichAlbumSensor(CoordinatorEntity[ImmichAlbumWatcherCoordinator], Sensor """Sensor representing an Immich album.""" _attr_state_class = SensorStateClass.MEASUREMENT - _attr_native_unit_of_measurement = "assets" _attr_icon = "mdi:image-album" + _attr_translation_key = "album_asset_count" + def __init__( self, coordinator: ImmichAlbumWatcherCoordinator, @@ -77,11 +78,11 @@ class ImmichAlbumSensor(CoordinatorEntity[ImmichAlbumWatcherCoordinator], Sensor return self.coordinator.data.get(self._album_id) @property - def name(self) -> str: - """Return the name of the sensor.""" + def translation_placeholders(self) -> dict[str, str]: + """Return translation placeholders.""" if self._album_data: - return self._album_data.name - return f"Album {self._album_id[:8]}" + return {"album_name": self._album_data.name} + return {"album_name": f"Album {self._album_id[:8]}"} @property def native_value(self) -> int | None: diff --git a/immich_album_watcher/strings.json b/immich_album_watcher/strings.json index ea69e75..0be111a 100644 --- a/immich_album_watcher/strings.json +++ b/immich_album_watcher/strings.json @@ -1,4 +1,11 @@ { + "entity": { + "sensor": { + "album_asset_count": { + "name": "{album_name}: Asset Count" + } + } + }, "config": { "step": { "user": { diff --git a/immich_album_watcher/translations/en.json b/immich_album_watcher/translations/en.json index ea69e75..0be111a 100644 --- a/immich_album_watcher/translations/en.json +++ b/immich_album_watcher/translations/en.json @@ -1,4 +1,11 @@ { + "entity": { + "sensor": { + "album_asset_count": { + "name": "{album_name}: Asset Count" + } + } + }, "config": { "step": { "user": { diff --git a/immich_album_watcher/translations/ru.json b/immich_album_watcher/translations/ru.json new file mode 100644 index 0000000..5a6eff7 --- /dev/null +++ b/immich_album_watcher/translations/ru.json @@ -0,0 +1,60 @@ +{ + "config": { + "step": { + "user": { + "title": "Подключение к Immich", + "description": "Введите данные вашего сервера Immich. API-ключ можно получить в Immich → Настройки пользователя → API-ключи.", + "data": { + "immich_url": "URL Immich", + "api_key": "API-ключ" + }, + "data_description": { + "immich_url": "URL вашего сервера Immich (например, http://192.168.1.100:2283)", + "api_key": "Ваш API-ключ Immich" + } + }, + "albums": { + "title": "Выбор альбомов", + "description": "Выберите альбомы для отслеживания изменений.", + "data": { + "albums": "Альбомы для отслеживания" + } + } + }, + "error": { + "cannot_connect": "Не удалось подключиться к серверу Immich", + "invalid_auth": "Неверный API-ключ", + "no_albums": "На сервере не найдено альбомов", + "no_albums_selected": "Пожалуйста, выберите хотя бы один альбом", + "unknown": "Произошла непредвиденная ошибка" + }, + "abort": { + "already_configured": "Этот сервер Immich уже настроен" + } + }, + "options": { + "step": { + "init": { + "title": "Настройки Immich Album Watcher", + "description": "Настройте отслеживаемые альбомы и частоту проверки изменений.", + "data": { + "albums": "Альбомы для отслеживания", + "scan_interval": "Интервал сканирования (секунды)" + }, + "data_description": { + "scan_interval": "Как часто проверять изменения в альбомах (10-3600 секунд)" + } + } + }, + "error": { + "cannot_connect": "Не удалось подключиться к серверу Immich" + } + }, + "entity": { + "sensor": { + "album_asset_count": { + "name": "{album_name}: Число файлов" + } + } + } +}