y83 projects / 08 / desktop

Y83 Music — плеер для локальной библиотеки на GTK4 и libmpv

0.1.0 · 2026

Читает папку с музыкой, собирает альбомы из тегов и обложек, играет через libmpv с предзагрузкой следующего трека, показывает текст из LRCLIB, спектр с выхода PipeWire и статистику прослушиваний. Управляется с клавиатуры, медиа-клавиш и через MPRIS, ставится одним install.sh.

версия
0.1.0
Rust
14 009 строк
тесты
73 · cargo test
стек
GTK4 · libadwaita · libmpv

продукт

Библиотека — это папка, а не каталог сервиса

Задача

Музыка лежит папками и сборными альбомами: у скачанных одиночек тег альбома у каждой песни свой, обложки чаще лежат файлом рядом, а не в тегах. Каталогизаторы хотят аккуратную медиатеку, а плееру нужно просто играть то, что на диске, и жить в системе как обычное приложение GNOME.

Решение

Rust и GTK4 с libadwaita для интерфейса, libmpv для звука, lofty для тегов, zbus для MPRIS. Папка-россыпь собирается в один альбом по имени папки, издание распознаётся по имени каталога, обложка ищется в теге, файле рядом или в интернете. Пять вкладок: альбомы, очередь, плейлисты, избранное, волна.

Следствие

Интерфейс не замирает на больших списках: теги кэшируются, строки строятся порциями, обложки разбираются один раз. Дальше начинается то, из-за чего плеером пользуются каждый день, — бесшовные переходы, восстановление позиции, «Моя волна», статистика и медиа-клавиши.

возможности

Что умеет

Разделы взяты из кода: библиотека, звук, страницы, текст и спектр, интеграция с системой.

Библиотека

Папка как источник

Скан ~/Музыка или каталога из HP_MUSIC_DIR, теги через lofty, обложка из тегов, файла cover.jpg/folder.jpg рядом или из iTunes Search API.

  • lofty

Кэш разбора

index.tsv помнит время правки и размер файла, поэтому повторный запуск читает только изменившееся: 3 000 треков — 0,06 с по кэшу против 0,17 с впустую.

  • cache

Папка-россыпь

Если у песен в папке разные теги альбома, папка считается одним альбомом с её именем; CD1/Disc 1 не дробят издание, а подписанные выпуски остаются отдельными.

  • albums

Живое отслеживание

Папка библиотеки под Gio::FileMonitor: скопированный альбом появляется в сетке сам, F5 остаётся для ручного случая.

  • monitor

Звук

libmpv и PipeWire

Очередь, повтор (выкл → всё → один трек), перемешивание без повторов внутри круга и новая тасовка на новом круге, скорость 0,5×–2,0× для аудиокниг.

  • mpv

Стык без паузы

Следующий трек уже лежит в плейлисте mpv (gapless-audio=yes), поэтому на конце песни звуковой выход не закрывается; предзагрузка пересобирается при смене альбома.

  • gapless

Настройки звука

Выбор аудиовыхода из списка устройств, ReplayGain выключен / по треку / по альбому, эквалайзер на три полосы (100 Гц, 1 кГц, 6 кГц, ±12 дБ) с восемью пресетами — от «Больше баса» до «Речи».

  • eq

Таймер сна

15, 30, 45 минут, 1 и 1,5 часа: остаток виден в нижней панели, по срабатывании плеер ставит паузу. Пока музыка играет, экран не гаснет.

  • sleep

Страницы

Альбомы

Сетка карточек с обложкой и числом треков, сортировка по исполнителю, году и названию, действия над альбомом целиком, скрытые альбомы и их возврат.

  • grid

Альбом и очередь

Внутри альбома — своё поле поиска и выбор порядка (трек, название, исполнитель, длительность, файл) со счётчиком показанных строк; строки строятся порциями по 60 за такт главного цикла — альбом на 348 треков открывается за ~60 мс вместо 310 мс. Очередь перетаскивается мышью, сохраняется плейлистом, чистится.

  • queue

Плейлисты и избранное

Обычные m3u8 в ~/.config/y83music/playlists, загрузка m3u, отдельная вкладка «Избранное» и файл favorites.m3u, который видно снаружи, плюс списки из истории: «Недавно игравшее» и «Забытое».

  • m3u

Поиск, фильтры, статистика

Поиск по альбомам и трекам (до 400 совпадений) вместе с фильтром по жанру и году; статистика: сводка, график по дням за две недели, топ-10 исполнителей и жанров, сброс с подтверждением.

  • search

«Моя волна», текст и спектр

Персональный поток

Вес трека растёт от прослушиваний, лайков, оценки и совпадения с любимыми исполнителями и жанрами, но у нового всегда остаётся базовый шанс. Пропуск (раньше четверти и не позже 30 секунд) снижает вес, «не играть в волне» убирает трек совсем.

  • wave

Характер волны

Три настройки, которые переживают перезапуск: знакомство (больше знакомого / сбалансированно / больше нового), настроение (спокойнее / как обычно / бодрее по жанрам) и разнообразие. Поток подкладывает следующую порцию сам.

  • tuning

Текст песни

Запрос к LRCLIB по исполнителю, названию, альбому и длительности идёт в отдельном потоке; синхронизированный LRC подсвечивает текущую строку по ходу трека и подкручивает страницу за ней.

  • lrclib

Визуализация

Круг с обложкой и 16 полос от 60 Гц до 12 кГц по логарифмической шкале. Спектр считается банками Гёртцеля из звука, снятого с выхода PipeWire через pw-record, без FFT и новых зависимостей; уровень подстраивается по недавнему пику.

  • viz

Система и окно

Сведения о треке

