ghost-pause — Go-демон, доведённый до продакшена
Небольшая, но полностью доведённая до реального использования утилита: 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.
Обработчик сигнала живёт внутри того же select, что слушает события PulseAudio, и просто переключает флаг enabled на лету. Это стандартный Unix-паттерн управления долгоживущим демоном там, где не нужно ничего сложнее двух состояний — не нужен ни HTTP-сервер для API, ни файл сокета, только сигнал и PID.
Конфигурация с graceful degradation
Если файл конфига не найден или не парсится, демон не падает и не завершает работу — он тихо откатывается на дефолтный список target_apps (основные браузеры: Zen, Firefox, Chrome, Chromium, Brave) и продолжает работать как ни в чём не бывало. Это осознанный выбор: для утилиты, которая должна работать в фоне годами без внимания пользователя, упасть из-за опечатки в JSON — куда хуже, чем поработать несколько дней с дефолтными настройками, пока пользователь не заметит и не поправит конфиг.
pause_delay_ms — необязательная задержка перед паузой, полезная, если у пользователя браузер иногда выдаёт короткий звук уведомления: без дебаунса такой писк дёргал бы плеер на паузу и сразу обратно.