MBL
Go / Проекты / ghost-pause / ghost-pause — Go-демон, доведённый до продакшена
Go средний

ghost-pause — Go-демон, доведённый до продакшена

projectslinuxdbus

Небольшая, но полностью доведённая до реального использования утилита: Go-демон для Linux, который автоматически ставит на паузу медиаплееры (Spotify и любой другой MPRIS2-совместимый плеер), когда в браузере начинает играть звук, и возобновляет их, когда браузер замолкает. Реально опубликован в AUR (ghost-pause-git) — не личный скрипт для себя, а дистрибутив с независимыми пользователями.

Диаграмма потока событий (archify) →

Механизм: event-driven через pactl subscribe

Демон подписывается на события PulseAudio/PipeWire командой pactl subscribe. Когда у настроенного браузера (список target_apps в конфиге) появляется активный — то есть не corked — sink-input, демон реагирует немедленно.

Реакция — поход в D-Bus: найти все имена вида org.mpris.MediaPlayer2.*, проверить у каждого PlaybackStatus == "Playing" и вызвать Player.Pause только у тех, что реально играют. Когда браузер замолкает (sink-input исчезает или становится corked), демон вызывает Player.Play у ранее остановленных плееров — списки запоминаются, чтобы не трогать плееры, которые и так стояли на паузе сами по себе.

Почему event-driven, а не polling. Опрос состояния раз в секунду держал бы процесс активным вхолостую почти всё время — PulseAudio молчит большую часть дня. pactl subscribe реагирует ровно в момент появления/исчезновения sink-input: без постоянной фоновой нагрузки и без задержки, которую даёт любой фиксированный интервал опроса.

Управление без перезапуска — сигналы, не HTTP/IPC

Демон пишет свой PID в файл при старте. Команды ghost-pause stop/ghost-pause start не убивают и не перезапускают процесс — они читают PID из файла и шлют работающему демону SIGUSR1/SIGUSR2.

на play.golang.org

Обработчик сигнала живёт внутри того же select, что слушает события PulseAudio, и просто переключает флаг enabled на лету. Это стандартный Unix-паттерн управления долгоживущим демоном там, где не нужно ничего сложнее двух состояний — не нужен ни HTTP-сервер для API, ни файл сокета, только сигнал и PID.

Конфигурация с graceful degradation

Если файл конфига не найден или не парсится, демон не падает и не завершает работу — он тихо откатывается на дефолтный список target_apps (основные браузеры: Zen, Firefox, Chrome, Chromium, Brave) и продолжает работать как ни в чём не бывало. Это осознанный выбор: для утилиты, которая должна работать в фоне годами без внимания пользователя, упасть из-за опечатки в JSON — куда хуже, чем поработать несколько дней с дефолтными настройками, пока пользователь не заметит и не поправит конфиг.

pause_delay_ms — необязательная задержка перед паузой, полезная, если у пользователя браузер иногда выдаёт короткий звук уведомления: без дебаунса такой писк дёргал бы плеер на паузу и сразу обратно.

Самопроверка 0 / 3
Могу объяснить, почему pactl subscribe лучше опроса по таймеру
Понимаю, как управлять долгоживущим демоном через сигналы без перезапуска
Знаю, что делает демон при отсутствии/поломке конфига — не падает, а откатывается на дефолт
Как усвоено?