neegde¶
neegde — десктопное приложение на Tauri 2 для стриминга музыки из двух источников: RuTracker (через BitTorrent) и SoulSeek (P2P). Эта вики документирует внутреннюю реализацию для разработчиков, которые хотят понять, проверить или доработать проект.
Исходный код: github.com/yepIwt/neegde-tauri.
Стек¶
| Слой | Технология |
|---|---|
| Десктопная оболочка | Tauri 2 |
| Фронтенд | Vue 3 + TypeScript + Vite |
| Бэкенд | Rust (tokio, reqwest, serde) |
| BitTorrent стриминг | vozduxan — C++ библиотека поверх libtorrent |
| BitTorrent экспорт | librqbit (Rust) |
| SoulSeek | Кастомная Rust-реализация бинарного протокола SoulSeek |
Как это работает, в одном абзаце¶
Пользователь вводит запрос. Rust-резолвер канонизирует его — превращает "нон стоп молли" в {artist: "Пошлая Молли", title: "Нон стоп"} — через Brave Search с Argon2id proof-of-work challenge. Поисковый движок отправляет канонический запрос в два провайдера параллельно: провайдер RuTracker получает HTML через аутентифицированную сессию, парсит торрент-топики и извлекает структуру альбомов/треков; провайдер SoulSeek отправляет поисковый пакет на SoulSeek-сервер и стримит ответы пиров по мере прихода. Результаты проходят пайплайн (normalize → dedup → score → filter) и рендерятся реактивно. При нажатии play: путь RuTracker вызывает vozduxan (C++, libtorrent), который открывает торрент, расставляет приоритеты кускам файла через deadline scheduling, поднимает локальный HTTP-сервер и возвращает localhost:… URL элементу <audio>. SoulSeek открывает прямое TCP-соединение с пиром-владельцем файла и делает то же самое.
Структура репозитория¶
neegde-tauri/
├── src/ Vue 3 фронтенд (TypeScript)
│ ├── App.vue Оболочка приложения, главный layout
│ ├── search/ Поисковый движок, сессия, провайдеры, пайплайн
│ ├── stores/ Реактивное состояние (очередь, сущности, поиск, лайки)
│ ├── persistence/ Хелперы для сериализации в localStorage
│ ├── torrent/ Обёртки Tauri-команд для стриминга
│ ├── soulseek/ SoulSeek API-обёртки для фронтенда
│ ├── rutracker/ Хелперы auth, поиска, сессии RuTracker
│ └── components/ Vue-компоненты (плеер, поиск, вид торрента)
│
└── src-tauri/
├── build.rs Вызов CMake для vozduxan
└── src/
├── lib.rs Tauri setup, managed state, invoke_handler
├── app_paths.rs Канонические хелперы для путей данных
├── vozduxan_ffi.rs Сырые unsafe C-биндинги
├── vozduxan_stream.rs Безопасная Rust-обёртка, token buckets
├── resolver/ Резолвер intent-а запроса
├── rutracker/ HTTP-сессия, поиск, парсинг топиков
├── soulseek/ Реализация протокола SoulSeek
├── torrent_stream/ Экспорт + AppDebugLog (на librqbit)
└── torrent_image.rs Обложки через транзиентные librqbit-сессии
Основные подсистемы¶
Стриминг¶
Всё аудио воспроизводится через один из двух путей: vozduxan для контента RuTracker и прямая загрузка от пира для SoulSeek. Оба предоставляют фронтенду один интерфейс: localhost URL для элемента <audio>.
Путь vozduxan использует три token bucket-а — current_token, prefetch_token, warm_prefetch_token — управляемых в Rust, чтобы не вытеснить нужный закешированный стрим при навигации по очереди.
Резолвер запросов¶
Пользовательский ввод редко бывает чистым. Резолвер запускает Brave Search с ограничением site:genius.com, парсит заголовки возвращённых страниц для извлечения исполнителя и названия, и возвращает ResolveResult с каноническими парой и лейблом intent (track, artist, album, lyric, raw). Когда Brave отвечает 429 с JSON-телом challenge, резолвер решает Argon2id PoW локально и повторяет запрос.
Поисковый пайплайн¶
SearchEngine управляет одним SearchSession на уникальный запрос. Сессия запускает два async generator-а (провайдеры) параллельно, собирает их снапшоты в Map<providerKind, PipelineEntity[]>, мержит на каждом animation frame и прогоняет через пайплайн. Пайплайн выполняет дедупликацию (по id сущности, мержит списки источников) и фильтрацию; скоринг является заглушкой.
RuTracker¶
Auth использует настоящую phpBB-сессию: POST на эндпоинт входа с credentials в Windows-1251, куки персистируются через reqwest_cookie_store. Поиск парсит HTML листинга топиков, затем загружает тело поста каждого топика для извлечения магнет-ссылки, списка файлов, обложки и структурированных метаданных (год, кодек, тип рипа, жанр).
SoulSeek¶
Rust-реализация бинарного протокола SoulSeek: TCP-соединение с SoulSeek-сервером, хэндшейк логина, поиск файлов через length-prefixed бинарный пакет. Ответы пиров приходят инкрементально. Стриминг — прямая HTTP-загрузка от пира (или альтернативного пира при сбое основного). На каждый трек хранится до пяти запасных пиров.
Ключевые инварианты¶
Неочевидные ограничения, нарушение которых молча сломает работу:
-
VozduxanStreamState,TorrentImageStateиTorrentStreamStateдолжны разделять одинArc<AppDebugLog>. Они создаются вlib.rsи Arc передаётся явно. -
VozduxanConfig.log_userdata— сырой указатель вArc<AppDebugLog>, который держит живымVozduxanSessionInner._debug_log_arc. Не дропать Arc пока vozduxan-сессия жива. -
metadata_received_alertlibtorrent не срабатывает когдаatp.tiуже установлен (т.е. когда передан.torrent-файл, а не магнет). vozduxan обрабатывает этот случай внутри на C++. Не добавлять workaround на стороне Rust. -
build.rsперечисляет C++ исходники поштучно черезcargo:rerun-if-changed, потому что macOS не обновляет mtime директории при изменении файла внутри. -
Brave source резолвера принудительно проверяет
site:genius.comна стороне клиента — Brave трактует оператор нестрого и возвращает посторонние результаты (YouTube, Apple Music, блоги).brave.rsотбрасывает всё, чей заголовок страницы не заканчивается наGenius.
С чего начать¶
- Понять как трек идёт от клика до воспроизведения: Стриминг — Vozduxan Engine
- Понять как запрос становится канонической парой artist/title: Резолвер — Обзор
- Понять пайплайн результатов поиска: Поисковый пайплайн — SearchSession
- Понять управление куками, магнет-ссылками и .torrent-файлами: RuTracker — Аутентификация
- Понять бинарный протокол SoulSeek: SoulSeek — Протокол