2026-05-09 magic4pc: tv-luna-send wrapper, Back+keyboard fix, deploy docs
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -58,52 +58,62 @@ cd ~/Developer/magic4pc/webos
|
|||||||
NODE_OPTIONS=--openssl-legacy-provider npm run build
|
NODE_OPTIONS=--openssl-legacy-provider npm run build
|
||||||
```
|
```
|
||||||
|
|
||||||
Требует `--openssl-legacy-provider` — старый webpack несовместим с Node 25.
|
> ⚠️ Требует `--openssl-legacy-provider` — старый webpack несовместим с Node 25.
|
||||||
|
|
||||||
## Сборка IPK
|
## Сборка IPK
|
||||||
|
|
||||||
|
```bash
|
||||||
|
/Users/admin/webOS_TV_SDK/CLI/bin/ares-package dist/ service/ --outdir .
|
||||||
|
```
|
||||||
|
|
||||||
|
> ⚠️ Оба аргумента `dist/ service/` обязательны — иначе сервис не попадёт в IPK.
|
||||||
|
> ⚠️ `npm run package` = `ares-package -n` (unsigned) — **не использовать**, TV отклоняет.
|
||||||
|
|
||||||
|
## Деплой на TV (192.168.1.75)
|
||||||
|
|
||||||
|
### Правильный способ — deploy.sh
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/Developer/magic4pc/webos
|
||||||
|
./deploy.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Скрипт делает всё: build → package → scp → close → remove → install → launch.
|
||||||
|
|
||||||
|
Использует `~/Automations/tv-luna-send.sh` для close/remove/launch.
|
||||||
|
Для install (`-i` subscribe) — прямой ssh+script с polling на `"state":"installed"`.
|
||||||
|
|
||||||
|
> ⚠️ **Не использовать `ares-install` / `ares-launch`** — не ждут завершения, работают ненадёжно.
|
||||||
|
> ⚠️ `luna-send` без PTY молчит — см. [[tv-luna-send]].
|
||||||
|
|
||||||
|
<details><summary>Ручной деплой</summary>
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd ~/Developer/magic4pc/webos
|
cd ~/Developer/magic4pc/webos
|
||||||
NODE_OPTIONS=--openssl-legacy-provider npm run build
|
NODE_OPTIONS=--openssl-legacy-provider npm run build
|
||||||
/Users/admin/webOS_TV_SDK/CLI/bin/ares-package dist/ service/ --outdir .
|
/Users/admin/webOS_TV_SDK/CLI/bin/ares-package dist/ service/ --outdir .
|
||||||
# Создаёт me.wouterdek.magic4pc_1.1.0_all.ipk
|
|
||||||
```
|
|
||||||
|
|
||||||
> ⚠️ `ares-package dist/ service/` — оба аргумента обязательны, иначе сервис не попадёт в IPK.
|
|
||||||
> `npm run package` = `ares-package -n` (без подписи) — **не использовать**, TV отклоняет IPK.
|
|
||||||
|
|
||||||
## Деплой на TV (192.168.1.75)
|
|
||||||
|
|
||||||
TV рутован, SSH без пароля: `ssh root@192.168.1.75`
|
|
||||||
|
|
||||||
> ⚠️ `luna-send` через SSH не выводит ответ в stdout — нужен PTY через `script`:
|
|
||||||
> `ssh root@192.168.1.75 "script -q -c \"luna-send -n 1 -f luna://...\" /tmp/o.txt; cat /tmp/o.txt"`
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 1. Скопировать IPK на TV
|
|
||||||
scp me.wouterdek.magic4pc_1.1.0_all.ipk root@192.168.1.75:/tmp/magic4pc.ipk
|
scp me.wouterdek.magic4pc_1.1.0_all.ipk root@192.168.1.75:/tmp/magic4pc.ipk
|
||||||
|
|
||||||
# 2. Закрыть приложение
|
~/Automations/tv-luna-send.sh -n 1 -f luna://com.webos.service.applicationmanager/closeByAppId '{"id":"me.wouterdek.magic4pc"}' || true
|
||||||
ssh root@192.168.1.75 "script -q -c \"luna-send -n 1 -f luna://com.webos.service.applicationmanager/closeByAppId '{\\\"id\\\":\\\"me.wouterdek.magic4pc\\\"}'\" /tmp/o.txt; cat /tmp/o.txt"
|
~/Automations/tv-luna-send.sh -n 1 -f luna://com.webos.appInstallService/dev/remove '{"id":"me.wouterdek.magic4pc"}' || true
|
||||||
|
sleep 2
|
||||||
|
|
||||||
# 3. Удалить старую версию
|
# install — через прямой script (luna-send -i не работает через враппер)
|
||||||
ssh root@192.168.1.75 "script -q -c \"luna-send -n 1 -f luna://com.webos.appInstallService/dev/remove '{\\\"id\\\":\\\"me.wouterdek.magic4pc\\\"}'\" /tmp/o.txt; cat /tmp/o.txt"
|
ssh root@192.168.1.75 "script -q -c \"luna-send -i -f luna://com.webos.appInstallService/dev/install '{\\\"id\\\":\\\"me.wouterdek.magic4pc\\\",\\\"ipkUrl\\\":\\\"/tmp/magic4pc.ipk\\\",\\\"subscribe\\\":true}'\" /tmp/install.txt &
|
||||||
|
for i in \$(seq 1 30); do sleep 1; grep -q '\"state\":\"installed\"' /tmp/install.txt 2>/dev/null && break; done
|
||||||
|
kill %1 2>/dev/null; grep -v '^Script ' /tmp/install.txt; rm -f /tmp/install.txt"
|
||||||
|
|
||||||
# 4. Установить новую (через PTY — иначе нет вывода)
|
~/Automations/tv-luna-send.sh -n 1 -f luna://com.webos.applicationManager/launch '{"id":"me.wouterdek.magic4pc"}'
|
||||||
ssh root@192.168.1.75 "script -q -c \"luna-send -i -f luna://com.webos.appInstallService/dev/install '{\\\"id\\\":\\\"me.wouterdek.magic4pc\\\",\\\"ipkUrl\\\":\\\"/tmp/magic4pc.ipk\\\",\\\"subscribe\\\":true}'\" /tmp/o.txt; cat /tmp/o.txt"
|
|
||||||
# Ждать "state": "installed" в выводе
|
|
||||||
|
|
||||||
# 5. Запустить
|
|
||||||
ssh root@192.168.1.75 "script -q -c \"luna-send -n 1 -f luna://com.webos.applicationManager/launch '{\\\"id\\\":\\\"me.wouterdek.magic4pc\\\"}'\" /tmp/o.txt; cat /tmp/o.txt"
|
|
||||||
```
|
```
|
||||||
|
</details>
|
||||||
|
|
||||||
### Проверка логов сервиса
|
### Проверка статуса сервиса
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
ssh root@192.168.1.75 "script -q -c \"luna-send -n 1 -f luna://me.wouterdek.magic4pc.service/query '{}'\" /tmp/o.txt; cat /tmp/o.txt"
|
~/Automations/tv-luna-send.sh -n 1 -f luna://me.wouterdek.magic4pc.service/query '{}'
|
||||||
```
|
```
|
||||||
|
|
||||||
Ожидаемый результат: `serviceActive: true`, `broadcastAdsActive: true` (или `isConnected: true` если HTPC подключён), в логах — `listApps: returned N apps`.
|
Ожидаемый результат: `serviceActive: true`, `broadcastAdsActive: true`.
|
||||||
|
|
||||||
## Деплой Go-клиента на HTPC
|
## Деплой Go-клиента на HTPC
|
||||||
|
|
||||||
@@ -129,101 +139,84 @@ ssh bazzite@192.168.1.86 "systemctl --user restart magic4pc"
|
|||||||
|
|
||||||
## Auto-launch при boot/wake
|
## Auto-launch при boot/wake
|
||||||
|
|
||||||
Magic4pc автоматически запускает выбранный app (VK Video, Кинопоиск, last used) при включении TV.
|
Magic4pc автоматически запускает выбранный app при включении TV.
|
||||||
|
|
||||||
### Логика
|
### Логика
|
||||||
|
|
||||||
- **Boot (полный ребут)** — `/tmp` чистится → нет `/tmp/magic4pc-run-state` → `freshStart=true` → запускает app
|
- **Boot** — `/tmp` чистится → нет `run-state` → `freshStart=true` → запускает app
|
||||||
- **Wake (standby→on) с последним активным app** — init.d при Suspend удаляет `run-state` → при wake нет файла → `freshStart=true` → запускает app
|
- **Wake** — init.d при Suspend удаляет `run-state` → при wake `freshStart=true` → запускает app
|
||||||
- **Wake после HDMI/EIM source** — если последний активный был HDMI (`com.webos.app.hdmi*`) — init.d при Suspend тоже удаляет `run-state` (TODO: можно улучшить), magic4pc по wake не запускает чужой app если пользователь вручную переключился на HDMI перед сном
|
- **Ручной запуск** — `run-state=running` уже есть → `freshStart=false` → ничего не запускает ✅
|
||||||
- **Ручной запуск magic4pc** (пользователь сам открыл) — `run-state = running` уже есть → `freshStart=false` → ничего не запускает ✅
|
|
||||||
|
|
||||||
### Файлы persistent storage
|
### Файлы persistent storage
|
||||||
|
|
||||||
Сервис (UID 5078, jail) имеет доступ только к `/tmp` и своей директории:
|
`PERSISTENT_DIR = /media/developer/apps/usr/palm/services/me.wouterdek.magic4pc.service`
|
||||||
|
|
||||||
| Файл | Где | Что |
|
| Файл | Где | Что |
|
||||||
|------|-----|-----|
|
|------|-----|-----|
|
||||||
| `magic4pc-settings` | `PERSISTENT_DIR/` | Выбранный app: appId / `__last_used__` / `none` |
|
| `magic4pc-settings` | `PERSISTENT_DIR/` | Выбранный app: appId / `__last_used__` / `none` |
|
||||||
| `magic4pc-last-app` | `PERSISTENT_DIR/` | Последний foreground app (пишет init.d + сервис) |
|
| `magic4pc-last-app` | `PERSISTENT_DIR/` | Последний foreground app |
|
||||||
| `magic4pc-run-state` | `/tmp/` | `running` = уже запускался после boot/wake |
|
| `magic4pc-run-state` | `/tmp/` | `running` = уже запускался после boot/wake |
|
||||||
|
|
||||||
`PERSISTENT_DIR = /media/developer/apps/usr/palm/services/me.wouterdek.magic4pc.service`
|
|
||||||
|
|
||||||
Init.d (root) копирует `last-app` в `PERSISTENT_DIR` при каждом обновлении foreground.
|
|
||||||
|
|
||||||
### Init.d скрипт
|
### Init.d скрипт
|
||||||
|
|
||||||
Файл на TV: `/var/lib/webosbrew/init.d/magic4pc`
|
Файл на TV: `/var/lib/webosbrew/init.d/magic4pc`
|
||||||
Исходник в репо: `tv-scripts/init.d-magic4pc.sh`
|
Исходник: `tv-scripts/init.d-magic4pc.sh` в репо
|
||||||
|
|
||||||
**Что делает:**
|
|
||||||
- При старте: удаляет `/tmp/magic4pc-run-state` (fresh boot)
|
|
||||||
- `track_foreground` — каждые 3 сек пишет foreground app в `/tmp/magic4pc-last-app` и `PERSISTENT_DIR/magic4pc-last-app`
|
|
||||||
- `monitor_power` — при Suspend удаляет `run-state` чтобы wake выглядел как fresh start
|
|
||||||
- Каждые 5 мин обновляет `/tmp/magic4pc-apps.json` (список app для Dropdown)
|
|
||||||
|
|
||||||
**Деплой init.d:**
|
|
||||||
```bash
|
```bash
|
||||||
|
# Деплой
|
||||||
scp tv-scripts/init.d-magic4pc.sh root@192.168.1.75:/var/lib/webosbrew/init.d/magic4pc
|
scp tv-scripts/init.d-magic4pc.sh root@192.168.1.75:/var/lib/webosbrew/init.d/magic4pc
|
||||||
ssh root@192.168.1.75 "chmod +x /var/lib/webosbrew/init.d/magic4pc"
|
ssh root@192.168.1.75 "chmod +x /var/lib/webosbrew/init.d/magic4pc"
|
||||||
# Изменения применяются после ребута TV (init.d запускается Homebrew Channel при старте)
|
# Применяется после ребута TV
|
||||||
```
|
```
|
||||||
|
|
||||||
> ⚠️ **Правило**: init.d всегда правится локально в репо (`tv-scripts/init.d-magic4pc.sh`), затем деплоится на TV через `scp`. Никогда не редактировать файл на TV напрямую — изменения не попадут в репо.
|
> ⚠️ Всегда править в репо, не на TV напрямую.
|
||||||
|
|
||||||
### Деплой IPK (правильный способ)
|
## Отладка
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd ~/Developer/magic4pc/webos
|
# Лог UI (appendLogPersist пишет сюда)
|
||||||
./deploy.sh
|
ssh root@192.168.1.75 "tail -30 /tmp/m4p_debug.log"
|
||||||
```
|
|
||||||
|
|
||||||
Скрипт делает всё: build → package → scp → install → launch. Ждёт `"state": "installed"` и запускает.
|
# Run-state
|
||||||
|
|
||||||
> ⚠️ `npm run package` = `ares-package -n` (unsigned) — **не использовать**, TV отклоняет.
|
|
||||||
> ⚠️ `luna-send` без PTY (`script`) молчит — в скрипте уже учтено.
|
|
||||||
|
|
||||||
<details><summary>Ручной деплой (если нужно)</summary>
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 1. Собрать и упаковать
|
|
||||||
cd ~/Developer/magic4pc/webos
|
|
||||||
NODE_OPTIONS=--openssl-legacy-provider npm run build
|
|
||||||
/Users/admin/webOS_TV_SDK/CLI/bin/ares-package dist/ service/ --outdir .
|
|
||||||
|
|
||||||
# 2. Скопировать на TV
|
|
||||||
scp me.wouterdek.magic4pc_1.1.0_all.ipk root@192.168.1.75:/tmp/magic4pc.ipk
|
|
||||||
|
|
||||||
# 3. Установить (через PTY — иначе нет вывода)
|
|
||||||
ssh root@192.168.1.75 'script -q -c "luna-send -i -f luna://com.webos.appInstallService/dev/install '"'"'{\"id\":\"me.wouterdek.magic4pc\",\"ipkUrl\":\"/tmp/magic4pc.ipk\",\"subscribe\":true}'"'"'" /tmp/o.txt; cat /tmp/o.txt'
|
|
||||||
# Ждать "state": "installed" в выводе
|
|
||||||
|
|
||||||
# 4. Запустить
|
|
||||||
ssh root@192.168.1.75 'script -q -c "luna-send -n 1 -f luna://com.webos.applicationManager/launch '"'"'{\"id\":\"me.wouterdek.magic4pc\"}'"'"'" /dev/null'
|
|
||||||
```
|
|
||||||
</details>
|
|
||||||
|
|
||||||
### Отладка
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Лог сервиса
|
|
||||||
ssh root@192.168.1.75 "cat /tmp/m4p_debug.log"
|
|
||||||
|
|
||||||
# Текущий выбранный app и last-app
|
|
||||||
ssh root@192.168.1.75 "cat /media/developer/apps/usr/palm/services/me.wouterdek.magic4pc.service/magic4pc-settings"
|
|
||||||
ssh root@192.168.1.75 "cat /media/developer/apps/usr/palm/services/me.wouterdek.magic4pc.service/magic4pc-last-app"
|
|
||||||
|
|
||||||
# Run-state (есть = уже запускался, нет = fresh start)
|
|
||||||
ssh root@192.168.1.75 "cat /tmp/magic4pc-run-state"
|
ssh root@192.168.1.75 "cat /tmp/magic4pc-run-state"
|
||||||
|
|
||||||
# Лог init.d
|
# Settings / last-app
|
||||||
ssh root@192.168.1.75 "cat /tmp/m4p_debug.log | grep 'magic4pc init'"
|
ssh root@192.168.1.75 "cat $PERSISTENT_DIR/magic4pc-settings"
|
||||||
|
ssh root@192.168.1.75 "cat $PERSISTENT_DIR/magic4pc-last-app"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> ⚠️ `appendLog()` пишет **только в UI**. В файл попадает только `appendLogPersist()`. При отладке использовать `appendLogPersist`.
|
||||||
|
|
||||||
|
## Back и клавиатура — особенности WebOS
|
||||||
|
|
||||||
|
**Как работает Back когда открыта системная клавиатура:**
|
||||||
|
|
||||||
|
- **Back #1** — система поглощает полностью: закрывает клавиатуру, вызывает `Input.onClose`. DOM `keydown` **не приходит**, `onButtonDown` **не вызывается**.
|
||||||
|
- **Back #2** — приходит в DOM → `onButtonDown`.
|
||||||
|
|
||||||
|
**Следствие:** нельзя детектировать первый Back через `keydown`. Единственный способ — флаг в `onActivate`.
|
||||||
|
|
||||||
|
**Реализованный фикс** (`_kbWasOpen` в `MainPanel.js`):
|
||||||
|
```js
|
||||||
|
// Input.onActivate:
|
||||||
|
this._kbWasOpen = true;
|
||||||
|
|
||||||
|
// onButtonDown при Back:
|
||||||
|
if (this.state.wolMacActive || this._kbWasOpen) {
|
||||||
|
this._kbWasOpen = false;
|
||||||
|
return; // не закрывать панель
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Что не работает на WebOS:**
|
||||||
|
- `Popup.noAutoDismiss` — Back закрывает через `onButtonDown`, не через Popup.onClose
|
||||||
|
- Таймаут (`Date.now() < ts + 1000ms`) — ненадёжно
|
||||||
|
- Polling `document.activeElement` — фокус никогда не переходит на `INPUT`, клавиатура — системный overlay
|
||||||
|
|
||||||
## Известные проблемы
|
## Известные проблемы
|
||||||
|
|
||||||
- **Guide (458)** — перехватывается WebOS системно, EIM-регистрация не помогает. Нет решения.
|
- **Guide (458)** — перехватывается WebOS системно. Нет решения.
|
||||||
- **listApps** — `applicationManager/dev/listApps` недоступен без dev mode. Используется `applicationManager/listApps`.
|
- **listApps** — `dev/listApps` недоступен без dev mode. Используется `applicationManager/listApps`.
|
||||||
- **Self-launch** — magic4pc не должен запускать сам себя. Фильтруется в `checkAutoLaunch` по appId.
|
- **Self-launch** — фильтруется в `checkAutoLaunch` по appId.
|
||||||
- **HDMI как last-app** — init.d трекает foreground включая HDMI sources. При `__last_used__` и последнем активном HDMI — не запустит ничего полезного. Решение: выбрать конкретный app вместо `last_used`.
|
- **HDMI как last-app** — при `__last_used__` и последнем активном HDMI не запустит ничего полезного. Решение: выбрать конкретный app.
|
||||||
|
- **`ares-install` ненадёжен** — молчит без PTY, не ждёт завершения. Использовать `luna-send dev/install` через script.
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
# tv-luna-send.sh — враппер для luna-send на LG TV
|
||||||
|
|
||||||
|
Скрипт: `~/Automations/tv-luna-send.sh`
|
||||||
|
|
||||||
|
## Проблема
|
||||||
|
|
||||||
|
`luna-send` на WebOS через SSH **не выводит результат в stdout** без PTY.
|
||||||
|
|
||||||
|
- `ssh root@TV "luna-send -n 1 ..."` — молчит
|
||||||
|
- `ssh -t root@TV "luna-send -n 1 ..."` — тоже молчит
|
||||||
|
- `script -q -c "luna-send ..." /tmp/out.txt` — **работает**
|
||||||
|
|
||||||
|
Причина: luna-send детектирует TTY и отказывается писать в pipe.
|
||||||
|
|
||||||
|
## Решение
|
||||||
|
|
||||||
|
`script(1)` аллоцирует псевдо-TTY и пишет вывод в файл. Враппер запускает luna-send через script, читает tmpfile (уникальный через $$), фильтрует мусор, удаляет файл.
|
||||||
|
|
||||||
|
## Использование
|
||||||
|
|
||||||
|
```bash
|
||||||
|
~/Automations/tv-luna-send.sh [luna-send flags] luna://service/method 'json'
|
||||||
|
```
|
||||||
|
|
||||||
|
Примеры:
|
||||||
|
```bash
|
||||||
|
# foreground app
|
||||||
|
~/Automations/tv-luna-send.sh -n 1 -f luna://com.webos.applicationManager/getForegroundAppInfo '{}'
|
||||||
|
|
||||||
|
# закрыть app
|
||||||
|
~/Automations/tv-luna-send.sh -n 1 -f luna://com.webos.service.applicationmanager/closeByAppId '{"id":"me.wouterdek.magic4pc"}'
|
||||||
|
|
||||||
|
# запустить app
|
||||||
|
~/Automations/tv-luna-send.sh -n 1 -f luna://com.webos.applicationManager/launch '{"id":"me.wouterdek.magic4pc"}'
|
||||||
|
|
||||||
|
# статус сервиса
|
||||||
|
~/Automations/tv-luna-send.sh -n 1 -f luna://me.wouterdek.magic4pc.service/query '{}'
|
||||||
|
```
|
||||||
|
|
||||||
|
Переменная `TV_HOST` переопределяет таргет (default: `root@192.168.1.75`).
|
||||||
|
|
||||||
|
## Ограничение
|
||||||
|
|
||||||
|
`luna-send -i` (subscribe, бесконечный) не работает через враппер. Для install (`dev/install`) используется прямой ssh+script с polling в deploy.sh.
|
||||||
|
|
||||||
|
## Где используется
|
||||||
|
|
||||||
|
`~/Developer/magic4pc/webos/deploy.sh` — close, remove, launch.
|
||||||
Reference in New Issue
Block a user