Плеер, на котором можно строить
У rox есть то, ради чего другие плееры встраивают веб-сервер: локальный сокет JSON-RPC, события, приходящие по мере изменений, прокси MCP и вещание на Icecast.
Сервер, которым rox отказывается быть
Обычный способ, которым настольный плеер открывает себя наружу, — встроить веб-сервер. Это покупает удалённое управление и стоит всего остального: порт на вашей машине, история с авторизацией, веб-интерфейс, бросающий собственный вид плеера, и поверхность атаки, которая музыкальному плееру ни к чему. Платит каждый, чтобы скриптовать свой плеер могли немногие.
rox оставляет возможность и отказывается от способа доставки. Его машинный интерфейс — локальный сокет, Unix domain socket на Linux и macOS и именованный канал на Windows, привязанный к папке данных, так что два портативных экземпляра никогда не пересекутся. Авторизация — права файловой системы: всё, что может читать вашу музыку, уже может то, что позволяет сокет. Порт не слушает никто, и HTTP-сервера в бинарнике нет.
Один сокет, весь плеер
Протокол — JSON-RPC 2.0, один объект на строку, открывается рукопожатием с версией. transport.* крутит транспорт: пуск и пауза, перемотка, громкость, отрезок A-B. queue.* правит порядок воспроизведения по стабильным id записей, так что строка, которую вы передвинули, всё ещё та, которую вы имели в виду. library.* ищет, возвращает полные теги играющего трека и отдаёт обложку. library.rescan и tasks.* запускают, отслеживают и останавливают пересканирование и проходы анализа, а ответ на запуск несёт число треков и оценку времени, которые показало бы окно. Каждый метод читает и ведёт тот же плеер и ту же медиатеку, что и панели, поэтому сокет не может сказать того, чего не сказал бы интерфейс.
Прообразы — JSON IPC у mpv и протокол mpd, и цена та же, что у них: потребителю нужен сокет-клиент там, где сервер предложил бы curl. roxctl, эталонный клиент в дереве исходников, закрывает случай шелла: один вызов на запуск, --json, когда читает скрипт, так что roxctl next и roxctl search miles davis работают до того, как вы написали хоть строчку чего-либо.
Пуш, чтобы никогда не опрашивать
Фронтенд, который не может подписаться, будет опрашивать, поэтому события в контракте с первой версии. Вызовите subscribe, и сокет присылает кадры по мере движения: event.track при смене трека, event.playback при изменении состояния воспроизведения, громкости или отключения звука, event.queue, когда меняется порядок.
Отставшего потребителя отключают, а не ждут, так что застрявший читатель никогда не упрётся обратно в воспроизведение. roxctl watch печатает поток по мере прихода, а это «сейчас играет» для статус-бара, решённое одним циклом в шелле.
MCP, которого нет ни у одного другого плеера
Рядом с приложением стоит rox-mcp, тонкий бинарник, говорящий MCP через stdio с одной стороны и с сокетом с другой. Наведите на него Claude или любой MCP-клиент, и плеер становится инструментами: что играет, поиск по медиатеке, чтение очереди, работа с транспортом, запуск пересканирования или прохода анализа. «Поставь в очередь что-нибудь тихое из семидесятых» перестаёт быть функцией, которую rox пришлось бы отращивать, и становится фразой, по которой может действовать ваш ассистент.
Каждый инструмент проксирует метод сокета, так что поверхность MCP по построению — подмножество того, что отдаёт сокет, и убежать вперёд него не может. И включается это дважды: переключатель возможностей ИИ, выключенный по умолчанию, открывает страницу настроек MCP с её собственным выключателем, а каждый вызов инструмента заново проверяет оба в работающем приложении, прежде чем ответить. Выключено — это ясный отказ, а не зависание.
Звуковая половина
Управление — половина фронтенда; вторая половина — что-то слышать. rox подключается наружу к серверу Icecast в роли источника и отдаёт обработанный поток, закодированный в MP3, на названную вами точку монтирования. Отвод идёт после цепочки обработки, так что в эфире ровно то, что получают колонки, вместе с эквалайзером.
Направление и есть суть. rox подключается наружу и никогда не обслуживает сам: точка монтирования, слушатели и вся сетевая сторона принадлежат Icecast. Если сервер недоступен, куски просто выбрасываются, а локальное воспроизведение остаётся нетронутым, и отправитель переподключается по собственным часам, пока конфигурация на месте.
Что это открывает
Каждая часть полезна сама по себе. Демон медиаклавиш или виджет для статус-бара — это сокет и несколько строк. Аппаратный контроллер, стрим-дек или ручка на микроконтроллере, — это transport.* из всего, что дотягивается до сокета. Киоск для комнаты прослушивания — методы очереди и event.track, ведущий дисплей.
Соедините их, и rox — бэкенд личного стриминга: транспорт и очередь через сокет, звук встраивается с точки монтирования Icecast, а фронтенд вы пишете на чём угодно, и ваша медиатека играет на машине, которая её хранит.
Захватите сокет-клиент
Сокет включён везде, где работает rox, rox-mcp лежит рядом с приложением, а на странице MCP в настройках есть строка конфигурации для вашего клиента. roxctl собирается из исходников одной командой cargo.