Files
obsidian-vault/family/how-to/magic4pc-webos.md
T

223 lines
9.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Magic4PC — WebOS Client
Управление LG MagicRemote как мышью/клавиатурой на HTPC через Bazzite.
## Архитектура
- **TV (WebOS)** — app `me.wouterdek.magic4pc` + JS-сервис `me.wouterdek.magic4pc.service`
- App: React/Enact UI, слушает кнопки пульта, отправляет в сервис через luna
- Сервис: Node.js, бродкастит UDP, принимает подключение от Go-клиента на HTPC
- **HTPC (Bazzite)** — Go-клиент `~/magic4pc/`, сервис `magic4pc.service`
- Получает UDP-пакеты от TV, инжектирует ввод через `/dev/uinput`
- `inputBackKey()` → Esc в gamescope, x1 в KDE
- Репо: https://github.com/mallexxx/magic4pc_altclient (ветка `main`)
## Исходники
| Компонент | Путь |
|-----------|------|
| WebOS UI | `~/Developer/magic4pc/webos/src/views/MainPanel.js` |
| WebOS сервис | `~/Developer/magic4pc/webos/service/m4p_service.js` |
| Go клиент | `~/Developer/magic4pc_altclient/` |
| HTPC бинарник | `~/magic4pc/magic4pc` |
| HTPC сервис | `~/.config/systemd/user/magic4pc.service` (HTPC) |
| run.sh | `~/magic4pc/run.sh` (HTPC) |
## Кнопки пульта (keyCode)
| Код | Кнопка | Действие |
|-----|--------|----------|
| 406 | 🔵 Синяя | Открыть панель настроек |
| 461 | Back | Esc (gamescope) / x1 (KDE) |
| 458 | Guide | системный (не перехватывается) |
| 403 | 🔴 Красная | передаётся на HTPC |
| 415 | Play | передаётся на HTPC |
| 19 | Pause | передаётся на HTPC |
## Панель настроек (синяя кнопка)
- **Статус** — Connected to IP:port / Waiting / Service disabled
- **v1.1.0 (YYYY-MM-DD HH:MM)** — версия + дата сборки справа от статуса
- **Input source** — выбор HDMI входа
- **Enable / Disable** — старт/стоп сервиса
- **Default app on exit** — приложение которое запускается при выходе из magic4pc (None / Last used / конкретное)
- **Show Log / Hide Log** — лог событий и ошибок поверх видео
## Версия сборки
Версия отображается как `1.1.0 (YYYY-MM-DD HH:MM)` — дата инжектируется webpack автоматически при каждой сборке:
```js
// config/webpack.config.js
'process.env.BUILD_DATE': JSON.stringify(new Date().toISOString().slice(0, 16).replace('T', ' '))
```
## Сборка WebOS app
```bash
cd ~/Developer/magic4pc/webos
NODE_OPTIONS=--openssl-legacy-provider npm run build
```
> ⚠️ Требует `--openssl-legacy-provider` — старый webpack несовместим с Node 25.
## Сборка 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.
Использует `~/Automation/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
cd ~/Developer/magic4pc/webos
NODE_OPTIONS=--openssl-legacy-provider npm run build
/Users/admin/webOS_TV_SDK/CLI/bin/ares-package dist/ service/ --outdir .
scp me.wouterdek.magic4pc_1.1.0_all.ipk root@192.168.1.75:/tmp/magic4pc.ipk
~/Automation/tv-luna-send.sh -n 1 -f luna://com.webos.service.applicationmanager/closeByAppId '{"id":"me.wouterdek.magic4pc"}' || true
~/Automation/tv-luna-send.sh -n 1 -f luna://com.webos.appInstallService/dev/remove '{"id":"me.wouterdek.magic4pc"}' || true
sleep 2
# install — через прямой script (luna-send -i не работает через враппер)
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"
~/Automation/tv-luna-send.sh -n 1 -f luna://com.webos.applicationManager/launch '{"id":"me.wouterdek.magic4pc"}'
```
</details>
### Проверка статуса сервиса
```bash
~/Automation/tv-luna-send.sh -n 1 -f luna://me.wouterdek.magic4pc.service/query '{}'
```
Ожидаемый результат: `serviceActive: true`, `broadcastAdsActive: true`.
## Деплой Go-клиента на HTPC
```bash
cd ~/Developer/magic4pc_altclient
GOOS=linux GOARCH=amd64 go build -o magic4pc_new .
scp magic4pc_new bazzite@192.168.1.86:~/magic4pc/
ssh bazzite@192.168.1.86 "
systemctl --user stop magic4pc
mv ~/magic4pc/magic4pc_new ~/magic4pc/magic4pc
systemctl --user start magic4pc
"
```
## HTPC сервис
```bash
ssh bazzite@192.168.1.86 "systemctl --user status magic4pc"
ssh bazzite@192.168.1.86 "systemctl --user restart magic4pc"
```
> `enable` не используется — autostart через EIM на стороне TV.
## Auto-launch при boot/wake
Magic4pc автоматически запускает выбранный app при включении TV.
### Логика
- **Boot** — `/tmp` чистится → нет `run-state``freshStart=true` → запускает app
- **Wake** — init.d при Suspend удаляет `run-state` → при wake `freshStart=true` → запускает app
- **Ручной запуск** — `run-state=running` уже есть → `freshStart=false` → ничего не запускает ✅
### Файлы persistent storage
`PERSISTENT_DIR = /media/developer/apps/usr/palm/services/me.wouterdek.magic4pc.service`
| Файл | Где | Что |
|------|-----|-----|
| `magic4pc-settings` | `PERSISTENT_DIR/` | Выбранный app: appId / `__last_used__` / `none` |
| `magic4pc-last-app` | `PERSISTENT_DIR/` | Последний foreground app |
| `magic4pc-run-state` | `/tmp/` | `running` = уже запускался после boot/wake |
### Init.d скрипт
Файл на TV: `/var/lib/webosbrew/init.d/magic4pc`
Исходник: `tv-scripts/init.d-magic4pc.sh` в репо
```bash
# Деплой
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"
# Применяется после ребута TV
```
> ⚠️ Всегда править в репо, не на TV напрямую.
## Отладка
```bash
# Лог UI (appendLogPersist пишет сюда)
ssh root@192.168.1.75 "tail -30 /tmp/m4p_debug.log"
# Run-state
ssh root@192.168.1.75 "cat /tmp/magic4pc-run-state"
# Settings / last-app
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 системно. Нет решения.
- **listApps** — `dev/listApps` недоступен без dev mode. Используется `applicationManager/listApps`.
- **Self-launch** — фильтруется в `checkAutoLaunch` по appId.
- **HDMI как last-app** — при `__last_used__` и последнем активном HDMI не запустит ничего полезного. Решение: выбрать конкретный app.
- **`ares-install` ненадёжен** — молчит без PTY, не ждёт завершения. Использовать `luna-send dev/install` через script.