Kodi service addon that detects HDR/SDR state of the currently playing video and notifies external services: - HyperHDR: toggles tone mapping via videomodehdr JSON-RPC command - Home Assistant: sends HDR state via webhook trigger Supports Kodi 20 (Nexus) and later. Both targets are independently configurable with host, port, SSL, and authentication settings. Includes GitHub Actions workflow to build installable ZIP packages on every push and publish them as release assets on tags.
This commit is contained in:
@@ -0,0 +1,40 @@
|
|||||||
|
name: Build Kodi Addon
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [master]
|
||||||
|
tags: ["v*"]
|
||||||
|
pull_request:
|
||||||
|
branches: [master]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Extract version from addon.xml
|
||||||
|
id: version
|
||||||
|
run: |
|
||||||
|
version=$(grep -oP 'version="\K[^"]+' service.video.hdrnotify/addon.xml | head -1)
|
||||||
|
echo "version=$version" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "Addon version: $version"
|
||||||
|
|
||||||
|
- name: Build ZIP package
|
||||||
|
run: |
|
||||||
|
zip -r "service.video.hdrnotify-${{ steps.version.outputs.version }}.zip" \
|
||||||
|
service.video.hdrnotify/ \
|
||||||
|
-x "service.video.hdrnotify/.*"
|
||||||
|
|
||||||
|
- name: Upload artifact
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: service.video.hdrnotify-${{ steps.version.outputs.version }}
|
||||||
|
path: service.video.hdrnotify-${{ steps.version.outputs.version }}.zip
|
||||||
|
|
||||||
|
- name: Create Gitea Release
|
||||||
|
if: startsWith(github.ref, 'refs/tags/v')
|
||||||
|
uses: https://gitea.com/actions/gitea-release-action@v1
|
||||||
|
with:
|
||||||
|
files: service.video.hdrnotify-${{ steps.version.outputs.version }}.zip
|
||||||
|
token: '${{ secrets.GITHUB_TOKEN }}'
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
name: Build Kodi Addon
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [master]
|
||||||
|
tags: ["v*"]
|
||||||
|
pull_request:
|
||||||
|
branches: [master]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v6
|
||||||
|
|
||||||
|
- name: Extract version from addon.xml
|
||||||
|
id: version
|
||||||
|
run: |
|
||||||
|
version=$(grep -oP 'version="\K[^"]+' service.video.hdrnotify/addon.xml | head -1)
|
||||||
|
echo "version=$version" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "Addon version: $version"
|
||||||
|
|
||||||
|
- name: Build ZIP package
|
||||||
|
run: |
|
||||||
|
zip -r "service.video.hdrnotify-${{ steps.version.outputs.version }}.zip" \
|
||||||
|
service.video.hdrnotify/ \
|
||||||
|
-x "service.video.hdrnotify/.*"
|
||||||
|
|
||||||
|
- name: Upload artifact
|
||||||
|
uses: actions/upload-artifact@v7
|
||||||
|
with:
|
||||||
|
name: service.video.hdrnotify-${{ steps.version.outputs.version }}
|
||||||
|
path: service.video.hdrnotify-${{ steps.version.outputs.version }}.zip
|
||||||
|
|
||||||
|
- name: Create GitHub Release
|
||||||
|
if: startsWith(github.ref, 'refs/tags/v')
|
||||||
|
uses: softprops/action-gh-release@v3
|
||||||
|
with:
|
||||||
|
files: service.video.hdrnotify-${{ steps.version.outputs.version }}.zip
|
||||||
|
generate_release_notes: true
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2026 Oleksandr Berezovskyi
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
# HDR Notify for Kodi
|
||||||
|
|
||||||
|
A Kodi service addon that detects the HDR/SDR state of the currently playing video and sends it to external services -- so they can react automatically without relying on signal auto-detection.
|
||||||
|
|
||||||
|
## The Problem
|
||||||
|
|
||||||
|
[HyperHDR](https://github.com/awawa-dev/HyperHDR) provides ambient lighting with HDR tone mapping support, but it needs to know *when* to apply tone mapping. Automatic detection is unreliable on some setups, causing washed-out colors or incorrect tone mapping. Similarly, you may want [Home Assistant](https://www.home-assistant.io/) to react to HDR content -- for example, adjusting room lighting or triggering scenes.
|
||||||
|
|
||||||
|
## How It Works
|
||||||
|
|
||||||
|
```
|
||||||
|
Kodi (playing video)
|
||||||
|
|
|
||||||
|
| onAVStarted / onPlayBackStopped / onPlayBackEnded
|
||||||
|
|
|
||||||
|
v
|
||||||
|
HDR Notify (this addon)
|
||||||
|
|
|
||||||
|
| reads VideoPlayer.HdrType
|
||||||
|
|
|
||||||
|
|--- HyperHDR: POST /json-rpc {"command":"videomodehdr", "HDR": 1|0}
|
||||||
|
|
|
||||||
|
'--- Home Assistant: POST /api/webhook/<id> {"hdr": true|false, "hdr_type": "..."}
|
||||||
|
```
|
||||||
|
|
||||||
|
1. When video playback starts, the addon reads the [`VideoPlayer.HdrType`](https://kodi.wiki/view/InfoLabels) InfoLabel
|
||||||
|
2. Any non-empty value (e.g. `hdr10`, `dolbyvision`, `hlg`) means HDR is active
|
||||||
|
3. The addon sends the state to whichever targets are enabled
|
||||||
|
4. When playback stops or ends, it sends SDR (reset) to all enabled targets
|
||||||
|
|
||||||
|
Both targets are independent -- you can enable one, both, or neither.
|
||||||
|
|
||||||
|
## Compatibility
|
||||||
|
|
||||||
|
- **Kodi 20 (Nexus)** and later -- the `VideoPlayer.HdrType` InfoLabel was introduced in Kodi 20
|
||||||
|
- No external dependencies -- uses Python stdlib only
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
1. Go to the [Releases](../../releases) page
|
||||||
|
2. Download the latest `service.video.hdrnotify-*.zip`
|
||||||
|
3. In Kodi: **Settings > Add-ons > Install from zip file** > select the downloaded ZIP
|
||||||
|
4. Configure the addon via **Settings > Add-ons > My add-ons > Services > HDR Notify**
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
The addon settings are split into two tabs:
|
||||||
|
|
||||||
|
### HyperHDR
|
||||||
|
|
||||||
|
| Setting | Default | Description |
|
||||||
|
|---------|---------|-------------|
|
||||||
|
| Enable HyperHDR | On | Toggle HyperHDR notifications |
|
||||||
|
| Host | `127.0.0.1` | HyperHDR IP or hostname |
|
||||||
|
| Port | `8090` | JSON API port (default HTTPS port: `8443`) |
|
||||||
|
| Use HTTPS | Off | Connect via HTTPS |
|
||||||
|
| API Token | *(empty)* | Auth token, if [token-based authentication](https://github.com/awawa-dev/HyperHDR/wiki) is enabled |
|
||||||
|
|
||||||
|
The addon sends the [`videomodehdr`](https://github.com/awawa-dev/HyperHDR) command to the HyperHDR JSON API at `/json-rpc`.
|
||||||
|
|
||||||
|
### Home Assistant
|
||||||
|
|
||||||
|
| Setting | Default | Description |
|
||||||
|
|---------|---------|-------------|
|
||||||
|
| Enable Home Assistant | Off | Toggle HA webhook notifications |
|
||||||
|
| Host | `127.0.0.1` | Home Assistant IP or hostname |
|
||||||
|
| Port | `8123` | HA port |
|
||||||
|
| Use HTTPS | Off | Connect via HTTPS |
|
||||||
|
| Webhook ID | *(empty)* | The webhook ID from your HA automation trigger |
|
||||||
|
|
||||||
|
The addon sends a JSON payload to the HA [webhook trigger](https://www.home-assistant.io/docs/automation/trigger/#webhook-trigger) endpoint:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{"hdr": true, "hdr_type": "hdr10"}
|
||||||
|
```
|
||||||
|
|
||||||
|
No authentication token is needed -- HA webhooks are auth-free by design.
|
||||||
|
|
||||||
|
#### Example Home Assistant Automation
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
automation:
|
||||||
|
- alias: "React to Kodi HDR state"
|
||||||
|
trigger:
|
||||||
|
- platform: webhook
|
||||||
|
webhook_id: "kodi_hdr_state"
|
||||||
|
allowed_methods:
|
||||||
|
- POST
|
||||||
|
local_only: true
|
||||||
|
action:
|
||||||
|
- choose:
|
||||||
|
- conditions:
|
||||||
|
- condition: template
|
||||||
|
value_template: "{{ trigger.json.hdr }}"
|
||||||
|
sequence:
|
||||||
|
- service: light.turn_off
|
||||||
|
target:
|
||||||
|
entity_id: light.living_room
|
||||||
|
default:
|
||||||
|
- service: light.turn_on
|
||||||
|
target:
|
||||||
|
entity_id: light.living_room
|
||||||
|
```
|
||||||
|
|
||||||
|
## Related Projects
|
||||||
|
|
||||||
|
- [HyperHDR](https://github.com/awawa-dev/HyperHDR) -- Open-source ambient lighting with HDR tone mapping
|
||||||
|
- [Home Assistant](https://www.home-assistant.io/) -- Open-source home automation platform
|
||||||
|
- [Kodi](https://kodi.tv/) -- Open-source media center
|
||||||
|
- [CoreELEC](https://coreelec.org/) -- Lightweight Kodi-focused OS for Amlogic devices
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
[MIT](LICENSE.md)
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
|
<addon id="service.video.hdrnotify"
|
||||||
|
name="HDR Notify"
|
||||||
|
version="1.0.0"
|
||||||
|
provider-name="Oleksandr">
|
||||||
|
<requires>
|
||||||
|
<import addon="xbmc.python" version="3.0.0"/>
|
||||||
|
</requires>
|
||||||
|
<extension point="xbmc.service" library="service.py"/>
|
||||||
|
<extension point="xbmc.addon.metadata">
|
||||||
|
<summary lang="en_GB">Notifies HyperHDR and Home Assistant about HDR/SDR playback state</summary>
|
||||||
|
<summary lang="uk_UA">Сповіщає HyperHDR та Home Assistant про стан HDR/SDR відтворення</summary>
|
||||||
|
<description lang="en_GB">Automatically detects HDR/SDR mode of currently playing video and sends the state to HyperHDR (to toggle tone mapping) and/or Home Assistant (via webhook). Supports Kodi 20 (Nexus) and later.</description>
|
||||||
|
<description lang="uk_UA">Автоматично визначає режим HDR/SDR поточного відео та надсилає стан до HyperHDR (для перемикання тонального відображення) та/або Home Assistant (через вебхук). Підтримує Kodi 20 (Nexus) та новіші версії.</description>
|
||||||
|
<platform>all</platform>
|
||||||
|
<license>MIT</license>
|
||||||
|
</extension>
|
||||||
|
</addon>
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
# Kodi Media Center language file
|
||||||
|
# Addon Name: HDR Notify
|
||||||
|
# Addon id: service.video.hdrnotify
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: service.video.hdrnotify\n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"PO-Revision-Date: 2026-03-21 00:00+0000\n"
|
||||||
|
"Last-Translator: \n"
|
||||||
|
"Language-Team: English\n"
|
||||||
|
"Language: en\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
|
|
||||||
|
# Category labels
|
||||||
|
msgctxt "#32001"
|
||||||
|
msgid "HyperHDR"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgctxt "#32002"
|
||||||
|
msgid "Home Assistant"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
# HyperHDR settings
|
||||||
|
msgctxt "#32010"
|
||||||
|
msgid "Enable HyperHDR"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgctxt "#32011"
|
||||||
|
msgid "Send HDR/SDR state to HyperHDR when playback starts or stops"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgctxt "#32012"
|
||||||
|
msgid "HyperHDR host"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgctxt "#32013"
|
||||||
|
msgid "IP address or hostname of your HyperHDR instance"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgctxt "#32014"
|
||||||
|
msgid "HyperHDR port"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgctxt "#32015"
|
||||||
|
msgid "Port number for HyperHDR JSON API"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgctxt "#32016"
|
||||||
|
msgid "Use HTTPS"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgctxt "#32017"
|
||||||
|
msgid "Connect to HyperHDR using HTTPS (default port: 8443)"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgctxt "#32018"
|
||||||
|
msgid "API token"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgctxt "#32019"
|
||||||
|
msgid "Authentication token (leave empty if authentication is disabled)"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
# Home Assistant settings
|
||||||
|
msgctxt "#32030"
|
||||||
|
msgid "Enable Home Assistant"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgctxt "#32031"
|
||||||
|
msgid "Send HDR/SDR state to Home Assistant via webhook"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgctxt "#32032"
|
||||||
|
msgid "Home Assistant host"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgctxt "#32033"
|
||||||
|
msgid "IP address or hostname of your Home Assistant instance"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgctxt "#32034"
|
||||||
|
msgid "Home Assistant port"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgctxt "#32035"
|
||||||
|
msgid "Port number for Home Assistant"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgctxt "#32036"
|
||||||
|
msgid "Use HTTPS"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgctxt "#32037"
|
||||||
|
msgid "Connect to Home Assistant using HTTPS"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgctxt "#32038"
|
||||||
|
msgid "Webhook ID"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgctxt "#32039"
|
||||||
|
msgid "Webhook ID from your Home Assistant automation trigger"
|
||||||
|
msgstr ""
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
# Kodi Media Center language file
|
||||||
|
# Addon Name: HDR Notify
|
||||||
|
# Addon id: service.video.hdrnotify
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: service.video.hdrnotify\n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"PO-Revision-Date: 2026-03-21 00:00+0000\n"
|
||||||
|
"Last-Translator: \n"
|
||||||
|
"Language-Team: Ukrainian\n"
|
||||||
|
"Language: uk\n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
|
||||||
|
|
||||||
|
# Category labels
|
||||||
|
msgctxt "#32001"
|
||||||
|
msgid "HyperHDR"
|
||||||
|
msgstr "HyperHDR"
|
||||||
|
|
||||||
|
msgctxt "#32002"
|
||||||
|
msgid "Home Assistant"
|
||||||
|
msgstr "Home Assistant"
|
||||||
|
|
||||||
|
# HyperHDR settings
|
||||||
|
msgctxt "#32010"
|
||||||
|
msgid "Enable HyperHDR"
|
||||||
|
msgstr "Увімкнути HyperHDR"
|
||||||
|
|
||||||
|
msgctxt "#32011"
|
||||||
|
msgid "Send HDR/SDR state to HyperHDR when playback starts or stops"
|
||||||
|
msgstr "Надсилати стан HDR/SDR до HyperHDR при початку або зупинці відтворення"
|
||||||
|
|
||||||
|
msgctxt "#32012"
|
||||||
|
msgid "HyperHDR host"
|
||||||
|
msgstr "Хост HyperHDR"
|
||||||
|
|
||||||
|
msgctxt "#32013"
|
||||||
|
msgid "IP address or hostname of your HyperHDR instance"
|
||||||
|
msgstr "IP-адреса або ім'я хоста вашого HyperHDR"
|
||||||
|
|
||||||
|
msgctxt "#32014"
|
||||||
|
msgid "HyperHDR port"
|
||||||
|
msgstr "Порт HyperHDR"
|
||||||
|
|
||||||
|
msgctxt "#32015"
|
||||||
|
msgid "Port number for HyperHDR JSON API"
|
||||||
|
msgstr "Номер порту для JSON API HyperHDR"
|
||||||
|
|
||||||
|
msgctxt "#32016"
|
||||||
|
msgid "Use HTTPS"
|
||||||
|
msgstr "Використовувати HTTPS"
|
||||||
|
|
||||||
|
msgctxt "#32017"
|
||||||
|
msgid "Connect to HyperHDR using HTTPS (default port: 8443)"
|
||||||
|
msgstr "Підключатися до HyperHDR через HTTPS (порт за замовчуванням: 8443)"
|
||||||
|
|
||||||
|
msgctxt "#32018"
|
||||||
|
msgid "API token"
|
||||||
|
msgstr "Токен API"
|
||||||
|
|
||||||
|
msgctxt "#32019"
|
||||||
|
msgid "Authentication token (leave empty if authentication is disabled)"
|
||||||
|
msgstr "Токен автентифікації (залиште порожнім, якщо автентифікація вимкнена)"
|
||||||
|
|
||||||
|
# Home Assistant settings
|
||||||
|
msgctxt "#32030"
|
||||||
|
msgid "Enable Home Assistant"
|
||||||
|
msgstr "Увімкнути Home Assistant"
|
||||||
|
|
||||||
|
msgctxt "#32031"
|
||||||
|
msgid "Send HDR/SDR state to Home Assistant via webhook"
|
||||||
|
msgstr "Надсилати стан HDR/SDR до Home Assistant через вебхук"
|
||||||
|
|
||||||
|
msgctxt "#32032"
|
||||||
|
msgid "Home Assistant host"
|
||||||
|
msgstr "Хост Home Assistant"
|
||||||
|
|
||||||
|
msgctxt "#32033"
|
||||||
|
msgid "IP address or hostname of your Home Assistant instance"
|
||||||
|
msgstr "IP-адреса або ім'я хоста вашого Home Assistant"
|
||||||
|
|
||||||
|
msgctxt "#32034"
|
||||||
|
msgid "Home Assistant port"
|
||||||
|
msgstr "Порт Home Assistant"
|
||||||
|
|
||||||
|
msgctxt "#32035"
|
||||||
|
msgid "Port number for Home Assistant"
|
||||||
|
msgstr "Номер порту Home Assistant"
|
||||||
|
|
||||||
|
msgctxt "#32036"
|
||||||
|
msgid "Use HTTPS"
|
||||||
|
msgstr "Використовувати HTTPS"
|
||||||
|
|
||||||
|
msgctxt "#32037"
|
||||||
|
msgid "Connect to Home Assistant using HTTPS"
|
||||||
|
msgstr "Підключатися до Home Assistant через HTTPS"
|
||||||
|
|
||||||
|
msgctxt "#32038"
|
||||||
|
msgid "Webhook ID"
|
||||||
|
msgstr "Ідентифікатор вебхука"
|
||||||
|
|
||||||
|
msgctxt "#32039"
|
||||||
|
msgid "Webhook ID from your Home Assistant automation trigger"
|
||||||
|
msgstr "Ідентифікатор вебхука з тригера автоматизації Home Assistant"
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<settings version="2">
|
||||||
|
<section id="main">
|
||||||
|
<category id="hyperhdr" label="32001">
|
||||||
|
<group id="1">
|
||||||
|
<setting id="hyperhdr_enabled" type="boolean" label="32010" help="32011">
|
||||||
|
<level>0</level>
|
||||||
|
<default>true</default>
|
||||||
|
<control type="toggle"/>
|
||||||
|
</setting>
|
||||||
|
<setting id="hyperhdr_host" type="string" label="32012" help="32013">
|
||||||
|
<level>0</level>
|
||||||
|
<default>127.0.0.1</default>
|
||||||
|
<dependencies>
|
||||||
|
<dependency type="visible" setting="hyperhdr_enabled">true</dependency>
|
||||||
|
</dependencies>
|
||||||
|
<constraints>
|
||||||
|
<allowempty>false</allowempty>
|
||||||
|
</constraints>
|
||||||
|
<control type="edit" format="string"/>
|
||||||
|
</setting>
|
||||||
|
<setting id="hyperhdr_port" type="integer" label="32014" help="32015">
|
||||||
|
<level>0</level>
|
||||||
|
<default>8090</default>
|
||||||
|
<dependencies>
|
||||||
|
<dependency type="visible" setting="hyperhdr_enabled">true</dependency>
|
||||||
|
</dependencies>
|
||||||
|
<constraints>
|
||||||
|
<minimum>1</minimum>
|
||||||
|
<maximum>65535</maximum>
|
||||||
|
</constraints>
|
||||||
|
<control type="edit" format="integer"/>
|
||||||
|
</setting>
|
||||||
|
<setting id="hyperhdr_ssl" type="boolean" label="32016" help="32017">
|
||||||
|
<level>0</level>
|
||||||
|
<default>false</default>
|
||||||
|
<dependencies>
|
||||||
|
<dependency type="visible" setting="hyperhdr_enabled">true</dependency>
|
||||||
|
</dependencies>
|
||||||
|
<control type="toggle"/>
|
||||||
|
</setting>
|
||||||
|
<setting id="hyperhdr_token" type="string" label="32018" help="32019">
|
||||||
|
<level>0</level>
|
||||||
|
<default></default>
|
||||||
|
<dependencies>
|
||||||
|
<dependency type="visible" setting="hyperhdr_enabled">true</dependency>
|
||||||
|
</dependencies>
|
||||||
|
<constraints>
|
||||||
|
<allowempty>true</allowempty>
|
||||||
|
</constraints>
|
||||||
|
<control type="edit" format="string">
|
||||||
|
<hidden>true</hidden>
|
||||||
|
</control>
|
||||||
|
</setting>
|
||||||
|
</group>
|
||||||
|
</category>
|
||||||
|
<category id="homeassistant" label="32002">
|
||||||
|
<group id="1">
|
||||||
|
<setting id="ha_enabled" type="boolean" label="32030" help="32031">
|
||||||
|
<level>0</level>
|
||||||
|
<default>false</default>
|
||||||
|
<control type="toggle"/>
|
||||||
|
</setting>
|
||||||
|
<setting id="ha_host" type="string" label="32032" help="32033">
|
||||||
|
<level>0</level>
|
||||||
|
<default>127.0.0.1</default>
|
||||||
|
<dependencies>
|
||||||
|
<dependency type="visible" setting="ha_enabled">true</dependency>
|
||||||
|
</dependencies>
|
||||||
|
<constraints>
|
||||||
|
<allowempty>false</allowempty>
|
||||||
|
</constraints>
|
||||||
|
<control type="edit" format="string"/>
|
||||||
|
</setting>
|
||||||
|
<setting id="ha_port" type="integer" label="32034" help="32035">
|
||||||
|
<level>0</level>
|
||||||
|
<default>8123</default>
|
||||||
|
<dependencies>
|
||||||
|
<dependency type="visible" setting="ha_enabled">true</dependency>
|
||||||
|
</dependencies>
|
||||||
|
<constraints>
|
||||||
|
<minimum>1</minimum>
|
||||||
|
<maximum>65535</maximum>
|
||||||
|
</constraints>
|
||||||
|
<control type="edit" format="integer"/>
|
||||||
|
</setting>
|
||||||
|
<setting id="ha_ssl" type="boolean" label="32036" help="32037">
|
||||||
|
<level>0</level>
|
||||||
|
<default>false</default>
|
||||||
|
<dependencies>
|
||||||
|
<dependency type="visible" setting="ha_enabled">true</dependency>
|
||||||
|
</dependencies>
|
||||||
|
<control type="toggle"/>
|
||||||
|
</setting>
|
||||||
|
<setting id="ha_webhook_id" type="string" label="32038" help="32039">
|
||||||
|
<level>0</level>
|
||||||
|
<default></default>
|
||||||
|
<dependencies>
|
||||||
|
<dependency type="visible" setting="ha_enabled">true</dependency>
|
||||||
|
</dependencies>
|
||||||
|
<constraints>
|
||||||
|
<allowempty>true</allowempty>
|
||||||
|
</constraints>
|
||||||
|
<control type="edit" format="string"/>
|
||||||
|
</setting>
|
||||||
|
</group>
|
||||||
|
</category>
|
||||||
|
</section>
|
||||||
|
</settings>
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
import json
|
||||||
|
import ssl
|
||||||
|
import urllib.request
|
||||||
|
|
||||||
|
import xbmc
|
||||||
|
import xbmcaddon
|
||||||
|
|
||||||
|
ADDON_ID = "service.video.hdrnotify"
|
||||||
|
LOG_PREFIX = "[HDR Notify]"
|
||||||
|
|
||||||
|
|
||||||
|
def log(msg, level=xbmc.LOGINFO):
|
||||||
|
xbmc.log(f"{LOG_PREFIX} {msg}", level)
|
||||||
|
|
||||||
|
|
||||||
|
def read_settings():
|
||||||
|
addon = xbmcaddon.Addon(ADDON_ID)
|
||||||
|
return {
|
||||||
|
"hyperhdr_enabled": addon.getSettingBool("hyperhdr_enabled"),
|
||||||
|
"hyperhdr_host": addon.getSetting("hyperhdr_host"),
|
||||||
|
"hyperhdr_port": addon.getSettingInt("hyperhdr_port"),
|
||||||
|
"hyperhdr_ssl": addon.getSettingBool("hyperhdr_ssl"),
|
||||||
|
"hyperhdr_token": addon.getSetting("hyperhdr_token"),
|
||||||
|
"ha_enabled": addon.getSettingBool("ha_enabled"),
|
||||||
|
"ha_host": addon.getSetting("ha_host"),
|
||||||
|
"ha_port": addon.getSettingInt("ha_port"),
|
||||||
|
"ha_ssl": addon.getSettingBool("ha_ssl"),
|
||||||
|
"ha_webhook_id": addon.getSetting("ha_webhook_id"),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _post_json(url, data, use_ssl=False):
|
||||||
|
payload = json.dumps(data).encode("utf-8")
|
||||||
|
req = urllib.request.Request(
|
||||||
|
url, data=payload, headers={"Content-Type": "application/json"}
|
||||||
|
)
|
||||||
|
ctx = None
|
||||||
|
if use_ssl:
|
||||||
|
ctx = ssl.create_default_context()
|
||||||
|
urllib.request.urlopen(req, timeout=2, context=ctx)
|
||||||
|
|
||||||
|
|
||||||
|
def notify_hyperhdr(settings, is_hdr):
|
||||||
|
host = settings["hyperhdr_host"]
|
||||||
|
port = settings["hyperhdr_port"]
|
||||||
|
if not host:
|
||||||
|
return
|
||||||
|
scheme = "https" if settings["hyperhdr_ssl"] else "http"
|
||||||
|
url = f"{scheme}://{host}:{port}/json-rpc"
|
||||||
|
use_ssl = settings["hyperhdr_ssl"]
|
||||||
|
try:
|
||||||
|
token = settings["hyperhdr_token"]
|
||||||
|
if token:
|
||||||
|
_post_json(
|
||||||
|
url,
|
||||||
|
{"command": "authorize", "subcommand": "login", "token": token},
|
||||||
|
use_ssl,
|
||||||
|
)
|
||||||
|
_post_json(
|
||||||
|
url,
|
||||||
|
{"command": "videomodehdr", "tan": 1, "HDR": 1 if is_hdr else 0},
|
||||||
|
use_ssl,
|
||||||
|
)
|
||||||
|
log(f"HyperHDR notified: HDR={'on' if is_hdr else 'off'}")
|
||||||
|
except Exception as e:
|
||||||
|
log(f"HyperHDR error: {e}", xbmc.LOGWARNING)
|
||||||
|
|
||||||
|
|
||||||
|
def notify_homeassistant(settings, is_hdr, hdr_type):
|
||||||
|
host = settings["ha_host"]
|
||||||
|
webhook_id = settings["ha_webhook_id"]
|
||||||
|
if not host or not webhook_id:
|
||||||
|
return
|
||||||
|
port = settings["ha_port"]
|
||||||
|
scheme = "https" if settings["ha_ssl"] else "http"
|
||||||
|
url = f"{scheme}://{host}:{port}/api/webhook/{webhook_id}"
|
||||||
|
try:
|
||||||
|
_post_json(
|
||||||
|
url,
|
||||||
|
{"hdr": is_hdr, "hdr_type": hdr_type},
|
||||||
|
settings["ha_ssl"],
|
||||||
|
)
|
||||||
|
log(f"Home Assistant notified: hdr={is_hdr}, hdr_type='{hdr_type}'")
|
||||||
|
except Exception as e:
|
||||||
|
log(f"Home Assistant error: {e}", xbmc.LOGWARNING)
|
||||||
|
|
||||||
|
|
||||||
|
def notify_targets(settings, is_hdr, hdr_type=""):
|
||||||
|
if settings["hyperhdr_enabled"]:
|
||||||
|
notify_hyperhdr(settings, is_hdr)
|
||||||
|
if settings["ha_enabled"]:
|
||||||
|
notify_homeassistant(settings, is_hdr, hdr_type)
|
||||||
|
|
||||||
|
|
||||||
|
class HDRMonitor(xbmc.Monitor):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.settings = read_settings()
|
||||||
|
|
||||||
|
def onSettingsChanged(self):
|
||||||
|
self.settings = read_settings()
|
||||||
|
log("Settings reloaded")
|
||||||
|
|
||||||
|
|
||||||
|
class HDRPlayer(xbmc.Player):
|
||||||
|
def __init__(self, monitor):
|
||||||
|
super().__init__()
|
||||||
|
self._monitor = monitor
|
||||||
|
|
||||||
|
def onAVStarted(self):
|
||||||
|
hdr_type = xbmc.getInfoLabel("VideoPlayer.HdrType")
|
||||||
|
is_hdr = bool(hdr_type)
|
||||||
|
log(f"Playback started: hdr_type='{hdr_type}', is_hdr={is_hdr}")
|
||||||
|
notify_targets(self._monitor.settings, is_hdr, hdr_type)
|
||||||
|
|
||||||
|
def onPlayBackStopped(self):
|
||||||
|
log("Playback stopped")
|
||||||
|
notify_targets(self._monitor.settings, False)
|
||||||
|
|
||||||
|
def onPlayBackEnded(self):
|
||||||
|
log("Playback ended")
|
||||||
|
notify_targets(self._monitor.settings, False)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
log("Service started")
|
||||||
|
monitor = HDRMonitor()
|
||||||
|
player = HDRPlayer(monitor)
|
||||||
|
|
||||||
|
while not monitor.abortRequested():
|
||||||
|
if monitor.waitForAbort(1):
|
||||||
|
break
|
||||||
|
|
||||||
|
log("Service stopped")
|
||||||
Reference in New Issue
Block a user