No description
  • JavaScript 78%
  • Shell 22%
Find a file
vini 5b6dbfd18d Enxuga o codigo: 695 -> 521 linhas, sem mudar comportamento
- Remove src/player.js: 86 linhas que ninguem importava (era para a API HTTP
  adiada; volta do historico quando a etapa chegar).
- mpv.js: tira observe()/property-change e waitFor(), que nada usava, junto
  com a re-assinatura de propriedades na reconexao. Funde get()+tryGet() num
  get(prop, fallback) so, e o emit generico de eventos cobre o que o caso
  especial de property-change fazia.
- MpvPlayer: um try/finally no lugar de dois try aninhados (o cancel() do
  #waitLoad e idempotente); remove o getter statusFromMpv, morto.
- store.js: troca o cache em memoria + leitura compartilhada por releitura
  dentro da fila de escrita. Mesma garantia contra as duas sessoes se
  atropelarem, com bem menos estado para acompanhar.
- dial.js: pinDialUuid() calcula o UUID sozinho, em vez de exigir duas
  chamadas encadeadas.

Verificado depois: play/pause/seek/stop 2/2, UDN inalterado, screenIds
intactos e um unico listener de end-file.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-14 10:52:18 -03:00
docs Nao instala cec-utils: amdgpu nao expoe CEC no HDMI 2026-08-14 09:28:42 -03:00
scripts Receptor de YouTube funcionando: DIAL + codigo de TV 2026-08-14 09:28:42 -03:00
src Enxuga o codigo: 695 -> 521 linhas, sem mudar comportamento 2026-08-14 10:52:18 -03:00
systemd Absorve o 403 intermitente do YouTube com retry no doPlay 2026-08-14 10:03:02 -03:00
.gitignore Receptor de YouTube funcionando: DIAL + codigo de TV 2026-08-14 09:28:42 -03:00
package-lock.json Receptor de YouTube funcionando: DIAL + codigo de TV 2026-08-14 09:28:42 -03:00
package.json Enxuga o codigo: 695 -> 521 linhas, sem mudar comportamento 2026-08-14 10:52:18 -03:00
README.md Documenta a TV em 30 Hz e descarta a preferencia por 30fps 2026-08-14 10:06:32 -03:00

homecast

Transformar esta máquina (Ubuntu 26.04, ligada na TV por HDMI) num alvo de transmissão para o celular Android — substituindo a Android TV que fica resetando de fábrica por problema de hardware.

Hardware / ambiente detectado

Item Valor
SO Ubuntu 26.04 LTS (resolute), kernel 7.0
Host jozz, IP LAN 192.168.1.107 (Wi-Fi wlx3c52a1462bd0)
GPU AMD Radeon 540/550 (amdgpu), /dev/dri/card1
Saída card1-HDMI-A-1connected + enabled
Sessão Plasma Wayland (kwin_wayland, socket wayland-0, Xwayland :0) no tty1/seat0, sempre logada
Áudio PipeWire; sink HDMI = alsa_output.pci-0000_01_00.1.hdmi-surround-extra3
Firewall ufw ativo → precisa de regras para mDNS/SSDP (ver docs/plano.md)
Player mpv 0.41, VLC, ffmpeg, yt-dlp 2026.03.17
Runtime Node 22.22, Python 3, avahi-daemon ativo (essencial p/ mDNS)

Conclusão da pesquisa (resumo)

Não dá para virar um Chromecast "de verdade" para apps Android (Stremio, etc.): o Cast v2 exige device authentication — o receptor precisa apresentar um certificado assinado pela ICA da Google, cuja chave privada só a Google tem. Não é engenharia reversa que resolve; é criptografia. Detalhes e fontes em docs/pesquisa.md.

Por isso o projeto usa um protocolo diferente para cada origem:

Origem no celular Protocolo Componente Viabilidade
App YouTube DIAL + Lounge API yt-cast-receiver (Node) + mpv nativo, aparece no botão de cast
Stremio UPnP/DLNA (via "abrir em player externo") gmediarender ou renderer próprio + mpv com app intermediário no celular
Qualquer link / navegador HTTP simples API POST /play própria + mpv atalho/PWA no celular
Espelhamento de tela Cast mirroring / Miracast shanocast (só Chrome desktop) / MiracleCast ⚠️ frágil

Arquitetura

        celular Android
   ┌──────────┬───────────┬──────────────┐
   │ YouTube  │  Stremio  │ navegador /  │
   │  (DIAL)  │ (→ DLNA)  │ atalho HTTP  │
   └────┬─────┴─────┬─────┴──────┬───────┘
        │           │            │            LAN 192.168.1.107
   ┌────▼───────────▼────────────▼───────┐
   │  homecast (este repo)               │
   │  ├─ receptor YouTube (Node/DIAL)    │
   │  ├─ renderer DLNA                   │
   │  └─ API HTTP /play                  │
   └───────────────┬─────────────────────┘
                   │ IPC (socket unix)
              ┌────▼─────┐
              │ mpv KMS  │──HDMI──▶ TV
              │  --vo=gpu│
              └──────────┘

Um único mpv persistente na sessão Plasma Wayland, controlado por --input-ipc-server, é o back-end de reprodução comum aos três caminhos. Validado: WAYLAND_DISPLAY=wayland-0 XDG_RUNTIME_DIR=/run/user/1000 mpv ... funciona a partir de um shell SSH, sem root e sem tocar em DRM/KMS.

Status

  • Levantamento do hardware e do que já está instalado
  • Pesquisa dos projetos existentes (docs/pesquisa.md)
  • mpv persistente na sessão Plasma + homecast-mpv.service
  • Receptor YouTube funcionando (homecast-youtube.service), descoberta por DIAL — aparece como homecast (jozz) no botão de transmitir
  • API HTTP /play (etapa 2)
  • Renderer DLNA para o Stremio (etapa 4)
  • Espelhamento de tela (etapa 5, opcional)

Armadilhas já resolvidas (não repetir)

  • ~/.local/bin/yt-dlp é um symlink pipx quebrado (o venv sumiu). O ytdl_hook do mpv falhava com "not found or not enough permissions" e não saía um frame. Use /usr/bin/yt-dlp.
  • O yt-cast-receiver não repassa uuid para o peer-dial, que então sorteia um UUID por start: cada reinício virava uma TV nova na lista do app do YouTube. Resolvido em src/youtube/dial.js, com UUID derivado do machine-id.
  • O DataStore padrão grava em .node-persist/ relativo ao cwd. Trocado por src/youtube/store.js, em ~/.local/state/homecast/.
  • A lib registra duas telas (YouTube e YouTube Music), com o mesmo nome — é normal aparecerem duas entradas com o mesmo rótulo.
  • A saída fica em 3840x2160@30 de propósito: em 4K@60 o áudio HDMI para de funcionar (limite de banda do link). Não "conserte" isso mexendo no kscreen-doctor.
  • Como a tela é 30 Hz, vídeo de 60fps mostra ~30 frames descartados por segundo no frame-drop-count. É esperado e não é perda de qualidade de imagem. Não vale forçar formatos de 30fps para zerar esse número: no YouTube as faixas de 30fps costumam ser de resolução menor (medido: um vídeo caiu de 1080p para 854x480). Resolução ganha de taxa de quadros aqui.
  • O 403 do YouTube em URLs assinadas é intermitente (~1 em 3); quem cuida disso é o retry do doPlay, não configuração de formato.

Passo a passo em docs/plano.md.