Формат, битрейт, частота, разрядность, каналы, размер и путь; «без потерь» определяется форматом (FLAC, WAV, AIFF, APE, WV), а не битрейтом. У играющего трека добавляются кодек, контейнер и параметры вывода mpv.

  • info

Оценки

Звёзды 1–5 пишутся в ratings.tsv и влияют на вес трека в «Моей волне».

  • rating

MPRIS и медиа-клавиши

На шине имя org.mpris.MediaPlayer2.y83music: система читает статус, метаданные с обложкой, позицию, громкость, очередь, а может переключать треки, менять громкость, повтор и перемешивание. Работают медиа-клавиши и пульт XF86*.

  • mpris

Клавиатура и мини-плеер

20 горячих клавиш со шпаргалкой в меню; Ctrl+M сжимает окно ровно по высоте нижней панели, тянуть мини-плеер можно за обложку и подпись трека, размер и состояние запоминаются.

  • keys

как работает

Путь трека

01

Скан

Плеер читает папку библиотеки: теги, обложки, длительности. Неизменившееся берётся из кэша, новый альбом замечает файловый монитор.

02

Альбом

Файлы собираются в альбомы, включая папку-россыпь: сетка остаётся сеткой альбомов, а не списком песен.

03

Звук

Очередь уходит в libmpv, следующий трек предзагружен — конец песни не закрывает звуковой выход.

04

Волна

Прослушивания, лайки, оценки и пропуски меняют вес треков; поток сам подкладывает следующую порцию.

05

Система

MPRIS отдаёт состояние шторке GNOME и медиа-клавишам, уведомление показывает трек, когда окно не в фокусе.

результаты

14 009

строк Rust

12 модулей + style.css
73

теста, cargo test

6 файлов с #[test]
0,06 с

скан 3 000 треков по кэшу

0,17 с без кэша
16

полос спектра

60 Гц – 12 кГц, банки Гёртцеля

Цифры сверены с кодом проекта 2026-10-14.

экраны

Как это выглядит

Здесь появятся настоящие скриншоты — приложение настольное, кадры широкие.

листайте вбок · 9 экранов

Сетка альбомов

Сетка альбомов

обложки, число треков, сортировка

Открытый альбом

Открытый альбом

поиск, порядок, подсветка играющего трека

Очередь

Очередь

порядок воспроизведения и перетаскивание строк

Плейлисты

Плейлисты

m3u8, избранное и списки из истории

Моя волна

Моя волна

поток и настройки характера

Текст песни

Текст песни

синхронизированный LRC

Визуализация

Визуализация

16 полос вокруг обложки

Настройки звука

Настройки звука

эквалайзер, ReplayGain, аудиовыход

Мини-плеер

Мини-плеер

окно по высоте нижней панели

технологии

Из чего собрано

Язык и интерфейс

  • Rust 2021
  • GTK4
  • libadwaita
  • style.css

Звук

  • libmpv
  • PipeWire
  • pw-record
  • ReplayGain
  • эквалайзер

Библиотека

  • lofty
  • walkdir
  • m3u8
  • iTunes Search API
  • LRCLIB

Система и сборка

  • zbus (MPRIS)
  • Gio::FileMonitor
  • AppStream
  • install.sh
  • GitHub Actions

этапы

Что сделано и что дальше

этап 1

Библиотека и воспроизведение

скан с кэшем, альбомы и обложки, очередь, повтор и перемешивание

этап 2

Системная интеграция

MPRIS, медиа-клавиши, уведомления, мини-плеер, install.sh и AppStream

этап 3

Повседневные сценарии

избранное, плейлисты m3u8, история прослушиваний, статистика, «Моя волна», оценки

этап 4

Звук и картинка

бесшовный стык треков, эквалайзер и ReplayGain, текст из LRCLIB, визуализация спектра

этап 5

Пакеты для дистрибутивов

следующий шаг — сборка deb и Flatpak поверх install.sh и готовых метаданных AppStream

вопросы

Частые вопросы

Зачем свой плеер, если готовые уже есть?

Библиотека здесь — папка, а не каталог сервиса: россыпь скачанных одиночек не рассыпается на сотни карточек, издание распознаётся по имени каталога, обложка берётся из тега, файла рядом или интернета. Плюс плеер ведёт себя как системное приложение GNOME: MPRIS, медиа-клавиши, уведомления, метаданные AppStream.

Что здесь самое сложное технически?

Звук и его стык: libmpv держит в плейлисте две записи, поэтому конец песни не закрывает звуковой выход. ReplayGain, эквалайзер, скорость и выбор аудиовыхода применяются прямо в mpv и читаются оттуда же, поэтому интерфейс не может показывать то, чего на самом деле нет. Отдельная часть — визуализация: звук снимается с выхода PipeWire, а полосы считаются банками Гёртцеля без FFT.

Почему Rust и GTK, а не веб-стек?

Плееру нужна настоящая системная интеграция: libmpv, PipeWire, D-Bus, файловый монитор, меню и медиа-клавиши GNOME. Здесь это не надстройка, а основной код — 14 009 строк Rust и 73 теста, включая живые прогоны --selftest на звуке и --uitest на дереве виджетов.

Y83 Music

Есть вопрос по проекту?

Настольный плеер для музыки, которая лежит папками на диске: интерфейс на GTK4 и libadwaita, звук на libmpv через PipeWire, теги через lofty, MPRIS для медиа-клавиш. Скан с кэшем разбора, бесшовный стык треков, синхронизированный текст песни, 16 полос живого спектра и «Моя волна» — поток, который учится на прослушиваниях и пропусках.

@xipovski xipovski@gmail.com
следующий проект Y83 Code