[2026-05-12] taiga sync: family/.DS_Store family/_index.md family/how-to/htpc-access.md family/how-to/htpc-gaming-plans.md family/how-to/htpc-magic4pc.md family/how-to/htpc-migration-plan.md family/how-to/htpc-system.md family/how-to/htpc-webos-luna.md family/how-to/htpc.md family/how-to/magic4pc-webos.md

This commit is contained in:
Local Administrator
2026-05-12 11:02:16 -07:00
commit d25629e140
32 changed files with 3821 additions and 0 deletions
+222
View File
@@ -0,0 +1,222 @@
# 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.