rox

Um player para construir em cima

O rox tem o que outros players embutem um servidor web para ganhar: um socket JSON-RPC local, eventos empurrados conforme as coisas mudam, um proxy MCP e um stream de saída para o Icecast.

O servidor que o rox se recusa a ser

O jeito comum de um player de desktop se abrir é embutir um servidor web. Isso compra controle remoto e custa todo o resto: uma porta na sua máquina, uma história de autenticação, uma interface web que abandona a cara do próprio player, e uma superfície de ataque que um player de música não tem por que ter. Todo usuário paga por isso para que os poucos que scriptam o player possam.

O rox fica com a capacidade e recusa a entrega. A interface de máquina dele é um socket local, um socket de domínio Unix no Linux e no macOS e um named pipe no Windows, atrelado à pasta de dados para que duas instâncias portáteis nunca se cruzem. A autenticação são as permissões do sistema de arquivos: qualquer coisa que consiga ler sua música já pode fazer o que o socket permite. Nada escuta numa porta, e nenhum servidor HTTP vem no binário.

Um socket, o player inteiro

O protocolo é JSON-RPC 2.0, um objeto por linha, aberto com um handshake de versão. transport.* comanda o deck: alternar, buscar posição, volume, o trecho A-B. queue.* edita a ordem de reprodução por id estável de entrada, então a linha que você moveu ainda é a linha que você quis mover. library.* busca, devolve as tags completas da faixa que toca e entrega a capa. library.rescan e tasks.* iniciam, acompanham e param as varreduras e as passagens de análise, e a resposta ao início traz a contagem de faixas e a estimativa de tempo que a janela teria mostrado. Todo método lê e comanda o mesmo player e a mesma biblioteca que os painéis, então o socket nunca pode dizer algo que a interface não diria.

O precedente é o IPC JSON do mpv e o protocolo do mpd, e o custo também é o deles: um consumidor precisa de um cliente de socket onde um servidor teria oferecido curl. O roxctl, o cliente de referência na árvore do código, cobre o caso do shell, uma chamada por invocação, --json quando um script está lendo, então roxctl next e roxctl search miles davis funcionam antes de você escrever uma linha de qualquer coisa.

Empurrar, para você nunca fazer polling

Um front end que não pode assinar vai fazer polling, então os eventos estão no contrato desde a versão um. Chame subscribe e o socket empurra frames conforme as coisas se movem: event.track na virada de faixa, event.playback quando o estado de reprodução, o volume ou o mudo mudam, event.queue quando a ordem muda.

Um consumidor que fica para trás é cortado em vez de esperado, então um leitor travado nunca consegue represar a reprodução. roxctl watch imprime o stream conforme chega, o que é um mostrador de faixa tocando para uma barra de status resolvido num loop de shell.

MCP, que nenhum outro player tem

Ao lado do app fica o rox-mcp, um binário fino que fala MCP por stdio de um lado e com o socket do outro. Aponte o Claude ou qualquer cliente MCP para ele e o player vira ferramentas: o que está tocando, buscar na biblioteca, ler a fila, operar o transporte, iniciar uma varredura ou uma passagem de análise. "Põe na fila algo quieto dos anos 70" deixa de ser um recurso que o rox teria que ganhar e vira uma frase que o seu assistente pode executar.

Toda ferramenta faz proxy de um método do socket, então a superfície MCP é por construção um subconjunto do que o socket serve e não pode andar na frente dele. E é opcional duas vezes: um interruptor de recursos de IA, desligado por padrão, revela uma página de configurações de MCP com o próprio interruptor, e toda chamada de ferramenta reverifica os dois no app rodando antes de responder. Desligado significa uma recusa clara, não um travamento.

A metade do áudio

Controle é metade de um front end; a outra metade é ouvir alguma coisa. O rox conecta para fora num servidor Icecast como cliente de origem e empurra o stream processado, codificado em MP3, no mount que você nomear. O desvio vem depois da cadeia de processamento, então a transmissão é exatamente o que as caixas recebem, equalizador e tudo.

A direção é o ponto. O rox conecta para fora, ele nunca serve: o mount, os ouvintes e a cara pública são todos do Icecast. Um servidor inalcançável faz os pedaços caírem no chão em vez de encostar na reprodução local, e o destino reconecta no próprio ritmo enquanto a configuração estiver no lugar.

O que isso abre

Cada peça é útil sozinha. Um daemon de teclas de mídia ou um widget de barra de status é o socket e umas poucas linhas. Um controlador de hardware, um stream deck ou um botão num microcontrolador, é transport.* a partir de qualquer coisa que alcance um socket. Serviço de quiosque numa sala de escuta é os métodos de fila e event.track movendo um display.

Junte tudo e o rox é o backend de um streaming pessoal: transporte e fila pelo socket, áudio embutido a partir do mount do Icecast, e um front end que você escreve no que quiser, com sua biblioteca tocando na máquina que a guarda.

Traga um cliente de socket

O socket está ligado onde quer que o rox rode, o rox-mcp vem junto do app, e a página de MCP nas configurações tem a linha de configuração para o seu cliente. O roxctl compila a partir do código-fonte com um comando cargo só.

Baixar o rox

Está no Arch ou no NixOS? Instale pelo AUR ou pelo flake do Nix.

v1.26.4 · Linux, macOS, Windows · todos os downloads