🌟 О проекте
VEIN Music — независимая платформа для любителей музыки. Она собирает прослушивания из приложения и сайта Яндекс Музыки, браузера, десктопных плееров и облачных сервисов, строит статистику и рекомендации, превращает прослушивание в игру с уровнями и достижениями и даёт разработчикам открытый API.
Проект на бета-тестировании. Сайт работает, но возможны ошибки и изменения. Если заметили ошибку, пожалуйтесь на неё через профиль или комментарий: жалобы попадают в админку.
⚡ Ключевые возможности
🎧 1. Сбор прослушиваний из любых источников
- Яндекс Музыка без расширения: после подключения аккаунта сервер держит живое соединение с плеером Яндекса (Ynison) и видит, что играет в мобильном приложении, десктопном приложении и на сайте music.yandex.ru.
- Время засчитывается только по событиям плеера (пауза, перемотка, переключение), поэтому закрытая вкладка или выгруженное приложение не засчитывают недослушанный трек.
- Если соединение недоступно, работает запасной опрос раз в 30 секунд.
- Браузерное расширение (Chrome, Edge, Яндекс Браузер и Firefox 142+, Manifest V3):
- Считывает трек и прогресс воспроизведения на вкладках Яндекс Музыки, Spotify, VK Музыки, YouTube Music, Apple Music, SoundCloud и Звука.
- Офлайн-очередь: если сервер недоступен, прослушивания сохраняются в хранилище расширения (до 500 штук) и досылаются раз в минуту через
chrome.alarms.
- Подключение по коду: расширение показывает короткий код, пользователь подтверждает его на странице
/link, и расширение получает собственный ключ. Ключ можно отозвать в настройках.
- Приложение для Windows (
desktop/, Tauri 2):
- Сайт VEINMusic в отдельном окне и значок в трее; запускается вместе с Windows и работает в фоне.
- Скробблит всё, что видно в системной панели медиа Windows: Spotify (без платного API), приложение Яндекс Музыки, AIMP, foobar2000, VLC, Apple Music, вкладки браузеров. Источники включаются по отдельности.
- Подключение аккаунта по коду, как у расширения; ключ хранится в диспетчере учётных данных Windows.
- Проверка обновлений через релизы GitHub, статус в Discord. Установщик собирает GitHub Actions (подробнее).
- Консольный клиент (
desktop_client/, Python) — для Linux:
- Linux: любые плееры с поддержкой MPRIS (через
playerctl); на Windows — SMTC и заголовки окон.
- Discord Rich Presence с обложкой, названием трека, артистом и таймером.
- Локальная очередь
~/.veinmusic/queue.json, которая досылается при восстановлении сети.
- Облачный скробблинг Spotify: фоновый опрос того, что играет в Spotify, без открытых вкладок и плееров. Работает как задача воркера с распределённой блокировкой, поэтому опрос не дублируется при нескольких экземплярах сервера.
- Облачный скробблинг SoundCloud: OAuth 2.1 с PKCE и официальный список недавно прослушанных треков позволяют фиксировать новые прослушивания без браузерного расширения. Первая синхронизация служит безопасной точкой отсчёта и не импортирует старую историю.
- Экспорт во внешние сервисы: каждое засчитанное прослушивание можно автоматически отправлять в Last.fm, ListenBrainz и Libre.fm (настраивается через API:
/api/developer/export/config).
- Импорт истории из Last.fm: постраничный импорт в фоне с прогресс-баром. После сбоя импорт продолжается с той же страницы, а повторный запуск забирает только новые прослушивания.
🛡️ 2. Обработка прослушиваний и защита от накруток
- Нормализация метаданных: из названий убираются пометки вроде
Remastered, Live at …, Radio Edit, Deluxe Edition, Explicit, а feat. переносится к артисту.
- Засчитывание прослушиваний: трек засчитывается и приносит XP, только если прослушано не меньше 85% его длительности. Повторные сигналы о том же треке обновляют одно прослушивание, а не создают дубли.
- Ограничение частоты запросов на скробблинг, вход и регистрацию. Счётчики общие для всех процессов (хранятся в Redis).
- Антифрод: система отмечает подозрительных пользователей по аномальному числу прослушиваний в час и в сутки и по потоку очень коротких треков. Администратор может сбросить им XP или снять отметку.
- Чёрный список: блокировка треков и артистов по ключевому слову, точному имени артиста или регулярному выражению.
📊 3. Статистика и рекомендации
- Графики на Recharts: активность по часам и дням недели, динамика прослушиваний; периоды — неделя, месяц, 90 дней, текущий год, всё время или произвольный диапазон дат.
- Топы артистов, треков и альбомов, любимые жанры.
- Музыкальный календарь: активность по каждому дню года, серии прослушиваний и подробности выбранного дня.
- VEIN Wrapped для любого периода: сравнение с предыдущим периодом, новые артисты, самый активный день и вертикальная карточка для публикации. В профиле также доступны OG-карточки итогов недели или месяца для соцсетей.
- Рекомендации: треки из любимых жанров, новинки знакомых артистов и то, что популярно в сообществе (
/api/recommendations/me), а в профиле — артисты, которых слушают ваши «музыкальные двойники».
- Музыкальная совместимость: процент совпадения вкусов с другим пользователем, общие артисты, подбор «музыкальных двойников» и поиск людей со схожим вкусом.
- Настроение: определение текущего музыкального настроения по последним трекам.
🏆 4. Геймификация, профиль и социальные функции
- Уровни и ранги: XP за каждое засчитанное прослушивание (x2 за любимые треки), ранги от Туриста до Божества, ежедневные серии прослушиваний. Администратор может включить множитель XP.
- Рамки аватара, которые открываются по уровню (Меломан, Аудиофил, Маньяк, Легенда, Божество), плюс рамки, созданные администратором.
- Достижения, которые администратор настраивает правилами: число прослушиваний, ночные прослушивания, конкретный трек, альбом или артист. О новых достижениях приходит уведомление на сайте и Web Push.
- Оформление профиля: аватар и обложка с обрезкой при загрузке, страна, ссылки на Telegram, GitHub и Instagram, свой акцентный цвет сайта.
- Витрина профиля: любимые артист, трек и альбом с обложками и фото исполнителя (поиск по Deezer и Яндекс Музыке, русские названия сохраняются). Менять их можно раз в 30 дней.
- Подписки и лента: подписчики и подписки, лента друзей и глобальная лента с лайками и комментариями, фильтр ленты по источнику (Яндекс, Spotify, десктоп, расширение).
- Лидерборд слушателей по XP.
- Приватный профиль: история и статистика скрыты от посторонних.
- Жалобы: на профиль или комментарий можно пожаловаться, указав причину; жалоба уходит модераторам.
🛠️ 5. Виджеты, PWA и платформа для разработчиков
- SVG-виджеты для README на GitHub и сайтов:
Now Playing — что играет сейчас, с анимированным эквалайзером (/api/widgets/now-playing/{username}.svg);
Top Artists — топ-5 артистов (/api/widgets/top-artists/{username}.svg).
- OG-карточки 1200×630 для соцсетей: итоги недели или месяца (
/api/widgets/og/recap/{username}.svg) и полученные достижения (/api/widgets/og/achievement/{username}/{id}.svg).
- PWA: сайт можно установить на телефон или компьютер (Service Worker и
manifest.json).
- Web Push: уведомления о новых достижениях (стандарт RFC 8291, ключи VAPID). Включаются во вкладке «Безопасность и данные».
- API для разработчиков:
- Личные ключи (
vm_...) с правами (scopes), хранятся в виде хэша PBKDF2-HMAC-SHA256.
- Вебхуки на события
scrobble.created и achievement.unlocked с подписью X-VEIN-Signature (HMAC-SHA256).
- Справочник по API на странице
/developers.
- Умная ссылка
/api/redirect: открывает найденный трек в Яндекс Музыке.
- Объявления и флаги функций: баннер объявлений на сайте и включение функций без перевыпуска.
- Окно «Идёт обновление»: пока сервер обновляется после нового коммита, сайт показывает окно «Пожалуйста, подождите» вместо ошибки и сам перезагружает страницу, когда новая версия готова.
🔐 6. Безопасность и данные аккаунта
- Сессии: выход со всех устройств одной кнопкой; забаненный пользователь сразу теряет доступ во всех сессиях.
- Защита входа: пароль от 8 символов, блокировка на 15 минут после 10 неудачных попыток.
- Шифрование: OAuth-токены, сессионные ключи и секреты вебхуков хранятся в базе в зашифрованном виде.
- Заголовки безопасности: CSP, запрет встраивания во фреймы,
nosniff, HSTS в продакшене.
- Защита от SSRF: вебхуки и push отправляются только на публичные адреса, с проверкой IP на момент отправки.
- Мои данные: выгрузка профиля, истории, подписок, комментариев и достижений в JSON и удаление аккаунта с подтверждением паролем.
🛡️ 7. Панель администратора (/admin)
- Обзор: графики регистраций, засчитанных прослушиваний и активных слушателей за 7/30/90 дней, метрики, множитель XP, сброс кэша.
- Пользователи: список и карточка пользователя — статистика, интеграции и экспорт, API-ключи (с отзывом), вебхуки, последние прослушивания, достижения и импорты; бан, роль, верификация, уровень, сброс профиля, завершение всех сессий, удаление истории или аккаунта, выдача и снятие достижений.
- Жалобы: жалобы на профили и комментарии с фильтрами, удаление комментария, «Меры приняты» или «Отклонить» с заметкой.
- Модерация: последние комментарии с поиском по тексту и автору, удаление.
- Прослушивания: поиск по пользователю, треку, источнику и периоду; исправление трека, удаление одной записи или массовое удаление у пользователя с предварительным подсчётом.
- Интеграции: подключённые Яндекс, Spotify, SoundCloud и Last.fm, живое состояние соединений с Яндексом, переподключение и отключение; обновление витрины пользователя.
- Антифрод: список подозрительных пользователей, сброс XP, снятие отметки.
- Каталог: поиск по всем трекам с числом прослушиваний, редактирование и удаление треков, слияние дубликатов и исполнителей, чёрный список.
- Геймификация: создание, редактирование и удаление достижений и их правил, рамки аватара.
- Оповещения: объявления, флаги функций (регистрация, импорт Last.fm, вебхуки) и рассылка — уведомление на сайте и/или Web Push всем или выбранным пользователям.
- Система: воркер и очередь задач, последние запуски cron, бэкапы БД, размер загрузок и базы и задачи импорта Last.fm с перезапуском.
- Логи: ошибки и предупреждения API и воркера с трассировками и фильтрами; ключи и токены в них скрываются.
- Журнал: все действия администраторов с фильтрами по действию, администратору и объекту.
Роль администратора выдаётся командой на сервере:
docker compose exec backend python -m app.cli set-role <username> admin
Аватары и обложки профиля при загрузке уменьшаются (аватар до 512 px,
обложка до 2000 px по длинной стороне), разворачиваются по EXIF и теряют
метаданные камеры и GPS. Файлы, загруженные раньше, один раз ужимаются на
месте (имена и ссылки не меняются; --dry-run только покажет экономию):
docker compose exec backend python -m app.cli shrink-uploads --dry-run
docker compose exec backend python -m app.cli shrink-uploads
Надёжность библиотеки
- Пошаговое подключение с проверкой первого трека, личный поиск с фильтрами,
выбор даты воспоминаний и история выбранного периода календаря.
- Потоковые JSON/CSV и перенос истории с предпросмотром, защитой от дублей и без XP.
- Вес недавних интересов в рекомендациях и исключение исполнителя целиком.
Подробнее: личная музыка и перенос истории.
- Подтверждающие источники одного прослушивания и защита от двойного зачёта облаком и клиентом.
- Статус зачёта, фильтры и страницы истории по курсору; массовые изменения с предварительным просмотром и отменой на 24 часа.
- Разнообразие рекомендаций, история показанного и личный список «Послушать позже» с заметками.
- Отдельные браузерные сессии с отзывом, уведомления о входе и обязательная 2FA администраторов в production.
- Отдельный монитор API, очереди, источников, диска и бэкапов; доставка предупреждений через настроенный HTTPS webhook.
Подробнее: сценарии и замеры большой истории, внешние бэкапы, реагирование на инцидент.
🏗️ Архитектура и технологический стек
┌────────────────────────────────────────────────────────┐
│ КЛИЕНТСКИЙ СЛОЙ │
│ Next.js 16 (PWA) │ Расширение MV3 │ Desktop (Py/RPC) │
└───────────────────────────┬────────────────────────────┘
│ HTTPS / WebSockets
▼
┌────────────────────────────────────────────────────────┐
│ FASTAPI SERVER │
│ Auth / API / WebSockets / Антифрод / Рекомендации │
└───────────────┬────────────────────────┬───────────────┘
│ │
PostgreSQL │ │ Redis / ARQ
┌──────────────────────▼───────┐ ┌───────▼────────────────────────┐
│ Пользователи, прослушивания │ │ Кэш, лимиты, WebSocket-комнаты│
│ каталог, вебхуки (Alembic) │ │ Воркер: достижения, вебхуки, │
│ │ │ экспорт, импорт, опрос облака │
└──────────────────────────────┘ └────────────────────────────────┘
- Backend: Python 3.11, FastAPI, SQLAlchemy 2.0, Alembic, PostgreSQL, Redis, ARQ, Pydantic v2, cryptography, PyJWT, websockets (Ynison), Sentry (опционально).
- Frontend: Next.js 16 (App Router, React 19), TypeScript 6, Tailwind CSS 4, Framer Motion, Recharts, Lucide.
- Desktop: Tauri 2 (Rust, WebView2), Windows SMTC; консольный клиент на Python 3 (
playerctl/MPRIS), Discord IPC.
- Расширение: JavaScript, Chrome Extensions API (Manifest V3), совместимо с Firefox.
- CI/CD и качество: GitHub Actions (тесты на SQLite и PostgreSQL, проверка миграций), ruff, flake8, mypy, bandit, ESLint 9, Prettier, Playwright E2E, CodeQL, SonarQube Cloud, GitGuardian, Dependabot.
📁 Структура репозитория
VEINMusic/
├── app/ # Бэкенд (FastAPI)
│ ├── core/ # Безопасность, шифрование, Redis, WebSockets, лимиты, миграции
│ ├── models.py # Модели базы данных SQLAlchemy
│ ├── schemas.py # Схемы валидации Pydantic
│ ├── routers/ # Роутеры (auth, scrobbling, users, stats, admin, developer, devices, account…)
│ ├── services/ # Бизнес-логика (антифрод, рекомендации, Ynison, экспорт, импорт, вебхуки, push, OG)
│ ├── worker.py # Фоновый воркер ARQ
│ └── main.py # Точка входа приложения
├── desktop/ # Приложение для Windows (Tauri 2): окно сайта, трей, скробблинг из панели медиа
├── desktop_client/ # Консольный клиент на Python (Linux: MPRIS, Discord RPC)
├── frontend/ # Веб-приложение Next.js 16 (React 19)
│ ├── app/ # Страницы и маршруты (about, admin, auth, developers, feed, link, user…)
│ ├── components/ # Общие компоненты (PWARegistration, StatsCharts, GlobalAnnouncementBanner)
│ └── public/ # Иконка, манифест PWA и Service Worker (sw.js)
├── music-extension/ # Браузерное расширение (Manifest V3)
├── alembic/ # Миграции базы данных
├── tests/ # Тесты бэкенда (pytest)
├── deploy/ # Продакшен на VPS: готовые образы, Caddy (HTTPS), автообновление, страница обновления
└── docker-compose.yml # PostgreSQL, Redis, API, воркер и фронтенд
🚀 Быстрый старт
1. Клонирование репозитория
git clone https://github.com/Peaostrel/VEINMusic.git
cd VEINMusic
2. Настройка окружения
cp .env.example .env
# Обязательно задайте SECRET_KEY, POSTGRES_PASSWORD и REDIS_PASSWORD
Для облачного SoundCloud-скробблинга зарегистрируйте приложение в SoundCloud
и задайте SOUNDCLOUD_CLIENT_ID, SOUNDCLOUD_CLIENT_SECRET и точный callback
SOUNDCLOUD_REDIRECT_URI (для продакшена —
https://api.music.vein.guru/auth/soundcloud/callback).
Для входа и привязки через VK ID создайте веб-приложение в кабинете
id.vk.ru, укажите доверенный redirect
URL https://api.music.vein.guru/auth/vk/callback и задайте VK_CLIENT_ID
(ID приложения). Защищённый ключ не нужен: вход идёт по OAuth 2.1 с PKCE.
Пока VK_CLIENT_ID пуст, кнопки VK ID на сайте не показываются.
3. Запуск всего стека в Docker (продакшен)
docker compose up -d --build
Поднимаются PostgreSQL, Redis, API (миграции применяются автоматически при старте),
фоновый воркер arq (достижения, вебхуки, экспорт скробблов, импорт Last.fm,
живое соединение с Яндексом, опрос Spotify и SoundCloud, ночная очистка неиспользуемых
загрузок) и фронтенд.
Проверка состояния: GET /health.
Для VPS с 1–2 ГБ памяти удобнее deploy/: образы
собирает GitHub Actions, сервер только скачивает их, а Caddy сам выпускает
HTTPS-сертификаты. Сервер сам подтягивает новые коммиты, а на время
перезапуска Caddy показывает страницу «Идёт обновление».
Резервные копии. Сервис db-backup раз в сутки делает pg_dump в том
db_backups и хранит копии BACKUP_KEEP_DAYS дней (по умолчанию 7).
Восстановление:
docker compose exec db-backup ls /backups
docker compose exec -T db-backup pg_restore --clean --if-exists \
-d veinmusic /backups/<файл>.dump
Копии лежат на том же сервере: для защиты от потери диска периодически
забирайте их на другое хранилище.
3а. Локальная разработка без Docker для кода
Для работы по обычному http поставьте в .env значение ENVIRONMENT=development
(в продакшене должно оставаться production).
# Только базы данных
docker compose up -d db redis
pip install -r requirements.txt
python -m app.core.migrate # миграции (подхватывает и старые базы без истории Alembic)
uvicorn app.main:app --reload --port 8000
arq app.worker.WorkerSettings # фоновый воркер (в отдельном терминале)
Web Push включается ключами VAPID: python -m app.services.push_notifications
выведет пару ключей для .env.
4. Настройка и запуск фронтенда
cd frontend
npm install
npm run dev
Фронтенд будет доступен по адресу: http://localhost:3000.
5. Приложение для Windows (Опционально)
Установщик публикуется в релизах с тегом desktop-v*;
сборка из исходников описана в desktop/README.md.
5а. Консольный клиент на Python (Опционально)
cd desktop_client
pip install -r requirements.txt
python -m desktop_client.main
6. Установка браузерного расширения
Готовые пакеты: VEINMusic Extension 1.5.0.
Скачать ZIP можно без аккаунта GitHub. Инструкция и ограничения установки.
В Chrome, Edge, Brave и Яндекс Браузере распакуйте пакет chromium, откройте
страницу расширений, включите режим разработчика и загрузите распакованную папку.
В Firefox 142+ пакет firefox пока устанавливается временно через about:debugging;
для постоянной установки требуется подпись Mozilla или публикация на AMO.
В окне расширения включите «Передавать прослушивания в VEIN», нажмите
«Подключить через сайт» и подтвердите код. Ключ устройства можно отозвать в
настройках VEIN. «Тест связи» проверяет доступ, не добавляя треков в историю.
Для разработчиков: python scripts/package_extension.py собирает два пакета,
node --test music-extension/tests/*.test.cjs запускает тесты.
🧪 Тестирование и проверка качества
# Юнит- и интеграционные тесты бэкенда (SQLite)
pytest
# Те же тесты на PostgreSQL и с реальным Redis (как в CI)
TEST_DATABASE_URL=postgresql://USER:PASSWORD@localhost:5432/veinmusic_test \
TEST_REDIS_URL=redis://localhost:6379 pytest
# Проверка, что миграции совпадают с моделями
alembic check
# Проверка типизации и линтинга бэкенда
flake8 app tests desktop_client
mypy app/
# Проверка линтера и форматирования фронтенда
cd frontend
npm run lint
npm run format:check
npm run build
📄 Лицензия
Проект распространяется под условиями собственной лицензии. Подробнее см. в файле LICENSE.